Wikilivres
frwikibooks
https://fr.wikibooks.org/wiki/Accueil
MediaWiki 1.46.0-wmf.22
first-letter
Média
Spécial
Discussion
Utilisateur
Discussion utilisateur
Wikilivres
Discussion Wikilivres
Fichier
Discussion fichier
MediaWiki
Discussion MediaWiki
Modèle
Discussion modèle
Aide
Discussion aide
Catégorie
Discussion catégorie
Transwiki
Discussion Transwiki
Wikijunior
Discussion Wikijunior
TimedText
TimedText talk
Module
Discussion module
Event
Event talk
Catégorie:Jeux vidéo
14
3866
762765
476759
2026-04-02T11:45:16Z
~2026-20374-30
123400
Уйыкта
555555
762765
wikitext
text/x-wiki
Cettdj sufokwf sjdfossk 55efjssv sjsuekedmdj jdjeiyrbuieiw 1111111111111111111111111111111111111111111111jfhdiskdgii Heritage iyebuduf duwjwgoewyeig isi ecb shdjfighedjf jgddhiiiz hzcfdj jejeg ijre hjfuguhehrb
7k24gtyxsossr0fbsk5tkm1ikgp2nen
Phytosociologie
0
27138
762720
643130
2026-04-01T13:00:38Z
Morhelluin
10577
/* Histoire */ typo
762720
wikitext
text/x-wiki
[[Image:Gasterental.jpg|thumb|350px|right|''la phytosociologie étudie les associations végétales'']]
La '''phytosociologie''' est la discipline botanique qui étudie les communautés végétales, en se basant sur des listes floristiques les plus exhaustives possibles. Elle est l'une des branches de l'étude de la végétation, laquelle peut s'appuyer sur d'autres types d'approches (physionomiques, climatiques, écomorphologiques, agricoles, sylvicoles, etc.)
L'analyse comparative des groupements végétaux permet de définir des catégories abstraites (par exemple des [[w:Association végétale|associations végétales]] et des [[w:phytotype|phytotype]]s).
La phytosociologie décrit les relations spatio-temporelles entre végétaux. Elle s'intéresse aussi au fonctionnement écologique et botanique des végétations, à différentes échelles (des [[w:synusie|synusie]]s aux [[w:biome|biome]]s zonaux), c'est à dire aux relations des plantes entre elles et avec leur milieu de vie ([[w:climat|climat]], [[w:Sol (pédologie)|sol]]), ainsi que leur répartition géographique. Ses méthodes et concepts sont transposables à tous les types d'organismes. Elle est donc une discipline écologique et géographique à part entière.
==Principes et vocabulaire ==
Pour le phytosociologue, les populations végétales de différentes espèces qui utilisent un même [[w:biotope|habitat naturel]], ou [[w:biotope|biotope]], constituent des [[w:synusie|synusie]]s, des [[w:phytocénose|phytocœnoses]], des [[w:tesela|tesela]]s, [[w:catena|catena]]s, etc., dont la phytosociologie cherche à décrire les compositions [[w:flore|floristiques]], l'architecture, mais aussi le fonctionnement dynamique et écologique.
==Histoire==
Constatant que les espèces végétales ne se répartissent pas au hasard et que l'on retrouve souvent les mêmes espèces cohabitant dans des mêmes milieux, les précurseurs de la phytosociologie, tel [[w:Henri Lecocq|Henri Lecocq]], [[w:Charles Flahaut|Charles Flahaut]], [[w:Émile Chateau|Émile Chateau]] (1866-1952), ont défini des [[w:association végétale|associations végétales]] comme unités floristico-physionomiques fondamentales de la couverture végétale. Le concept floristique de la végétation s'est ensuite substitué au concept physionomique (basé sur les types biologiques), tel qu'instauré par les premiers phytogéographes : Alexander von Humboldt & Aimé Bonpland (1807), Grisebach (1838, 1872), [[w:Johannes Eugenius Bülow Warming|Eugen Warming]] (1909), etc.
D'autres phytosociologues, comme [[w:Josias Braun-Blanquet|Josias Braun-Blanquet]] (1884-1980), [[w:Erich Oberdorfer|Erich Oberdorfer]] ou [[w:Reinhold Tüxen|Reinhold Tüxen]] ont progressivement construit un système de classification hiérarchisé, analogue à celui établi pour les espèces, prenant pour base l'association végétale considérée comme représentée sur le terrain par des «individus d'association».
Ce système a constitué un socle [[w:théorie|théorique]] pour le développement d'outils pratiques de connaissance écologique. Il a facilité la compréhension des affinités entre les communautés végétales et entre celles-ci et les milieux ([[w:naturalité|naturels]] ou artificialisés).
La reconnaissance des groupements végétaux qui reflètent la [[w:fertilité|fertilité]] et les qualités structurelles d'une « [[w:station|station]] » a des applications pratiques en [[w:sylviculture|sylviculture]] et en [[w:agronomie|agronomie]].
<br />En matière de [[w:protection de la nature|protection de la nature]], le phytosociologue distingue les différents habitats en les hiérarchisant (par exemple en fonction de critères de rareté ou vulnérabilité et oriente et évalue les opérations de [[w:restauration écologique|restauration écologique]] de milieux (diagnostic initial, suivi de l'évolution des effets d'une gestion conservatoire ou restauratoire).
==les écoles de phytosociologie==
* L’école suédoise des sociations (HULT 1881, SERNANDER, Uppsala : DU RIETZ 1920, 1930, 1954), encore utilisée de nos jours en Fennoscandie.
* L’école anglaise de la dominance (SMITH 1898, 1899, CHIPP 1927, TANSLEY 1946).
* L’école américaine du climax (CLEMENTS 1905, 1916, 1928) à laquelle se rattachent les cartes des [[w:série de végétation|séries de végétation]] (Toulouse : GAUSSEN 1933), et les documents pour la carte de la végétation des Alpes de OZENDA.
* L’école franco-suisse sigmatiste (Zürich, SIGMA Montpellier : BRAUN-BLANQUET 1913, 1928, 1951, 1964) à laquelle se rattachent les cartes de GUINOCHET (1956) et de LEMEE (1959).
* L’école suisse des synusies (RÜBEL 1917, GAMS 1918).
* L’école américaine du continuum (GLEASON 1926, 1939, CURTIS & MAC INTOSH1951, CURTIS 1959, MAC INTOSH 1967, 1968).
* L’école russe des phytogéocénoses (SUKACHEV 1929,1954, ALECHIN 1932, 1935, LAVRENKO 1938).
* L’école estonienne unistrate (LIPPMAA 1931, 1933, 1934, 1935).
* L’école belge des groupes socioécologiques (Paul DUVIGNEAUD 1946), à laquelle se rattachent les travaux de PASSARGE (1964).
* L’école française des groupes écologiques statistiques (CEPE Montpellier : GOUNOT 1969, GODRON 1967, 1971, DAGET 1968).
* L’école française de la phytosociologie synusiale intégrée (Lille, Neuchâtel : JULVE 1985, DE FOUCAULT 1985, GILLET 1985, 2000, GILLET, DE FOUCAULT & JULVE 1991), qui puise ses racines dans les travaux de LIPPMAA, GAMS et BRAUN-BLANQUET.
Ces écoles diffèrent :
* par leurs concepts, en particulier des unités de base (association, sociation, concept individualiste…), choisies par une approche synusiale ou phytocénotique,
* par l’importance différente attribuée à la dominance, la constance et la fidélité des espèces, la stratification, la dynamique des groupements végétaux,
* par leurs techniques de terrain (relevés, quadrats de taille constante, échantillonnage au hasard ou stratifié…),
* par leurs méthodes de synthèse et de modélisation.
==Phytosociologie systématique floristique - sociologie des plantes==
La phytosociologie existe parce que les plantes, comme tout organisme vivant, ne vivent pas de manière isolée ; les espèces végétales vivent associées entre elles (et avec des animaux, des champignons, des protistes, des bactéries...), et elles modifient leur milieu selon plusieurs aspects et [[w:facteurs écologiques|facteurs écologiques]] :
* un aspect dit '''statique''', réunissant les paramètres [[w:abiotique|abiotique]]s du milieu (lumière, chaleur, humidité...).
* un aspect dit '''de succession''', où les écosystèmes (structurés par des groupements végétaux) se succèdent en stades différents pour parvenir à un ''climax'' homéostatique.
* un aspect d''''interactions''', qui tient compte des nombreuses relations entre espèces : interactions biotiques (prédation, parasitisme, coopération, mutualisme, symbiose, compétition...), interactions abiotiques (ombrage, intoxication, fertilisation...).
C'est [[w:Josias Braun-Blanquet|Josias Braun-Blanquet]] qui a fait prédominer l'aspect floristique plutôt que la forme (ou physionomie) des plantes, comme critère principal de détermination des associations végétales considérées. Suivant sa méthode, on considère des échantillons de terrains aux biotopes uniformes, où les espèces sont distribuées de façon répétitive.
On établit alors une liste semi-quantifiée des espèces présentes sur une surface semblant floristiquement homogène, supérieure à l'aire minimale des groupements considérés. Le choix de la forme et de la taille de la zone relevée dépend du type de végétation considéré.
Par surface floristiquement homogène, on entend une surface où la liste d'espèces ne varie pas, indépendamment de la répartition plus ou moins agrégée des individus.
On estime aussi la couverture respective des espèces selon deux critères :
* l'abondance-dominance : surface occupée par chaque espèce végétale en proportion de la surface totale occupée par l'ensemble des plantes de la zone relevée,
* sociabilité : distribution des individus de chaque espèce présente sur l'ensemble de l'échantillon de terrain – sont-elles régulièrement dispersées, ou apparaissent-elles selon un ''« motif »'' de répartition particulier ?
Le second critère est de moins en poins utilisé.
Les relevés botaniques effectués sont comparés entre eux pour déterminer leurs degrés de similitude (ex : espèces toujours conjointement présentes dans un certain biotope), on arrive à agréger plusieurs relevés pour finalement former des ''unités phytosociologiques'' homogènes floristiquement. On peut ensuite comparer les groupes de relevés avec ceux de biotopes similaires situés dans des régions plus éloignées, ou proches mais entièrement différents.
===Classification phytosociologique des végétations===
Les phytosociologues du {{s|XX|e}} ont construit un système de classification hiérarchique (syntaxinomie) analogue à celui de la [[w:classification scientifique des espèces|classification classique]] (idiotaxinomie). Les [[w:association végétale|associations végétales]] forment l'unité de base, et sont regroupées par similarités dans des alliances. Les alliances les plus proches dans leur structure floristique sont groupées en ordres, eux-mêmes groupés en classes. Chaque niveau de cette hiérarchie est dénommée "syntaxon" (par analogie aux [[w:idiotaxons|idiotaxons]] du système de classification des organismes).
Une association végétale est nommée à partir du ou des noms de genre d'une ou de deux espèces caractéristiques présentes, auxquelles on ajoute un suffixe (en gras ci-dessous) différent selon que l'on parle d'une classe, d'un ordre, d'une alliance ou d'une association végétale:
*Classe (suffixe ''-etea'') : ''Querco-Fag'''etea''''' (forêts feuillues des climats tempérés dominées par les Chênes et le Hêtre) ;
**Ordre (suffixe ''-etalia'') : ''Fag'''etalia''''' (forêts feuillues des climats tempérées froides à Hêtre, ''Fagus sylvatica'') ;
***Alliance (suffixe ''-ion'') : ''Fag'''ion''''' (hêtraie et associations voisines montagnardes) ;
****Association végétale (suffixe ''-etum'') : ''Abi'''eto'''-Fag'''etum''''' (hêtraie à sapins de moyenne montagne).
Les sous-unités éventuelles portent des suffixes spécifiques :
:''-etosum'' ; pour la sous-association,
:''-enion'' ; pour la sous-alliance,
:''-enalia'' ; pour le sous-ordre, -
:''-enea'' ; pour la sous-classe.
==Classification physionomique des végétations==
Une approche basée sur la physionomie des groupements végétaux existe aussi. Elle considère d'abord les types biologiques des espèces dominantes dans un lieu donné. L'unité considérée est la [[w:formation végétale|formation végétale]], concept formulé dès [[w:1838|1838]] par [[w:August Grisebach|August Grisebach]]. Les formations sont insérées elles aussi dans un système hiérarchique, illustré ci-dessous par trois exemples :
{|border="1"
|'''Classe'''
|Buissons
|Formations herbacées
|Formations aquatiques
|-
|'''Sous-classe'''
|Formations xéromorphes de buissons
|Champs herbacés
|Roseaux
|-
|'''Groupe'''
|Formations xéromorphes de buissons très ouvertes (semi-désertiques)
|Champs arbustifs
|Roseaux de lacs d'eau douce
|-
|'''Formation'''
|…
|Couverts de fougères
|…
|}
Ce modèle tend à être délaissé au profit du système de classification phytosociologique proprement dit, de nature floristique, car ce dernier détaille les différentes espèces présentes plutôt que de se référer principalement à la physionomie globale. Hors, la connaissance des espèces inclut la connaissance de la physionomie, alors que l'inverse n'est pas vrai.
==Intérêt de la phytosociologie en écologie==
La phytosociologie permet d'étudier les relations abiotiques des végétations avec le [[w:climat|climat]], les [[w:Sol (pédologie)|sols]] et la [[w:géomorphologie|géomorphologie]] locale ainsi que les relations biotiques avec les autres communautés végétales, les communautés animales et les sociétés humaines. Ainsi, la reconnaissance des groupements végétaux révèle de manière plus précise les fonctionnements écologiques locaux, la bioindication des communautés étant l'intersection des valences écologiques de toutes les espèces les constituant.
===Cartographie des végétations===
La caractérisation des végétations repose sur des [[w:Inventaire floristique|inventaires floristiques]] effectués selon des normes précises. L'objectif étant de décrire la diversité des végétations mondiales et de permettre la compréhension des liens fonctionnels entre les communautés de plantes et les milieux naturels ou artificiels.
L'utilisation de cartes pour la représentation spatiale des unités phytosociologiques permet une étude précise des conditions écologiques du milieu et de la répartition des espèces végétales. Selon l'échelle, on choisira l'échelon approprié d'unité de végétation, et on le représentera sur les cartes : cartes phytosociologiques ou physionomiques, cartes des formations, des types de biotopes, des ressources forestières, des valeurs agronomiques, etc.
===Étude des indicateurs et des groupes écologiques===
La phytosociologie peut servir à la [[w:bioindicateur|bioindication]]. Certaines plantes sont des "indicateurs biologiques" de certains types de terrains (acidiphile, calcaire, humide, sableux, etc.). Selon le système introduit par [[w:Heinz Ellenberg|Heinz Ellenberg]], le comportement écologique d'une espèce botanique est décrit par un indicateur comprenant de 9 à 12 classes pour chaque facteur écologique primordial. Ces indicateurs précisent certaines variables de l'environnement comme la lumière, la température, la continentalité, l'humidité du sol, le pH, la quantité de nutriments dans le sol, la salinité.
Par "indication biologique" on doit entendre plusieurs niveaux possibles de bioindication : présence-absence qualitative, importance quantitative des populations, modifications physiologiques héréditaires, adaptations physiologiques temporaires.
===Phytosociologie et dynamique des végétations===
Sous le concept de dynamique des végétations on regroupe toutes les modifications quantitatives et qualitatives des associations végétales au cours du temps : les modifications saisonnières [[w:phénologie|phénologiques]], les fluctuations pluriannuelles de la végétation, les modifications cycliques, dues notamment aux invasions de parasites, les successions autogènes ou allogènes ([[w:série de végétation|séries de végétation]]).
L'utilisation de la méthode phytosociologique à divers intervalles de temps sur un même site permet l'analyse des fluctuations ou de l'évolution de la végétation. Cette évolution peut par la suite être expliquée par l'effet de phénomènes internes (autogènes) ou externes (allogènes) à l'écosystème considéré. Ces phénomènes peuvent trouver leur origine dans des actions humaines, des changements climatiques, des cicatrisations, comme après après un incendie, etc.).
== Les classes de végétations en France ==
Voir [[Phytosociologie/Classes CATMINAT de végétation en France|Classes CATMINAT de végétation en France]]
==Voir aussi ==
* [[w:Catégorie:Phytosociologie]]
===Articles sur wikipédia===
* [[w:Botanique|Botanique]],
* [[w:Phytosociologie|Phytosociologie]],
* [[w:Phytosociologie synusiale|Phytosociologie synusiale]]
* [[w:Formation végétale|Formation végétale]], [[w:Association végétale|Association végétale]], [[w:Phytotype|Phytotype]], [[w:bioindicateur|bioindicateur]]
* [[w:étude d'impact|étude d'impact]], [[w:renaturation|renaturation]]
* [[w:Observatoire de la biodiversité|Observatoire de la biodiversité]]
* [[w:Conservatoire botanique national|Conservatoires botaniques nationaux]]
'''Phytosociologues'''
* [[w:Bruno de Foucault|Bruno de Foucault]]
* [[w:Émile Chateau|Émile Chateau]]
* [[w:Josias Braun-Blanquet|Josias Braun-Blanquet]]
* [[w:Heinz Ellenberg|Heinz Ellenberg]]
* [[w:Philippe Julve|Philippe Julve]]
* [[w:François Gillet|François Gillet]]
* [[w:Marcel Guinochet|Marcel Guinochet]]
=== Références ===
<references />
===Liens externes===
* [http://www.tela-botanica.org/environnement Introduction à la phytosociologie] (site internet de Tela Botanica)
* {{lien brisé|url=http://www2.ecol.ucl.ac.be/cours/phytosocio/home.html|titre=Cours de phytosociologie - Partie analyse des données}}
* [http://www.unice.fr/LEML/Francour_Internet/Fichiers_en_ligne/Cours_1_Ecosysteme_Introduction.pdf "Écosystème" par Patrice Francour]. Un tres bon site d'introduction sur l'ecologie, la phytosociologie et concepts voisins.
* Une page synthétique sur [http://perso.orange.fr/philippe.julve/catminat.htm la classification CATMINAT] maintenue par Philippe Julve.
===Bibliographie===
* {{Ouvrage|titre=Phytosociologie|éditeur=Masson et cie|auteur=Marcel Guinochet|langue=français|année=1973|lieu=Paris|pages=227|isbn=2-225-35618-1}}
* {{Ouvrage|titre=Guide des groupements végétaux de la région parisienne|éditeur=Belin|auteurs=Marcel Bournérias, Gérard Arnal, Christian Bock|langue=français|jour=14|mois=janvier|année=2002|lieu=Paris|pages=640|isbn= 2-701-12522-7}}
[[Catégorie:Phytosociologie (livre)|*]]
0ixrwe50whg1sr729w83hjr8qwp6mkq
762721
762720
2026-04-01T13:12:17Z
Morhelluin
10577
/* Phytosociologie systématique floristique - sociologie des plantes */ typo
762721
wikitext
text/x-wiki
[[Image:Gasterental.jpg|thumb|350px|right|''la phytosociologie étudie les associations végétales'']]
La '''phytosociologie''' est la discipline botanique qui étudie les communautés végétales, en se basant sur des listes floristiques les plus exhaustives possibles. Elle est l'une des branches de l'étude de la végétation, laquelle peut s'appuyer sur d'autres types d'approches (physionomiques, climatiques, écomorphologiques, agricoles, sylvicoles, etc.)
L'analyse comparative des groupements végétaux permet de définir des catégories abstraites (par exemple des [[w:Association végétale|associations végétales]] et des [[w:phytotype|phytotype]]s).
La phytosociologie décrit les relations spatio-temporelles entre végétaux. Elle s'intéresse aussi au fonctionnement écologique et botanique des végétations, à différentes échelles (des [[w:synusie|synusie]]s aux [[w:biome|biome]]s zonaux), c'est à dire aux relations des plantes entre elles et avec leur milieu de vie ([[w:climat|climat]], [[w:Sol (pédologie)|sol]]), ainsi que leur répartition géographique. Ses méthodes et concepts sont transposables à tous les types d'organismes. Elle est donc une discipline écologique et géographique à part entière.
==Principes et vocabulaire ==
Pour le phytosociologue, les populations végétales de différentes espèces qui utilisent un même [[w:biotope|habitat naturel]], ou [[w:biotope|biotope]], constituent des [[w:synusie|synusie]]s, des [[w:phytocénose|phytocœnoses]], des [[w:tesela|tesela]]s, [[w:catena|catena]]s, etc., dont la phytosociologie cherche à décrire les compositions [[w:flore|floristiques]], l'architecture, mais aussi le fonctionnement dynamique et écologique.
==Histoire==
Constatant que les espèces végétales ne se répartissent pas au hasard et que l'on retrouve souvent les mêmes espèces cohabitant dans des mêmes milieux, les précurseurs de la phytosociologie, tel [[w:Henri Lecocq|Henri Lecocq]], [[w:Charles Flahaut|Charles Flahaut]], [[w:Émile Chateau|Émile Chateau]] (1866-1952), ont défini des [[w:association végétale|associations végétales]] comme unités floristico-physionomiques fondamentales de la couverture végétale. Le concept floristique de la végétation s'est ensuite substitué au concept physionomique (basé sur les types biologiques), tel qu'instauré par les premiers phytogéographes : Alexander von Humboldt & Aimé Bonpland (1807), Grisebach (1838, 1872), [[w:Johannes Eugenius Bülow Warming|Eugen Warming]] (1909), etc.
D'autres phytosociologues, comme [[w:Josias Braun-Blanquet|Josias Braun-Blanquet]] (1884-1980), [[w:Erich Oberdorfer|Erich Oberdorfer]] ou [[w:Reinhold Tüxen|Reinhold Tüxen]] ont progressivement construit un système de classification hiérarchisé, analogue à celui établi pour les espèces, prenant pour base l'association végétale considérée comme représentée sur le terrain par des «individus d'association».
Ce système a constitué un socle [[w:théorie|théorique]] pour le développement d'outils pratiques de connaissance écologique. Il a facilité la compréhension des affinités entre les communautés végétales et entre celles-ci et les milieux ([[w:naturalité|naturels]] ou artificialisés).
La reconnaissance des groupements végétaux qui reflètent la [[w:fertilité|fertilité]] et les qualités structurelles d'une « [[w:station|station]] » a des applications pratiques en [[w:sylviculture|sylviculture]] et en [[w:agronomie|agronomie]].
<br />En matière de [[w:protection de la nature|protection de la nature]], le phytosociologue distingue les différents habitats en les hiérarchisant (par exemple en fonction de critères de rareté ou vulnérabilité et oriente et évalue les opérations de [[w:restauration écologique|restauration écologique]] de milieux (diagnostic initial, suivi de l'évolution des effets d'une gestion conservatoire ou restauratoire).
==les écoles de phytosociologie==
* L’école suédoise des sociations (HULT 1881, SERNANDER, Uppsala : DU RIETZ 1920, 1930, 1954), encore utilisée de nos jours en Fennoscandie.
* L’école anglaise de la dominance (SMITH 1898, 1899, CHIPP 1927, TANSLEY 1946).
* L’école américaine du climax (CLEMENTS 1905, 1916, 1928) à laquelle se rattachent les cartes des [[w:série de végétation|séries de végétation]] (Toulouse : GAUSSEN 1933), et les documents pour la carte de la végétation des Alpes de OZENDA.
* L’école franco-suisse sigmatiste (Zürich, SIGMA Montpellier : BRAUN-BLANQUET 1913, 1928, 1951, 1964) à laquelle se rattachent les cartes de GUINOCHET (1956) et de LEMEE (1959).
* L’école suisse des synusies (RÜBEL 1917, GAMS 1918).
* L’école américaine du continuum (GLEASON 1926, 1939, CURTIS & MAC INTOSH1951, CURTIS 1959, MAC INTOSH 1967, 1968).
* L’école russe des phytogéocénoses (SUKACHEV 1929,1954, ALECHIN 1932, 1935, LAVRENKO 1938).
* L’école estonienne unistrate (LIPPMAA 1931, 1933, 1934, 1935).
* L’école belge des groupes socioécologiques (Paul DUVIGNEAUD 1946), à laquelle se rattachent les travaux de PASSARGE (1964).
* L’école française des groupes écologiques statistiques (CEPE Montpellier : GOUNOT 1969, GODRON 1967, 1971, DAGET 1968).
* L’école française de la phytosociologie synusiale intégrée (Lille, Neuchâtel : JULVE 1985, DE FOUCAULT 1985, GILLET 1985, 2000, GILLET, DE FOUCAULT & JULVE 1991), qui puise ses racines dans les travaux de LIPPMAA, GAMS et BRAUN-BLANQUET.
Ces écoles diffèrent :
* par leurs concepts, en particulier des unités de base (association, sociation, concept individualiste…), choisies par une approche synusiale ou phytocénotique,
* par l’importance différente attribuée à la dominance, la constance et la fidélité des espèces, la stratification, la dynamique des groupements végétaux,
* par leurs techniques de terrain (relevés, quadrats de taille constante, échantillonnage au hasard ou stratifié…),
* par leurs méthodes de synthèse et de modélisation.
==Phytosociologie systématique floristique - sociologie des plantes==
La phytosociologie existe parce que les plantes, comme tout organisme vivant, ne vivent pas de manière isolée ; les espèces végétales vivent associées entre elles (et avec des animaux, des champignons, des protistes, des bactéries...), et elles modifient leur milieu selon plusieurs aspects et [[w:facteurs écologiques|facteurs écologiques]] :
* un aspect dit '''statique''', réunissant les paramètres [[w:abiotique|abiotique]]s du milieu (lumière, chaleur, humidité...).
* un aspect dit '''de succession''', où les écosystèmes (structurés par des groupements végétaux) se succèdent en stades différents pour parvenir à un ''climax'' homéostatique.
* un aspect d''''interactions''', qui tient compte des nombreuses relations entre espèces : interactions biotiques (prédation, parasitisme, coopération, mutualisme, symbiose, compétition...), interactions abiotiques (ombrage, intoxication, fertilisation...).
C'est [[w:Josias Braun-Blanquet|Josias Braun-Blanquet]] qui a fait prédominer l'aspect floristique plutôt que la forme (ou physionomie) des plantes, comme critère principal de détermination des associations végétales considérées. Suivant sa méthode, on considère des échantillons de terrains aux biotopes uniformes, où les espèces sont distribuées de façon répétitive.
On établit alors une liste semi-quantifiée des espèces présentes sur une surface semblant floristiquement homogène, supérieure à l'aire minimale des groupements considérés. Le choix de la forme et de la taille de la zone relevée dépend du type de végétation considéré.
Par surface floristiquement homogène, on entend une surface où la liste d'espèces ne varie pas, indépendamment de la répartition plus ou moins agrégée des individus.
On estime aussi la couverture respective des espèces selon deux critères :
* l'abondance-dominance : surface occupée par chaque espèce végétale en proportion de la surface totale occupée par l'ensemble des plantes de la zone relevée,
* sociabilité : distribution des individus de chaque espèce présente sur l'ensemble de l'échantillon de terrain – sont-elles régulièrement dispersées, ou apparaissent-elles selon un ''« motif »'' de répartition particulier ?
Le second critère est de moins en moins utilisé.
Les relevés botaniques effectués sont comparés entre eux pour déterminer leurs degrés de similitude (ex : espèces toujours conjointement présentes dans un certain biotope), on arrive à agréger plusieurs relevés pour finalement former des ''unités phytosociologiques'' homogènes floristiquement. On peut ensuite comparer les groupes de relevés avec ceux de biotopes similaires situés dans des régions plus éloignées, ou proches mais entièrement différents.
===Classification phytosociologique des végétations===
Les phytosociologues du {{s|XX|e}} ont construit un système de classification hiérarchique (syntaxinomie) analogue à celui de la [[w:classification scientifique des espèces|classification classique]] (idiotaxinomie). Les [[w:association végétale|associations végétales]] forment l'unité de base, et sont regroupées par similarités dans des alliances. Les alliances les plus proches dans leur structure floristique sont groupées en ordres, eux-mêmes groupés en classes. Chaque niveau de cette hiérarchie est dénommée "syntaxon" (par analogie aux [[w:idiotaxons|idiotaxons]] du système de classification des organismes).
Une association végétale est nommée à partir du ou des noms de genre d'une ou de deux espèces caractéristiques présentes, auxquelles on ajoute un suffixe (en gras ci-dessous) différent selon que l'on parle d'une classe, d'un ordre, d'une alliance ou d'une association végétale:
*Classe (suffixe ''-etea'') : ''Querco-Fag'''etea''''' (forêts feuillues des climats tempérés dominées par les Chênes et le Hêtre) ;
**Ordre (suffixe ''-etalia'') : ''Fag'''etalia''''' (forêts feuillues des climats tempérées froides à Hêtre, ''Fagus sylvatica'') ;
***Alliance (suffixe ''-ion'') : ''Fag'''ion''''' (hêtraie et associations voisines montagnardes) ;
****Association végétale (suffixe ''-etum'') : ''Abi'''eto'''-Fag'''etum''''' (hêtraie à sapins de moyenne montagne).
Les sous-unités éventuelles portent des suffixes spécifiques :
:''-etosum'' ; pour la sous-association,
:''-enion'' ; pour la sous-alliance,
:''-enalia'' ; pour le sous-ordre, -
:''-enea'' ; pour la sous-classe.
==Classification physionomique des végétations==
Une approche basée sur la physionomie des groupements végétaux existe aussi. Elle considère d'abord les types biologiques des espèces dominantes dans un lieu donné. L'unité considérée est la [[w:formation végétale|formation végétale]], concept formulé dès [[w:1838|1838]] par [[w:August Grisebach|August Grisebach]]. Les formations sont insérées elles aussi dans un système hiérarchique, illustré ci-dessous par trois exemples :
{|border="1"
|'''Classe'''
|Buissons
|Formations herbacées
|Formations aquatiques
|-
|'''Sous-classe'''
|Formations xéromorphes de buissons
|Champs herbacés
|Roseaux
|-
|'''Groupe'''
|Formations xéromorphes de buissons très ouvertes (semi-désertiques)
|Champs arbustifs
|Roseaux de lacs d'eau douce
|-
|'''Formation'''
|…
|Couverts de fougères
|…
|}
Ce modèle tend à être délaissé au profit du système de classification phytosociologique proprement dit, de nature floristique, car ce dernier détaille les différentes espèces présentes plutôt que de se référer principalement à la physionomie globale. Hors, la connaissance des espèces inclut la connaissance de la physionomie, alors que l'inverse n'est pas vrai.
==Intérêt de la phytosociologie en écologie==
La phytosociologie permet d'étudier les relations abiotiques des végétations avec le [[w:climat|climat]], les [[w:Sol (pédologie)|sols]] et la [[w:géomorphologie|géomorphologie]] locale ainsi que les relations biotiques avec les autres communautés végétales, les communautés animales et les sociétés humaines. Ainsi, la reconnaissance des groupements végétaux révèle de manière plus précise les fonctionnements écologiques locaux, la bioindication des communautés étant l'intersection des valences écologiques de toutes les espèces les constituant.
===Cartographie des végétations===
La caractérisation des végétations repose sur des [[w:Inventaire floristique|inventaires floristiques]] effectués selon des normes précises. L'objectif étant de décrire la diversité des végétations mondiales et de permettre la compréhension des liens fonctionnels entre les communautés de plantes et les milieux naturels ou artificiels.
L'utilisation de cartes pour la représentation spatiale des unités phytosociologiques permet une étude précise des conditions écologiques du milieu et de la répartition des espèces végétales. Selon l'échelle, on choisira l'échelon approprié d'unité de végétation, et on le représentera sur les cartes : cartes phytosociologiques ou physionomiques, cartes des formations, des types de biotopes, des ressources forestières, des valeurs agronomiques, etc.
===Étude des indicateurs et des groupes écologiques===
La phytosociologie peut servir à la [[w:bioindicateur|bioindication]]. Certaines plantes sont des "indicateurs biologiques" de certains types de terrains (acidiphile, calcaire, humide, sableux, etc.). Selon le système introduit par [[w:Heinz Ellenberg|Heinz Ellenberg]], le comportement écologique d'une espèce botanique est décrit par un indicateur comprenant de 9 à 12 classes pour chaque facteur écologique primordial. Ces indicateurs précisent certaines variables de l'environnement comme la lumière, la température, la continentalité, l'humidité du sol, le pH, la quantité de nutriments dans le sol, la salinité.
Par "indication biologique" on doit entendre plusieurs niveaux possibles de bioindication : présence-absence qualitative, importance quantitative des populations, modifications physiologiques héréditaires, adaptations physiologiques temporaires.
===Phytosociologie et dynamique des végétations===
Sous le concept de dynamique des végétations on regroupe toutes les modifications quantitatives et qualitatives des associations végétales au cours du temps : les modifications saisonnières [[w:phénologie|phénologiques]], les fluctuations pluriannuelles de la végétation, les modifications cycliques, dues notamment aux invasions de parasites, les successions autogènes ou allogènes ([[w:série de végétation|séries de végétation]]).
L'utilisation de la méthode phytosociologique à divers intervalles de temps sur un même site permet l'analyse des fluctuations ou de l'évolution de la végétation. Cette évolution peut par la suite être expliquée par l'effet de phénomènes internes (autogènes) ou externes (allogènes) à l'écosystème considéré. Ces phénomènes peuvent trouver leur origine dans des actions humaines, des changements climatiques, des cicatrisations, comme après après un incendie, etc.).
== Les classes de végétations en France ==
Voir [[Phytosociologie/Classes CATMINAT de végétation en France|Classes CATMINAT de végétation en France]]
==Voir aussi ==
* [[w:Catégorie:Phytosociologie]]
===Articles sur wikipédia===
* [[w:Botanique|Botanique]],
* [[w:Phytosociologie|Phytosociologie]],
* [[w:Phytosociologie synusiale|Phytosociologie synusiale]]
* [[w:Formation végétale|Formation végétale]], [[w:Association végétale|Association végétale]], [[w:Phytotype|Phytotype]], [[w:bioindicateur|bioindicateur]]
* [[w:étude d'impact|étude d'impact]], [[w:renaturation|renaturation]]
* [[w:Observatoire de la biodiversité|Observatoire de la biodiversité]]
* [[w:Conservatoire botanique national|Conservatoires botaniques nationaux]]
'''Phytosociologues'''
* [[w:Bruno de Foucault|Bruno de Foucault]]
* [[w:Émile Chateau|Émile Chateau]]
* [[w:Josias Braun-Blanquet|Josias Braun-Blanquet]]
* [[w:Heinz Ellenberg|Heinz Ellenberg]]
* [[w:Philippe Julve|Philippe Julve]]
* [[w:François Gillet|François Gillet]]
* [[w:Marcel Guinochet|Marcel Guinochet]]
=== Références ===
<references />
===Liens externes===
* [http://www.tela-botanica.org/environnement Introduction à la phytosociologie] (site internet de Tela Botanica)
* {{lien brisé|url=http://www2.ecol.ucl.ac.be/cours/phytosocio/home.html|titre=Cours de phytosociologie - Partie analyse des données}}
* [http://www.unice.fr/LEML/Francour_Internet/Fichiers_en_ligne/Cours_1_Ecosysteme_Introduction.pdf "Écosystème" par Patrice Francour]. Un tres bon site d'introduction sur l'ecologie, la phytosociologie et concepts voisins.
* Une page synthétique sur [http://perso.orange.fr/philippe.julve/catminat.htm la classification CATMINAT] maintenue par Philippe Julve.
===Bibliographie===
* {{Ouvrage|titre=Phytosociologie|éditeur=Masson et cie|auteur=Marcel Guinochet|langue=français|année=1973|lieu=Paris|pages=227|isbn=2-225-35618-1}}
* {{Ouvrage|titre=Guide des groupements végétaux de la région parisienne|éditeur=Belin|auteurs=Marcel Bournérias, Gérard Arnal, Christian Bock|langue=français|jour=14|mois=janvier|année=2002|lieu=Paris|pages=640|isbn= 2-701-12522-7}}
[[Catégorie:Phytosociologie (livre)|*]]
3kbqujta6z0f0a4ujup1navfon9dxi9
Calcul écrit/Calcul de la racine n-ième d'un nombre
0
30582
762755
723986
2026-04-02T07:07:00Z
DavidL
1746
/* Exemple 1 */ 2648-1261=1387
762755
wikitext
text/x-wiki
<noinclude>{{Calcul écrit|racine}}</noinclude>
Cette méthode pour calculer la N<sup>iéme</sup>racine d'un nombre dérive du boulier (mais il n'est pas nécessaire d'avoir un boulier ni de savoir comment ça marche pour la mettre en pratique) elle est donc presque uniquement basée sur des additions et des soustractions (Pour la petite histoire j'avais passé toute une nuit a tenter de généraliser la méthode à partir de l'extraction des racines carrées et cubiques que je connaissais pour le boulier, et c'est lorsque le premier rayon de Soleil a traversé la vitre que la lumière fut ! Qui n'a pas connu l'ivresse des équations diophantienne à 4h du mat' ne peut pas comprendre !!!).
== Les colonnes ==
Pour calculer <span style="font-size: 140%;"><math>\sqrt[n]{x}</math></span> on va faire un tableau de <math>n</math> colonnes.
Le calcul se fera de gauche à droite puis de bas en haut.
Les colonnes seront nommées R1,R2,R3 etc jusqu'à R(<math>n</math> - 1) et la dernière sera T.
Cette colonne T pour "tranche" contiendra les tranches en cours car <math>x</math> sera découpé en tranches de N chiffres à partir de la droite ou de la virgule.
Exemples :
{| style="border-collapse:collapse;"
|
* <math>\sqrt[4]{160041}\longrightarrow 16 | 0041</math>
| style="width:3em;" |
| style="width:3em;" |
| style="width:3em;border:solid 1px;text-align:center;"| 16
| style="width:3em;border:solid 1px;text-align:center;"| 0041
|-
|
* <math>\sqrt[3]{543987321}\longrightarrow 543 | 987 | 321</math>
|
| style="border:solid 1px;text-align:center;"| 543
| style="border:solid 1px;text-align:center;"| 987
| style="border:solid 1px;text-align:center;"| 321
|-
|
* <math>\sqrt[2]{431,2245}\longrightarrow 4 | 31 | 22 | 45</math>
| style="border:solid 1px;text-align:center;"| 4
| style="border:solid 1px;text-align:center;"| 31,
| style="border:solid 1px;text-align:center;"| 22
| style="border:solid 1px;text-align:center;"| 45
|}
* Comme pour la division, on abaissera d'abord la tranche la plus à gauche puis celle à sa droite et ainsi de suite.
* Le nombre de tranches nous renseigne déjà sur le nombre de chiffres du résultat.
:Exemple : La solution de <math>\scriptstyle{\sqrt[3]{543987321}}</math> aura 3 chiffres avant la virgule car il y a 3 tranches avant la virgule.
* Chaque tranche va subir un certain nombre de soustractions avant que soit descendue la prochaine.
Laissons de côté, pour l'instant, les changements de tranche.
== Calcul en escalier ==
Sur R1,R2 etc vont s'enchaîner une suite d'additions en forme d'escalier à l'envers (voir l'exemple ci-dessous).
À chaque nouvelle ligne on ajoutera +1 au nombre de R1.
# On commence donc et l'on met +1 en R1, ensuite R1 va venir s'ajouter à R2 (0+1=1!), qui lui ira s'ajouter à R3 et ainsi de suite jusqu'à R(N - 1) qui lui ira se '''soustraire''' à T.
# On démarre la seconde ligne en ajoutant +1 dans R1 (donc=2), R1 s'ajoute à R2 (1+2=3) qui s'ajoute à R3 etc jusqu'à R(N - 1) qui cette fois ne vient pas se soustraire à T.
# On démarre la ligne3 en ajoutant +1 à R1 qui vient s'ajouter à R2 etc jusqu'à R(N - 2).
# Pareil pour la ligne 4 mais jusqu'à R(N - 3), jusqu'à R(N - 4) pour la ligne 5
# etc.
Et les lignes s'enchaînent ainsi en se raccourcissant jusqu'à ce que R1 prenne son +1 sans aller s'ajouter à R2.
Lorsque l'on a fini le premier "escalier" on en redémarre un autre avec toujours les derniers chiffres des colonnes auxquels viennent s'ajouter les R1 dans les R2 etc (voir l'exemple).
Donc en dehors de la colonne R1 (qui prend +1 à chaque ligne) et de T, vous pourrez constater sur l'exemple que chaque chiffre est la somme du chiffre qui est au-dessus de lui et de celui qui est à sa gauche.
La première marche de l'escalier est toujours la plus grande, c'est celle qui va jusqu'à la soustraction de R(N - 1) à T.
On continue ce manège jusqu'à ce que T soit inférieur à R(N-1) (donc la soustraction serait négative) auquel cas il faut descendre une nouvelle tranche. Mais on verra ça plus tard.
Intéressons-nous d'abord au cas n'ayant qu'une seule tranche et tombant juste.
'''Exemple :''' <math>\sqrt[5]{1024}</math>
{| cellpadding="5" style="border: solid 1px #3399ff80; border-collapse: collapse; margin:auto;"
! style="background-color: #3399ff80" | '''R1'''
0
! style="background-color: #99ddff80" | '''R2'''
0
! style="background-color: #3399ff80" | '''R3'''
0
! style="background-color: #99ddff80" | '''R4'''
0
! style="background-color: #3399ff80" | '''T'''
1024
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 1
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 1
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 1
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 1
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | 1023 <math>(1024 - R4)</math>
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 2
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 3
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 4
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 5
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 3
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 6
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 10
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 4
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 10
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 5
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 6
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 16
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 26
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 31
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | 992 <math>(1023 - R4)</math>
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 7
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 23
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 49
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 80
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 8
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 31
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 80
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 9
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 40
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 10
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 11
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 51
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 131
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 211
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | 781 <math>(992 - R4)</math>
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 12
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 63
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 194
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 405
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 13
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 76
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 270
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 14
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 90
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 15
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
| style="border: solid 1px #3399ff80;" |
| style="border: solid 1px #3399ff80; background-color: #99ddff80" |
|-
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+1)''</small> 16
| style="border: solid 1px #3399ff80;" | <small>''(+R1)''</small> 106
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | <small>''(+R2)''</small> 376
| style="border: solid 1px #3399ff80;" | <small>''(+R3)''</small> 781
| style="border: solid 1px #3399ff80; background-color: #99ddff80" | 0 <math>(781 - R4)</math>
|}
== Résultat ==
Maintenant il y a deux manières de voir le résultat :
*Soit on prend la dernière valeur de R1 et l'on fait : <math>{\frac {R1+N-1}{N}}</math>
:Donc ici <math>\textstyle{\frac{16+5-1}{5}=\frac{20}{5}=4;\quad 4^5=1024}</math> c'est bien ça !
:L'ajout de N-1 à R1 donne la valeur de R1 si on complète le dernier escalier.
:Donc si on poursuit le calcul de l'escalier jusqu'au bout, on n'ajoute pas N-1 : <math>{\frac {R1}{N}}</math>
*Soit on compte combien de soustractions a dû subir la tranche (colonne T), ici 4. Si l'on avait dû baisser une seconde tranche et que celle-ci avait dû subir 2 soustractions la réponse aurait été 42 : 4 soustractions pour la 1{{ère}} tranche et 2 pour la 2{{ème}}. Cela veut dire aussi qu'un calcul dont la réponse serait 9 sera souvent plus long à effectuer que si c'était 2222 (9 escaliers contre 8).
Encore un exemple avant de passer au cas de plusieurs tranches :
''Ex:'' <math>\sqrt[4]{16}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''R3'''
! '''T'''
! <math>( 16 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(-)}\Rightarrow15</math>
| <math>( = 16 - 1 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow3</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow4</math>
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow6</math>
|-
| style="text-align:right;padding:0 1em;" | <math>4</math>
|-
| style="text-align:right;padding:0 1em;" | <math>5</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow11</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(+)}\longrightarrow15</math>
| style="text-align:right;padding:0 1em;" | <math>\quad_{(-)}\Rightarrow0</math>
| <math>( = 15 - 15 )</math>
|-
| || || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|}
Donc : <math>\textstyle{\frac{R1+N-1}{N}=\frac{5+4-1}{4}=2\qquad 2^4=16}</math>
== Plusieurs tranches ==
Le passage d'une tranche à l'autre est un peu plus délicat (à peine !), il s'effectue lorsque R(N - 1) est devenu supérieur à T.
Il faut tout d'abord finir l'escalier qui précède cette situation embêtante jusqu'à la marche où R1 était seul sans s'ajouter à R2.
Si l'on a poursuivi le calcul jusqu'à cette fameuse soustraction impossible, il suffit de barrer cette dernière ligne.
Mais,le plus souvent,on s'aperçoit que ça ne "passera plus" avant, alors on termine l'escalier en cours.
Ensuite on multiplie R1 par 10, R2 par 100, R3 par 1000 bref tous les R(N) par 10<sup>N</sup> et l'on abaisse la tranche suivante en T ('' ! ATTENTION !''cette ligne n'a eu aucune addition ou soustraction !).
Enfin on redémarre un escalier comme avant : on ajoute +1 à R1, R1 s'ajoute à R2 qui s'ajoute à R3...etc et R(N - 1) se soustrait à T.
=== Exemple 1 ===
Calculer <math>:\qquad \sqrt[3]{10648}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''T'''
! <math>( 10 | 648 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow\quad9</math>
| ( = 10 - 1 )
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow3</math>
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>4</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow7</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow\quad2</math>
| ( 7 > 2 , là on voit que ça ne passera plus !)
|-
| style="text-align:right;padding:0 1em;" | <math>5</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow12</math>
|
| (On finit l'escalier)
|-
| style="text-align:right;padding:0 1em;" | <math>6</math>
|
|
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>60</math>
| style="text-align:right;padding:0 1em;" | <math>1200</math>
| style="text-align:right;padding:0 1em;" | <math>2\,\mathbf{648}</math>
| (on multiplie et abaisse la nouvelle tranche)
|-
| style="text-align:right;padding:0 1em;" | <math>61</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1261</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow1387</math>
|
|-
| style="text-align:right;padding:0 1em;" | <math>62</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1323</math>
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>63</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>64</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1387</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow0</math>
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|}
Donc : <math>\textstyle{\frac{64+3-1}{3}=22\; ;\quad 22^3=10648 }</math>
=== Exemple 2 ===
Calculer <math>:\qquad \sqrt[4]{10617447681}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''R3'''
! '''T'''
! <math>( 106 | 1744 | 7681 )</math>
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>0</math>
| style="text-align:right;padding:0 1em;" | <math>00</math>
| style="text-align:right;padding:0 1em;" | <math>000</math>
| style="text-align:right;padding:0 1em;" | <math>106</math>
| '''Tranche 1'''
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow105</math>
| ( = 106 - 1 )
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow3</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow4</math>
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow6</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>4</math>
|
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>5</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow11</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow15</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow90</math>
|
|-
| style="text-align:right;padding:0 1em;" | <math>6</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow17</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow32</math>
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>7</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow24</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>8</math>
|
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>9</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow33</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow65</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow25</math>
| ( 65 > 25 ...ça ne passera plus !)
|-
| style="text-align:right;padding:0 1em;" | <math>10</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow43</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow108</math>
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>11</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow54</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>12</math>
|
|
|
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''3''' </span> soustractions pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>120</math>
| style="text-align:right;padding:0 1em;" | <math>5400</math>
| style="text-align:right;padding:0 1em;" | <math>108000</math>
| style="text-align:right;padding:0 1em;" | <math>25\,\mathbf{1744}</math>
| '''Tranche 2''' : on multiplie et abaisse la nouvelle tranche
|-
| style="text-align:right;padding:0 1em;" | <math>121</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow5521</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow113521</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow138223</math>
|
|-
| style="text-align:right;padding:0 1em;" | <math>122</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow5643</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow119164</math>
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>123</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow5766</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>124</math>
|
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>125</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow5891</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow125055</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow13168</math>
| ( 125055 > 13168...ça ne passera plus !)
|-
| style="text-align:right;padding:0 1em;" | <math>126</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow6017</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow131072</math>
|
| (On finit l'escalier)
|-
| style="text-align:right;padding:0 1em;" | <math>127</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow6144</math>
|
|
|
|-
| style="text-align:right;padding:0 1em;" | <math>128</math>
|
|
|
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>1280</math>
| style="text-align:right;padding:0 1em;" | <math>614400</math>
| style="text-align:right;padding:0 1em;" | <math>131072000</math>
| style="text-align:right;padding:0 1em;" | <math>13168\,\mathbf{7681}</math>
| '''Tranche 3''' : on multiplie et abaisse la nouvelle tranche
|-
| style="text-align:right;padding:0 1em;" | <math>1281</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow615681</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow131687681</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow0</math>
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''1''' </span> soustraction pour la tranche''
|}
Donc : <math>\textstyle{\frac{1281+4-1}{4}=321\; ;\quad 321^4=10617447681 }</math>
== Chiffre zéro dans le résultat ==
Il peut arriver (1 fois sur 10) que même aprés avoir descendu une nouvelle tranche la soustraction reste négative, il va alors falloir descendre une nouvelle tranche ( cela correspond en fait au chiffre zéro dans la solution ).
Il faut alors supprimer la dernière ligne ; on garde celle où les R(N) étaient multipliés par 10<sup>N</sup> et on remultiplie à nouveau les R(N) par 10<sup>N</sup> et l'on abaisse une nouvelle tranche.
Le plus souvent on s'apercevra que ça ne "passera plus" avant de commencer la ligne suivante. Inutile de calculer ce que l'on va barrer, on remultiplie directement !
Si cela ne suffit toujours pas à rendre R(N - 1) supérieur à T, on remultiplie de nouveau les R(N) par 10<sup>N</sup>, on abaisse encore une tranche...
=== Exemple 1 ===
Calculer <math>:\qquad \sqrt[4]{104060401}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''R3'''
! '''T'''
! <math>( 1 | 0406 | 0401 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow0</math>
| (...ça passera plus !...)
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow3</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow4</math>
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow6</math>
|-
| style="text-align:right;padding:0 1em;" | <math>4</math>
| || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''1''' </span> soustraction pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>40</math>
| style="text-align:right;padding:0 1em;" | <math>600</math>
| style="text-align:right;padding:0 1em;" | <math>4000</math>
| style="text-align:right;padding:0 1em;" | <math>\mathbf{406}</math>
| (la nouvelle tranche n'est pas suffisante !)
|-
| || || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''0''' </span> soustractions pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>400</math>
| style="text-align:right;padding:0 1em;" | <math>60000</math>
| style="text-align:right;padding:0 1em;" | <math>4000000</math>
| style="text-align:right;padding:0 1em;" | <math>406\,\mathbf{0401}</math>
| (on remultiplie et remet une tranche)
|-
| style="text-align:right;padding:0 1em;" | <math>401</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow60401</math>
| style="text-align:right;padding:0 1em;" | <math>_{(+)}\longrightarrow4060401</math>
| style="text-align:right;padding:0 1em;" | <math>_{(-)}\Rightarrow0</math>
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''1''' </span> soustraction pour la tranche''
|}
Donc : <math>\textstyle{\frac{401+4-1}{4}=101\; ;\quad 101^4=104060401 }</math><br/>
'''Remarque :''' La tranche "0406" n'a subi aucune soustraction d'où le zéro !
Désormais les opérations (+) et (-) ne seront plus signalées devant les flèches.
=== Exemple 2 ===
Calculer <math>:\qquad \sqrt[3]{1003003001}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''T'''
! <math>( 1 | 003 | 003 | 001 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow0</math>
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow3</math>
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''1''' </span> soustraction pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>30</math>
| style="text-align:right;padding:0 1em;" | <math>300</math>
| style="text-align:right;padding:0 1em;" | <math>\mathbf{3}</math>
| (...pas suffisant !)
|-
| || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''0''' </span> soustraction pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>300</math>
| style="text-align:right;padding:0 1em;" | <math>30000</math>
| style="text-align:right;padding:0 1em;" | <math>3\,\mathbf{003}</math>
| (...toujours pas !)
|-
| || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''0''' </span> soustraction pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>3000</math>
| style="text-align:right;padding:0 1em;" | <math>3000000</math>
| style="text-align:right;padding:0 1em;" | <math>3003\,\mathbf{001}</math>
| (OK)
|-
| style="text-align:right;padding:0 1em;" | <math>3001</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow3003001</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow0</math>
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''1''' </span> soustraction pour la tranche''
|}
Donc : <math>\textstyle{\frac{3001+3-1}{3}=1001\; ;\quad 1001^3=1003003001 }</math>
=== Exemple 3 ===
Voyons maintenant le cas particulier du résultat se terminant par un ou des zéros.
Calculer <math>:\qquad \sqrt[5]{3200000}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''R3'''
! '''R4'''
! '''T'''
! <math>( 32 | 00000 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow31</math>
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow3</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow4</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow5</math>
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow6</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow10</math>
|-
| style="text-align:right;padding:0 1em;" | <math>4</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow10</math>
|-
| style="text-align:right;padding:0 1em;" | <math>5</math>
|-
| style="text-align:right;padding:0 1em;" | <math>6</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow16</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow26</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow31</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow0</math>
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|}
'''ATTENTION !''' Il reste une tranche ! Vide, mais une tranche quand même !!! Mais finir l'escalier, multiplier et baisser la tranche vide nous conduirait à une erreur !
Dans ces cas là, on ne panique pas ...il suffit de multiplier le résultat final par 10 :<br/>
<math>\textstyle{10 \frac{6+5-1}{5} = \frac{100}{5} =20\ ;\quad 20^5=3200000}</math>
De la même manière <math>\scriptstyle{\sqrt[5]{320000000000}}</math> nous laisserait deux tranches vides, donc <math>\textstyle{100 \frac{6+5-1}{5} = 200\ ;\quad 200^5=320000000000}</math><br/>
Inversement, pour un gain de temps, on peut dans <math>\scriptstyle{\sqrt[5]{0.00032}}</math> abaisser immédiatement la tranche après la virgule à condition de ne pas oublier de '''diviser''' le résultat final par 10 :<br/>
<math>\textstyle{\frac{6+5-1}{5*10} = 0.2\ ;\quad 0.2^5=0.00032}</math>
D'une manière générale, il vaut mieux voir à l'avance si il y a moyen de se simplifier la tâche avec ce genre de multiplication ou de division.
Cependant, si on compte le nombre de soustractions pour obtenir le résultat, continuer le calcul aboutit au bon résultat :
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''R3'''
! '''R4'''
! '''T'''
! <math>( 32 | 00000 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow31</math>
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow3</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow4</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow5</math>
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow6</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow10</math>
|-
| style="text-align:right;padding:0 1em;" | <math>4</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow10</math>
|-
| style="text-align:right;padding:0 1em;" | <math>5</math>
|-
| style="text-align:right;padding:0 1em;" | <math>6</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow16</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow26</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow31</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow0</math>
|-
| style="text-align:right;padding:0 1em;" | <math>7</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow23</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow49</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow80</math>
|-
| style="text-align:right;padding:0 1em;" | <math>8</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow31</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow80</math>
|-
| style="text-align:right;padding:0 1em;" | <math>9</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow40</math>
|-
| style="text-align:right;padding:0 1em;" | <math>10</math>
| || || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>100</math>
| style="text-align:right;padding:0 1em;" | <math>4000</math>
| style="text-align:right;padding:0 1em;" | <math>80000</math>
| style="text-align:right;padding:0 1em;" | <math>800000</math>
| style="text-align:right;padding:0 1em;" | <math>0\,\mathbf{00000}</math>
| (on multiplie et abaisse la nouvelle tranche)
|-
| || || || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''0''' </span> soustraction pour la tranche''
|}
De même utiliser la dernière valeur de R1 permet d'obtenir le bon résultat sans l'ajout de N-1.
<math>\textstyle{ \frac{100}{5} = 20\ ;\quad 20^5=3200000}</math>
== Nombres décimaux ==
Le principe reste le même avec les nombres décimaux.
'''Exemple :''' Calculer <math>:\qquad \sqrt[3]{1.061208}</math>
{| style="border-collapse:collapse;margin:auto;"
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
! '''R1'''
! '''R2'''
! '''T'''
! <math>( 1 | 061 | 208 )</math>
|-
| style="text-align:right;padding:0 1em;" | <math>1</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow1</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow0</math>
|-
| style="text-align:right;padding:0 1em;" | <math>2</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow3</math>
|-
| style="text-align:right;padding:0 1em;" | <math>3</math>
| || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''1''' </span> soustraction pour la tranche''
|-
| || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''.''' </span> point décimal avant la nouvelle tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>30</math>
| style="text-align:right;padding:0 1em;" | <math>300</math>
| style="text-align:right;padding:0 1em;" | <math>\,\mathbf{61}</math>
| (pas suffisant)
|-
| || || || ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''0''' </span> soustraction pour la tranche''
|- style="background-color:#9999ff80;border-collapse:collapse;border-top:solid 2px black;"
| style="text-align:right;padding:0 1em;" | <math>300</math>
| style="text-align:right;padding:0 1em;" | <math>30000</math>
| style="text-align:right;padding:0 1em;" | <math>61\,\mathbf{208}</math>
|
|-
| style="text-align:right;padding:0 1em;" | <math>301</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow30301</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow30907</math>
|-
| style="text-align:right;padding:0 1em;" | <math>302</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow30603</math>
|-
| style="text-align:right;padding:0 1em;" | <math>303</math>
|-
| style="text-align:right;padding:0 1em;" | <math>304</math>
| style="text-align:right;padding:0 1em;" | <math>\longrightarrow30907</math>
| style="text-align:right;padding:0 1em;" | <math>\Rightarrow0</math>
| ''<span style="background-color:yellow;color:black;border:solid 1px;"> '''2''' </span> soustractions pour la tranche''
|}
On a descendu deux tranches après la virgule ; on divise donc le résultat final par 100 :
<math>\textstyle{\frac{304+3-1}{3*100}=\frac{306}{300}=\frac{102}{100}=1.02\; ;\quad 1.02^3=1.061208 }</math>
[[Catégorie:Calcul écrit (livre)|Calcul de la racine n-ième d'un nombre]]
5sqmjltwaf5baamyn03ybpuluh6pqt1
Fonctionnement d'un ordinateur/L'architecture de base d'un ordinateur
0
65780
762724
762711
2026-04-01T14:07:50Z
Mewtow
31375
/* Le processeur */
762724
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
L'intérieur d'un processeur contient des circuits de calcul qui sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié. Il s'agit de la même unité de calcul qu'on trouve dans le processeur, du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les instructions arithmétiques, qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des instructions d'accès mémoire, qui échangent des données entre la mémoire RAM et le processeur, notamment entre la mémoire RAM et les registres. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
Au delà des registres de contrôle, le processeur contient un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul pour qu'elle fasse le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gére aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, le processeur utilise un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération. Elles étaient conçues pour lire le premier opérande depuis l'accumulateur, et le second opérande dans la mémoire RAM.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Voyons maintenant l'intérieur d'un processeur à registres généraux. Il contient une unité de calcul, des registres et une interface de communication avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
4hykg2zsw0vqwkfty3kw5i8ybw6rh8x
762725
762724
2026-04-01T14:15:15Z
Mewtow
31375
/* Le processeur */
762725
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. L'intérieur d'un processeur contient des circuits de calcul qui sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié. Il s'agit de la même unité de calcul qu'on trouve dans le processeur, du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul, les registres et l'interface avec la mémoire pour qu'elle fasse le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, le processeur utilise un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération. Elles étaient conçues pour lire le premier opérande depuis l'accumulateur, et le second opérande dans la mémoire RAM.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
jrhxi5sd6dk7eif2ewd9zojvjhg4sra
762726
762725
2026-04-01T14:16:25Z
Mewtow
31375
/* L'intérieur d'un processeur */
762726
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. L'intérieur d'un processeur contient des circuits de calcul qui sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié. Il s'agit de la même unité de calcul qu'on trouve dans le processeur, du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul, les registres et l'interface avec la mémoire pour qu'elle fasse le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, le processeur utilise un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération. Elles étaient conçues pour lire le premier opérande depuis l'accumulateur, et le second opérande dans la mémoire RAM.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
cwo58ch4it8jh366ebxm5yelxhbv64g
762727
762726
2026-04-01T14:18:15Z
Mewtow
31375
/* Introduction historique : les processeurs à accumulateur */
762727
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. L'intérieur d'un processeur contient des circuits de calcul qui sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié. Il s'agit de la même unité de calcul qu'on trouve dans le processeur, du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul, les registres et l'interface avec la mémoire pour qu'elle fasse le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
legoia1daivwp3rk60io6gw4gqfv2f3
762728
762727
2026-04-01T14:20:57Z
Mewtow
31375
/* L'intérieur d'un processeur */
762728
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul, les registres et l'interface avec la mémoire pour qu'elle fasse le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
cx1gy0583etktulu1ydspsb25oueg62
762729
762728
2026-04-01T14:21:43Z
Mewtow
31375
/* L'intérieur d'un processeur */
762729
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
bbm1d8xssjt3z8mapqdfup0hyw0m2rs
762730
762729
2026-04-01T14:24:10Z
Mewtow
31375
/* L'intérieur d'un processeur */
762730
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
my7cto3zz54nbf98w8vycifxuo5lysb
762731
762730
2026-04-01T14:30:44Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762731
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés par l'unité de contrôle, afin de sélectionner les registres adéquats.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
iayp9b7lphd8jjljh7563dtovj4plmw
762732
762731
2026-04-01T14:31:33Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762732
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des registres. Pour rappel, les '''registres''' sont de petites mémoires très rapides et de faible capacité, capables de mémoriser un nombre. Le nombre de registres dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans ce qui suit.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
m4mwhrez2vqn5jz88ioy6bctiwnt2y7
762733
762732
2026-04-01T14:35:16Z
Mewtow
31375
/* L'intérieur d'un processeur */
762733
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===Introduction historique : les processeurs à accumulateur===
Si le processeur fait des calculs, qu'en est-il des opérandes ? La solution la plus simple serait de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème. La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
De telles architectures étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide et les registres couteux à produire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeurs ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
mwx4am0txr58jsivnn6x0si160atewg
762735
762733
2026-04-01T15:45:00Z
Mewtow
31375
/* Le processeur */ Déplacement autre chapitre
762735
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
3ffyh78p7mtogqf5h9rhtuylju5xxpj
762742
762735
2026-04-01T16:15:25Z
Mewtow
31375
/* Un ordinateur peut avoir plusieurs processeurs */
762742
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===D'où viennent les adresses ?===
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? A cette réponse, il y a deux possibilités, qui correspondent à deux types de données : les données statiques et les données dynamiques.
Les '''données statiques''' sont les plus simples : elles existent durant toute la durée de vie du programme. Tant que celui-ci s'exécute, il aura besoin de ces données. En conséquence, il leur réserve une place en mémoire, qui est toujours la même. La donnée se situe donc à une adresse bien précise, qui ne change jamais. Attention cependant : les données peuvent être modifiées, changer de valeur. Le programme écrit dans les donnée statiques, c'est même assez fréquent. Ce sont ne sont pas forcément des données constantes !
Pour les données statiques, elles sont toujours placées à la même adresse mémoire. Pour le dire autrement, l'adresse mémoire est une constante, qui ne change pas. L'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. Et même si vous quittez le programme et vous le relancez plusieurs jours après, l'adresse mémoire sera la même avant et après.
t cela permet d'utiliser l''''adressage direct'''. L'idée est que l'adresse est intégrée dans l’instruction elle-même. Pour rappel, l'instruction est codée par une suite de bit en mémoire RAM/ROM, dont certains précisent l'opération à faire, les autres servant à autre chose. L'idée est que certains bits précisent l'adresse mémoire de la donnée à lire. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans un registre;
* ''STORE R5 , adress 99'', copie le registre R5 dans l'adresse 99 ;
* ''ADD R5 , adress 209'' : additionne le registre R5 avec le contenu de l'adresse 209.
S'il existe des données statiques, c'est signe qu'il existe des '''données dynamiques'''. Ces dernières sont des données qui sont créées ou détruites selon les besoins. Pour comprendre d'où viennent ces données dynamiques, prenons le cas d'une personne qui écrit du texte sur un ordinateur. Le texte qu'il écrit est mémorisé dans la RAM de l’ordinateur, puis est sauvegardé sur le disque dur quand il sauvegarde son document. Au fur et à mesure qu'il écrit du texte, la RAM utilisée par ce texte augmente. Donc, ce texte est une donnée dynamique, dont la taille varie dans le temps.
Pour gérer des données dynamiques, la plupart des systèmes d'exploitation incorporent des fonctionnalités d''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer les données qu'ils souhaitent. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free().
Avec l'allocation mémoire, les données n'ont pas de place fixe en mémoire. Leur adresse mémoire peut varier d'une exécution du programme à l'autre. Pire que ça : les données peuvent être déplacées dans la mémoire RAM, si besoin. En clair : l'adresse est déterminée lors de l'exécution du programme. L'adresse est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général. Pour gérer ces adresse variables, les processeurs utilisent l''''adressage indirect'''. L'adressage indirect permet d'utiliser une adresse qui est dans un registre de données. L'adresse en question peut être envoyée à la mémoire RAM sans problème, le processeur peut automatiquement connecter le registre adéquat sur le bus d'adresse.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
g284uq4z8bli8ktl7ap4lso20bz9zp2
762744
762742
2026-04-01T16:16:08Z
Mewtow
31375
/* D'où viennent les adresses ? */
762744
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===D'où viennent les adresses ?===
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? A cette réponse, il y a deux possibilités, qui correspondent à deux types de données : les données statiques et les données dynamiques.
Les '''données statiques''' sont les plus simples : elles existent durant toute la durée de vie du programme. Tant que celui-ci s'exécute, il aura besoin de ces données. En conséquence, il leur réserve une place en mémoire, qui est toujours la même. La donnée se situe donc à une adresse bien précise, qui ne change jamais. Attention cependant : les données peuvent être modifiées, changer de valeur. Le programme écrit dans les donnée statiques, c'est même assez fréquent. Ce sont ne sont pas forcément des données constantes !
Pour les données statiques, elles sont toujours placées à la même adresse mémoire. Pour le dire autrement, l'adresse mémoire est une constante, qui ne change pas. L'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. Et même si vous quittez le programme et vous le relancez plusieurs jours après, l'adresse mémoire sera la même avant et après.
t cela permet d'utiliser l''''adressage direct'''. L'idée est que l'adresse est intégrée dans l’instruction elle-même. Pour rappel, l'instruction est codée par une suite de bit en mémoire RAM/ROM, dont certains précisent l'opération à faire, les autres servant à autre chose. L'idée est que certains bits précisent l'adresse mémoire de la donnée à lire. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans un registre;
* ''STORE R5 , adress 99'', copie le registre R5 dans l'adresse 99 ;
* ''ADD R5 , adress 209'' : additionne le registre R5 avec le contenu de l'adresse 209.
S'il existe des données statiques, c'est signe qu'il existe des '''données dynamiques'''. Ces dernières sont des données qui sont créées ou détruites selon les besoins. Pour comprendre d'où viennent ces données dynamiques, prenons le cas d'une personne qui écrit du texte sur un ordinateur. Le texte qu'il écrit est mémorisé dans la RAM de l’ordinateur, puis est sauvegardé sur le disque dur quand il sauvegarde son document. Au fur et à mesure qu'il écrit du texte, la RAM utilisée par ce texte augmente. Donc, ce texte est une donnée dynamique, dont la taille varie dans le temps.
Pour gérer des données dynamiques, la plupart des systèmes d'exploitation incorporent des fonctionnalités d''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer les données qu'ils souhaitent. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free().
Avec l'allocation mémoire, les données n'ont pas de place fixe en mémoire. Leur adresse mémoire peut varier d'une exécution du programme à l'autre. Pire que ça : les données peuvent être déplacées dans la mémoire RAM, si besoin. En clair : l'adresse est déterminée lors de l'exécution du programme. L'adresse est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général. Pour gérer ces adresse variables, les processeurs utilisent l''''adressage indirect'''. L'adressage indirect permet d'utiliser une adresse qui est dans un registre de données. L'adresse en question peut être envoyée à la mémoire RAM sans problème, le processeur peut automatiquement connecter le registre adéquat sur le bus d'adresse.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
71od3byzgj3pqtdrl23i498xjqxttt5
762745
762744
2026-04-01T16:24:05Z
Mewtow
31375
/* D'où viennent les adresses ? */
762745
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===D'où viennent les adresses ?===
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Pour ce qui est des adresses des instructions, on connait déjà la réponse : c'est le ''program counter'' qui gère tout. Mais pour les données, il y a deux possibilités, qui correspondent à deux types de données : les données statiques et les données dynamiques.
Les '''données statiques''' sont les plus simples : elles existent durant toute la durée de vie du programme. Tant que celui-ci s'exécute, il aura besoin de ces données. En conséquence, il leur réserve une place en mémoire, qui est toujours la même. La donnée se situe donc à une adresse bien précise, qui ne change jamais. Attention cependant : les données peuvent être modifiées, changer de valeur. Le programme écrit dans les donnée statiques, c'est même assez fréquent. Ce sont ne sont pas forcément des données constantes !
Pour les données statiques, elles sont toujours placées à la même adresse mémoire. Pour le dire autrement, l'adresse mémoire est une constante, qui ne change pas. L'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. Et même si vous quittez le programme et vous le relancez plusieurs jours après, l'adresse mémoire sera la même avant et après.
t cela permet d'utiliser l''''adressage direct'''. L'idée est que l'adresse est intégrée dans l’instruction elle-même. Pour rappel, l'instruction est codée par une suite de bit en mémoire RAM/ROM, dont certains précisent l'opération à faire, les autres servant à autre chose. L'idée est que certains bits précisent l'adresse mémoire de la donnée à lire. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans un registre;
* ''STORE R5 , adress 99'', copie le registre R5 dans l'adresse 99 ;
* ''ADD R5 , adress 209'' : additionne le registre R5 avec le contenu de l'adresse 209.
S'il existe des données statiques, c'est signe qu'il existe des '''données dynamiques'''. Ces dernières sont des données qui sont créées ou détruites selon les besoins. Pour comprendre d'où viennent ces données dynamiques, prenons le cas d'une personne qui écrit du texte sur un ordinateur. Le texte qu'il écrit est mémorisé dans la RAM de l’ordinateur, puis est sauvegardé sur le disque dur quand il sauvegarde son document. Au fur et à mesure qu'il écrit du texte, la RAM utilisée par ce texte augmente. Donc, ce texte est une donnée dynamique, dont la taille varie dans le temps.
Pour gérer des données dynamiques, la plupart des systèmes d'exploitation incorporent des fonctionnalités d''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer les données qu'ils souhaitent. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free().
Avec l'allocation mémoire, les données n'ont pas de place fixe en mémoire. Leur adresse mémoire peut varier d'une exécution du programme à l'autre. Pire que ça : les données peuvent être déplacées dans la mémoire RAM, si besoin. En clair : l'adresse est déterminée lors de l'exécution du programme. L'adresse est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général. Pour gérer ces adresse variables, les processeurs utilisent l''''adressage indirect'''. L'adressage indirect permet d'utiliser une adresse qui est dans un registre de données. L'adresse en question peut être envoyée à la mémoire RAM sans problème, le processeur peut automatiquement connecter le registre adéquat sur le bus d'adresse.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
1uum0n2bpfxvi4xceydccmk7p0wjlqc
762746
762745
2026-04-01T16:27:32Z
Mewtow
31375
/* Lecture et écriture : mémoires ROM et RWM */
762746
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===D'où viennent les adresses ?===
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Pour ce qui est des adresses des instructions, on connait déjà la réponse : c'est le ''program counter'' qui gère tout. Mais pour les données, il y a deux possibilités, qui correspondent à deux types de données : les données statiques et les données dynamiques.
Les '''données statiques''' sont les plus simples : elles existent durant toute la durée de vie du programme. Tant que celui-ci s'exécute, il aura besoin de ces données. En conséquence, il leur réserve une place en mémoire, qui est toujours la même. La donnée se situe donc à une adresse bien précise, qui ne change jamais. Attention cependant : les données peuvent être modifiées, changer de valeur. Le programme écrit dans les donnée statiques, c'est même assez fréquent. Ce sont ne sont pas forcément des données constantes !
Pour les données statiques, elles sont toujours placées à la même adresse mémoire. Pour le dire autrement, l'adresse mémoire est une constante, qui ne change pas. L'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. Et même si vous quittez le programme et vous le relancez plusieurs jours après, l'adresse mémoire sera la même avant et après.
t cela permet d'utiliser l''''adressage direct'''. L'idée est que l'adresse est intégrée dans l’instruction elle-même. Pour rappel, l'instruction est codée par une suite de bit en mémoire RAM/ROM, dont certains précisent l'opération à faire, les autres servant à autre chose. L'idée est que certains bits précisent l'adresse mémoire de la donnée à lire. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans un registre;
* ''STORE R5 , adress 99'', copie le registre R5 dans l'adresse 99 ;
* ''ADD R5 , adress 209'' : additionne le registre R5 avec le contenu de l'adresse 209.
S'il existe des données statiques, c'est signe qu'il existe des '''données dynamiques'''. Ces dernières sont des données qui sont créées ou détruites selon les besoins. Pour comprendre d'où viennent ces données dynamiques, prenons le cas d'une personne qui écrit du texte sur un ordinateur. Le texte qu'il écrit est mémorisé dans la RAM de l’ordinateur, puis est sauvegardé sur le disque dur quand il sauvegarde son document. Au fur et à mesure qu'il écrit du texte, la RAM utilisée par ce texte augmente. Donc, ce texte est une donnée dynamique, dont la taille varie dans le temps.
Pour gérer des données dynamiques, la plupart des systèmes d'exploitation incorporent des fonctionnalités d''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer les données qu'ils souhaitent. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free().
Avec l'allocation mémoire, les données n'ont pas de place fixe en mémoire. Leur adresse mémoire peut varier d'une exécution du programme à l'autre. Pire que ça : les données peuvent être déplacées dans la mémoire RAM, si besoin. En clair : l'adresse est déterminée lors de l'exécution du programme. L'adresse est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général. Pour gérer ces adresse variables, les processeurs utilisent l''''adressage indirect'''. L'adressage indirect permet d'utiliser une adresse qui est dans un registre de données. L'adresse en question peut être envoyée à la mémoire RAM sans problème, le processeur peut automatiquement connecter le registre adéquat sur le bus d'adresse.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
ogqvh5ye98fsppotafpi8v19piudybr
762747
762746
2026-04-01T16:31:51Z
Mewtow
31375
/* D'où viennent les adresses ? */
762747
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===D'où viennent les adresses ?===
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Pour ce qui est des adresses des instructions, on connait déjà la réponse : c'est le ''program counter'' qui gère tout. Mais pour les données, il y a deux possibilités, qui correspondent à deux types de données : les données statiques et les données dynamiques.
Les '''données statiques''' sont les plus simples : elles existent durant toute la durée de vie du programme. Tant que celui-ci s'exécute, il aura besoin de ces données. En conséquence, il leur réserve une place en mémoire, qui est toujours la même. La donnée se situe donc à une adresse bien précise, qui ne change jamais. Attention cependant : les données peuvent être modifiées, changer de valeur. Le programme écrit dans les donnée statiques, c'est même assez fréquent. Ce sont ne sont pas forcément des données constantes !
Pour les données statiques, elles sont toujours placées à la même adresse mémoire. Pour le dire autrement, l'adresse mémoire est une constante, qui ne change pas. L'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. Et même si vous quittez le programme et vous le relancez plusieurs jours après, l'adresse mémoire sera la même avant et après.
Et cela permet d'utiliser l''''adressage direct'''. L'idée est que les instructions précisent donc l'adresse à lire ou écrire. Pour cela, l'adresse est intégrée dans l’instruction elle-même. Pour rappel, l'instruction est codée par une suite de bit en mémoire RAM/ROM, dont certains précisent l'opération à faire, les autres servant à autre chose. L'idée est que certains bits précisent l'adresse mémoire de la donnée à lire. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans un registre;
* ''STORE R5 , adress 99'', copie le registre R5 dans l'adresse 99 ;
* ''ADD R5 , adress 209'' : additionne le registre R5 avec le contenu de l'adresse 209.
S'il existe des données statiques, c'est signe qu'il existe des '''données dynamiques'''. Ces dernières sont des données qui sont créées ou détruites selon les besoins. Pour comprendre d'où viennent ces données dynamiques, prenons le cas d'une personne qui écrit du texte sur un ordinateur. Le texte qu'il écrit est mémorisé dans la RAM de l’ordinateur, puis est sauvegardé sur le disque dur quand il sauvegarde son document. Au fur et à mesure qu'il écrit du texte, la RAM utilisée par ce texte augmente. Donc, ce texte est une donnée dynamique, dont la taille varie dans le temps.
Pour gérer des données dynamiques, la plupart des systèmes d'exploitation incorporent des fonctionnalités d''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer les données qu'ils souhaitent. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free().
Avec l'allocation mémoire, les données n'ont pas de place fixe en mémoire. Leur adresse mémoire peut varier d'une exécution du programme à l'autre. Pire que ça : les données peuvent être déplacées dans la mémoire RAM, si besoin. En clair : l'adresse est déterminée lors de l'exécution du programme. L'adresse est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général. Pour gérer ces adresse variables, les processeurs utilisent l''''adressage indirect'''. L'adressage indirect permet d'utiliser une adresse qui est dans un registre de données. L'adresse en question peut être envoyée à la mémoire RAM sans problème, le processeur peut automatiquement connecter le registre adéquat sur le bus d'adresse.
Au tout début de l'informatique, les processeurs ne supportaient que l'adressage direct, pas plus. L'adressage indirect n'était tout simplement pas possible. Mais dès les années 70, l'adressage indirect est apparu, rendant la programmation bien plus simple. Mais cela a demandé quelques adaptation au niveau du processeur. Avec l'adressage direct, l'adresse à lire est extraite directement des instructions, par l'unité de contrôle. Le bus d'adresse de la RAM est alors relié directement à l'unité de contrôle, le bus de données est relié aux registres.
Avec l'adressage indirect, le bus d'adresse est connecté soit aux registres, soit à l'unité de contrôle.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
4g762ppoowehba8y1frboy6s8l5em83
762748
762747
2026-04-01T18:14:52Z
Mewtow
31375
/* D'où viennent les adresses ? */
762748
wikitext
text/x-wiki
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 :
* un '''processeur''', qui manipule l'information et donne un résultat ;
* une '''mémoire''' qui mémorise les données à manipuler ;
* les '''entrées/sorties''', qui permettent à l'ordinateur de communiquer avec l'extérieur.
[[File:Architecture Von Neumann.png|centre|vignette|upright=2|Architecture d'un système à mémoire.]]
Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs. Rien d'étonnant à cela. Je rappelle que tout est codé par des nombres dans un ordinateur, ce qui fait que manipuler des nombres revient simplement à faire des calculs. Un ordinateur n'est donc qu'une grosse calculatrice améliorée, et le processeur est le composant qui fait les calculs.
La mémoire s'occupe purement de la mémorisation des données, des nombres sur lesquelles faire des calculs. Pour être plus précis, il y a deux mémoires : une pour les données proprement dites, une autre pour le programme à exécuter. La première est la '''mémoire RAM''', la seconde est la '''mémoire ROM'''. Nous détaillerons ce que sont ces deux mémoires dans la suite du chapitre, mais sachez que nous avions déjà rencontré ces deux types de mémoires dans les chapitres sur les registres et les mémoires adressables.
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. Les '''périphériques''' regroupent, pour rappel, tout ce est branché sur un ordinateur, mais n'est pas à l'intérieur de celui-ci.
Le processeur, les mémoires et les entrées-sorties communiquent ensemble via un '''réseau d'interconnexions'''. Le terme est assez barbare, mais rien de compliqué sur le principe. C'est juste un ensemble de fils électriques qui relie les différents éléments d'un ordinateur. Les interconnexions sont souvent appelées le bus de communication, mais le terme est un abus de langage, comme on le verra plus bas.
Afin de simplifier les explications, on va supposer que le réseau d'interconnexion est le suivant. Tout est connecté au processeur. Il y a des interconnexions entre le processeur et la mémoire RAM, d'autres interconnexions entre processeur et mémoire ROM, et d'autres entre le processeur et les entrées-sorties. Nous verrons que d'autres réseaux d'interconnexions fusionnent certaines interconnexions, pour les partager entre la ROM et la RAM, par exemple. Mais pour le moment, gardez le schéma ci-dessous en tête.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
==Les mémoires RAM et ROM==
La mémoire est le composant qui mémorise des informations, des données. Dans la majorité des cas, la mémoire est composée de plusieurs '''cases mémoire''', chacune mémorisant plusieurs bits, le nombre de bits étant identique pour toutes les cases mémoire. Dans le cas le plus simple, une case mémoire mémorise un '''octet''', un groupe de 8 bits. Mais les mémoires modernes mémorisent plusieurs octets par case mémoire : elles ont des cases mémoires de 16, 32 ou 64 bits, soit respectivement 2/4/8 octets. De rares mémoires assez anciennes utilisaient des cases mémoires contenant 1, 2, 3, 4, 5, 6 7, 13, 17, 23, 36 ou 48 bits. Mais ce n'était pas des mémoires électroniques, aussi nous allons les passer sous silence.
Tout ce qu'il faut savoir est que la quasi-totalité des mémoires électronique a un ou plusieurs octets par case mémoire. Pour simplifier, vous pouvez imaginer qu'une mémoire RAM est un regroupement de registre, chacun étant une case mémoire. C'est une description pas trop mauvaise pour décrire les mémoires RAM, qu'on abordera dans ce qui suit.
{|class="wikitable"
|+ Contenu d'une mémoire, case mémoire de 16 bits (deux octets)
|-
! Case mémoire N°1
| 0001 0110 1111 1110
|-
! Case mémoire N°2
| 1111 1110 0110 1111
|-
! Case mémoire N°3
| 0001 0000 0110 0001
|-
! Case mémoire N°4
| 1000 0110 0001 0000
|-
! Case mémoire N°5
| 1100 1010 0110 0001
|-
! ...
| ...
|-
! Case mémoire N°1023
| 0001 0110 0001 0110
|-
! Case mémoire N°1024
| 0001 0110 0001 0110
|}
Dans ce cours, il nous arrivera de partir du principe qu'il y a un octet par case mémoire, par souci de simplification. Mais ce ne sera pas systématique. De plus, il nous arrivera d'utiliser le terme adresse pour parler en réalité de la case mémoire associée, par métonymie.
===La capacité mémoire===
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 maximal de bits qu'une mémoire peut contenir. Elle est le produit entre le nombre de cases mémoire, et la taille en bit d'une case mémoire.
Toutes les mémoires actuelles utilisant des cases mémoire d'un ou plusieurs octets, ce qui nous arrange pour compter la capacité d'une mémoire. Au lieu de compter cette capacité en bits, on préfère mesurer la capacité d'une mémoire avec le nombre d'octets qu'elle contient. 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. Vous connaissez sûrement ces préfixes : kibioctets, mébioctets et gibioctets, notés respectivement Kio, Mio et Gio.
{|class="wikitable"
|-
!Préfixe!!Capacité mémoire en octets!!Puissance de deux
|-
||Kio||1024||2<sup>10</sup> octets
|-
||Mio||1 048 576||2<sup>20</sup> octets
|-
||Gio||1 073 741 824||2<sup>30</sup> octets
|}
On peut se demander pourquoi utiliser des puissances de 1024, et ne pas utiliser des puissances un peu plus communes ? Dans la majorité des situations, les électroniciens préfèrent manipuler des puissances de deux pour se faciliter la vie. 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. Quand vous vous pesez sur votre balance et que celle-ci vous indique 58 kilogrammes, cela veut dire que vous pesez 58 000 grammes. De même, un kilomètre est égal à 1000 mètres, et non 1024 mètres.
Autrefois, on utilisait les termes kilo, méga et giga à la place de nos 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. Et cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, méga ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mébi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
===Lecture et écriture : mémoires ROM et RWM===
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 minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Pour simplifier, la mémoire ROM mémorise le programme à exécuter, la mémoire RWM stocke des données. Il a existé des ordinateurs où la mémoire RWM était une mémoire magnétique, voire acoustique, mais ce n'est plus le cas de nos jours. Pour les ordinateurs modernes, la mémoire RWM est une mémoire électronique. Pour faire la différence avec ces anciennes mémoires RWM, elle est appelée la '''mémoire RAM'''. Il s'agit d'une mémoire qui stocke temporairement des données que le processeur doit manipuler (on dit qu'elle est volatile). Elle s'efface complètement quand on coupe l'alimentation de l'ordinateur.
Outre le programme à exécuter, la mémoire ROM peut mémoriser des constantes, des données qui ne changent pas. Elles ne sont jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. En conséquence, elles ne sont jamais accédées en écriture durant l'exécution du programme, ce qui fait que leur place est dans une mémoire ROM. La mémoire RWM est alors destinée aux données temporaires, qui changent ou sont modifiées lors de l'exécution du programme, et qui sont donc manipulées aussi bien en lecture et en écriture. La mémoire RWM mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Pour donner un exemple de données stockées en ROM, on peut prendre l'exemple des anciennes consoles de jeu 8 et 16 bits. Les jeux vidéos sur ces consoles étaient placés dans des cartouches de jeu, précisément dans une mémoire ROM à l'intérieur de la cartouche de jeu. La ROM mémorisait non seulement le code du jeu, le programme du jeu vidéo, mais aussi les niveaux et les ''sprites'' et autres données graphiques.
Une conséquence est que les consoles 8/16 bits n'avaient pas besoin de beaucoup de RAM, comparé aux ordinateurs de l'époque, vu qu'une grande partie des données utiles étaient dans une ROM directement accessible par le processeur. À l'opposé, les micro-ordinateurs devaient copier les données d'un jeu depuis une disquette dans la mémoire RAM, ce qui demandait d'avoir plus de RAM. Le passage au support CD sur les consoles 32 bits a eu la même conséquence. Le processeur ne pouvant pas lire directement le CD à sa guise, il fallait copier les données du CD en RAM. D'où l'apparition de temps de chargement assez longs, inexistants sur support cartouche.
===L'adressage mémoire===
Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'une case mémoire, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'une seule case mémoire. Techniquement, le processeur doit préciser à quel case mémoire il veut accéder à chaque lecture/écriture. Pour cela, chaque case mémoire 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 cases mémoire.
[[File:Adressage mémoire.png|centre|vignette|upright=2|Exemple : on demande à la mémoire de sélectionner la case mémoire d'adresse 1002 et on récupère son contenu (ici, 17).]]
L'adresse mémoire est générée par le processeur. Le processeur peut parfaitement calculer des adresses, en extraire du programme qu'il exécute, et bien d'autres choses. Nous détaillerons d'ailleurs les mécanismes pour dans les chapitres portant sur les modes d'adressage du processeur. Mais pour le moment, nous avons juste besoin de savoir que c'est le processeur qui envoie des adresses aux mémoires RAM et ROM.
Les adresses générées par le processeur sont alors envoyées à la RAM ou la ROM via une connexion dédiée, un ensemble de fils qui connecte le processeur à la mémoire : le '''bus d'adresse mémoire'''. L'adresse sélectionne une case mémoire, le processeur peut alors récupérer la donnée dedans pour une lecture, écrire une donnée pour l'écriture. Pour cela, un second ensemble de fil connecte le processeur à la RAM/ROM, mais cette fois-ci pour échanger des données. Il s'agit du '''bus de données mémoire'''. Les deux sont souvent regroupés sous le terme de '''bus mémoire'''.
Un ordinateur contient toujours une RAM et une ROM, ce qui demande aux bus mémoire de s'adapter à la présence de deux mémoires. Il y a alors deux solutions, illustrées dans les deux schémas ci-dessous. Avec la première, il y a un seul bus mémoire partagé entre la RAM et la ROM, comme illustré ci-dessous. Une autre solution utilise deux bus séparés : un pour la RAM et un autre pour la ROM. Nous verrons les différences pratiques entre les deux à la fin du chapitre. Pour le moment, nous allons partir du principe qu'il y a un bus pour la mémoire ROM, et un autre bus pour la RAM.
[[File:CPT-System-Architecture-gapfill1-ANS.svg|centre|vignette|upright=2|Architecture avec une ROM et une RAM.]]
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
===L'alignement mémoire : introduction===
Plus haut, nous avions dit qu'il y a une adresse par case mémoire, chaque case mémoire contenant un ou plusieurs octets. Mais les processeurs modernes partent du principe que la mémoire a un octet par adresse, pas plus. Et ce même si la mémoire reliée au processeur utilise des cases mémoires de 2, 3, 4 octets ou plus. D'ailleurs, la majorité des mémoires RAM actuelle a des cases mémoires de 64 bits, soit 8 octets par case mémoire. Les raisons à cela sont multiple, mais nous les verrons en détail dans le chapitre sur l'alignement mémoire. Toujours est-il qu'il faut distinguer les '''adresses mémoire''' et les '''adresses d'octet''' gérées par le processeur.
Le processeur génère des adresses d'octet, qui permettent de sélectionner un octet bien précis. L'adresse d'octet permet de sélectionner un octet parmi tous les autres. Mais la mémoire ne comprend pas directement cette adresse d'octet. Heureusement, l'octet en question est dans une case mémoire bien précise, qui a elle-même une adresse mémoire bien précise. L'adresse d'octet est alors convertie en une adresse mémoire, qui sélectionne la case mémoire adéquate, celle qui contient l'octet voulu. La case mémoire entière est lue, puis le processeur ne récupère que les données adéquates. Pour cela, des circuits d'alignement mémoire se chargent de faire la conversion entre adresses du processeur et adresse mémoire. Nous verrons cela dans le détail dans le chapitre sur l'alignement mémoire.
Il existe des mémoires qui n'utilisent pas d'adresses mémoire, mais passons : ce sera pour la suite du cours.
==Le processeur==
Dans les ordinateurs, l'unité de traitement porte le nom de '''processeur''', ou encore de '''''Central Processing Unit''''', abrévié en CPU. Le rôle principal du processeur est de faire des calculs. La plupart des processeurs actuels supportent au minimum l'addition, la soustraction et la multiplication. Quelques processeurs ne gèrent pas la division, qui est une opération très gourmande en circuit, peu utilisée, très lente. Il arrive que des processeurs très peu performants ne gèrent pas la multiplication, mais c'est assez rare.
Un processeur ne fait pas que des calculs. 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'''. Les plus intuitives sont les '''instructions arithmétiques''', qui font des calculs, comme l'addition, la soustraction, la multiplication, la division. Mais il y a aussi des '''instructions d'accès mémoire''', qui échangent des données entre la mémoire RAM et le processeur. Les autres instructions ne sont pas très intuitives, aussi passons-les sous silence pour le moment, tout deviendra plus clair dans les chapitres sur le processeur.
===Le processeur exécute un programme, une suite d'instructions===
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. 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. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres.
Le programme à exécuter est stockée dans la mémoire de l'ordinateur. 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.
Une instruction est codée comme les données : sous la forme de suites de bits. Telle suite de bit indique qu'il faut faire une addition, telle autre demande de faire une soustraction, etc. Pour simplifier, nous allons supposer qu'il y a une instruction par adresse mémoire. 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.
{|class="wikitable"
|+ Exemple de programme informatique
|-
! Adresse
! Instruction
|-
! 0
| Copier le contenu de l'adresse 0F05 dans le registre numéro 5
|-
! 1
| Charger le contenu de l'adresse 0555 dans le registre numéro 4
|-
! 2
| Additionner ces deux nombres
|-
! 3
| Charger le contenu de l'adresse 0555
|-
! 4
| Faire en XOR avec le résultat antérieur
|-
! ...
| ...
|-
! 5464
| Instruction d'arrêt
|}
Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Pour cela, le processeur mémorise l'adresse de l'instruction en cours dans un registre : le '''Program Counter'''. Je rappelle que des instructions consécutives sont dans des adresses consécutives. Pour passer à la prochaine instruction, il suffit donc d'incrémenter le ''program counter''.
: Si une instruction prend plusieurs octets, plusieurs adresses, il suffit de l'incrémenter du nombre d'octets/adresses.
D'autres processeurs font autrement : chaque instruction précise l'adresse de la suivante, directement dans la suite de bit représentant l'instruction en mémoire. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. 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.
Nous venons de voir qu'un processeur contient un registre appelé le ''program counter''. Mais il n'est pas le seul. Pour pouvoir fonctionner, tout processeur doit mémoriser un certain nombre d’informations nécessaires à son fonctionnement, qui sont mémorisées dans des '''registres de contrôle'''. La plupart ont des noms assez barbares (registre d'état, ''program counter'') et nous ne pouvons pas en parler à ce moment du cours. Nous les verrons en temps voulu, mais il est important de préciser qu'ils existent.
===L'intérieur d'un processeur===
Fort de ce que nous savons, nous pouvons expliquer ce qu'il y a à l'intérieur d'un processeur. Le premier point est qu'un processeur fait des calculs, ce qui implique qu'il contient des circuits de calcul. Ils sont regroupés dans une ou plusieurs '''unités de calcul'''. Nous avons déjà vu comment fabriquer une unité de calcul simple, dans un chapitre dédié, et c'est la même qui est présente dans un processeur. Du moins dans les grandes lignes, les circuits des processeurs modernes étant particulièrement optimisés. Il en est de même pour les autres circuits de calcul comme ceux pour les multiplications/division/autres.
Si le processeur fait des calculs, qu'en est-il des opérandes ? Et où sont mémorisés les résultats des opérations ? Pour cela, le processeur incorpore des '''registres généraux'''. Les registres généraux servent à mémoriser les opérandes et résultats des instructions. Ils mémorisent des données, contrairement aux registres de contrôle mentionnés plus haut. Le nombre de registres généraux dépend grandement du processeur. Les tout premiers processeurs se débrouillaient avec un seul registre, mais les processeurs actuels utilisent plusieurs registres, pour mémoriser plusieurs opérandes/résultats. Mais la présence de registres est source de pas mal de petites complications. Par exemple, il faut échanger les données entre la RAM et les registres, il faut gérer l'adressage des registres, etc. Il s'agit là de détails que nous expliquerons dans les chapitres sur le processeur.
Le processeur contient enfin un circuit pour interpréter les instructions, appelé l''''unité de contrôle'''. Elle lit les instructions depuis la mémoire, interprète la suite de bit associée, et commande le reste du processeur pour qu'il exécute l'instruction. Ses fonctions sont assez variées, mais nous allons simplifier en disant qu'elle configure l'unité de calcul et les registres pour faire le bon calcul. Son rôle est d'analyser la suite de bit qui constitue l'instruction, et d'en déduire quelle opération effectuer. Elle gère aussi l'accès à la mémoire RAM, et notamment ce qui est envoyé sur son bus d'adresse.
: Dans ce qui suit, on suppose que le ''program counter'' fait partie de l'unité de contrôle.
Pour résumer, un processeur contient une unité de calcul, des registres et une interface avec la mémoire RAM. Le tout est interconnecté, afin de pouvoir échanger des données. L’ensemble forme le '''chemin de données''', nom qui trahit le fait que c'est là que les données se déplacent et sont traitées. Il faut aussi ajouter l'unité de contrôle pour commander le tout. Elle lit les instructions en mémoire, puis commande le chemin de données pour que l'instruction soit exécutée correctement.
[[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]]
Un processeur parait donc assez simple expliqué comme ça, mais il y a de nombreuses subtilités. L'une d'entre elle est liée aux registres, et notamment à la manière dont on les utilise. Pour expliquer ces subtilités, nous allons voir comment les premiers processeurs fonctionnaient, avant de passer aux processeurs un peu plus modernes. Les tout premiers processeurs n'utilisaient qu'un seul registre, ce qui fait que l'utilisation des registres était très simple. Le passage à plusieurs registres a complexifié le tout.
===D'où viennent les adresses ?===
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Pour ce qui est des adresses des instructions, on connait déjà la réponse : c'est le ''program counter'' qui gère tout. Mais pour les données, il y a deux possibilités, qui correspondent à deux types de données : les données statiques et les données dynamiques.
Les '''données statiques''' sont les plus simples : elles existent durant toute la durée de vie du programme. Tant que celui-ci s'exécute, il aura besoin de ces données. En conséquence, il leur réserve une place en mémoire, qui est toujours la même. La donnée se situe donc à une adresse bien précise, qui ne change jamais. Attention cependant : les données peuvent être modifiées, changer de valeur. Le programme écrit dans les donnée statiques, c'est même assez fréquent. Ce sont ne sont pas forcément des données constantes !
Pour les données statiques, elles sont toujours placées à la même adresse mémoire. Pour le dire autrement, l'adresse mémoire est une constante, qui ne change pas. L'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. Et même si vous quittez le programme et vous le relancez plusieurs jours après, l'adresse mémoire sera la même avant et après.
Et cela permet d'utiliser l''''adressage direct'''. L'idée est que les instructions précisent donc l'adresse à lire ou écrire. Pour cela, l'adresse est intégrée dans l’instruction elle-même. Pour rappel, l'instruction est codée par une suite de bit en mémoire RAM/ROM, dont certains précisent l'opération à faire, les autres servant à autre chose. L'idée est que certains bits précisent l'adresse mémoire de la donnée à lire. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans un registre;
* ''STORE R5 , adress 99'', copie le registre R5 dans l'adresse 99 ;
* ''ADD R5 , adress 209'' : additionne le registre R5 avec le contenu de l'adresse 209.
S'il existe des données statiques, c'est signe qu'il existe des '''données dynamiques'''. Ces dernières sont des données qui sont créées ou détruites selon les besoins. Pour comprendre d'où viennent ces données dynamiques, prenons le cas d'une personne qui écrit du texte sur un ordinateur. Le texte qu'il écrit est mémorisé dans la RAM de l’ordinateur, puis est sauvegardé sur le disque dur quand il sauvegarde son document. Au fur et à mesure qu'il écrit du texte, la RAM utilisée par ce texte augmente. Donc, ce texte est une donnée dynamique, dont la taille varie dans le temps.
Pour gérer des données dynamiques, la plupart des systèmes d'exploitation incorporent des fonctionnalités d''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer les données qu'ils souhaitent. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free().
Avec l'allocation mémoire, les données n'ont pas de place fixe en mémoire. Leur adresse mémoire peut varier d'une exécution du programme à l'autre. Pire que ça : les données peuvent être déplacées dans la mémoire RAM, si besoin. En clair : l'adresse est déterminée lors de l'exécution du programme. L'adresse est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général. Pour gérer ces adresse variables, les processeurs utilisent l''''adressage indirect'''. L'adressage indirect permet d'utiliser une adresse qui est dans un registre de données. L'adresse en question peut être envoyée à la mémoire RAM sans problème, le processeur peut automatiquement connecter le registre adéquat sur le bus d'adresse.
Au tout début de l'informatique, les processeurs ne supportaient que l'adressage direct, pas plus. L'adressage indirect n'était tout simplement pas possible. Avec l'adressage direct, l'adresse à lire est extraite directement des instructions, par l'unité de contrôle. Le bus d'adresse de la RAM est alors relié directement à l'unité de contrôle, le bus de données est relié aux registres.
[[File:Architecture Harvard avec adressage direct uniquement.png|centre|vignette|upright=2|Architecture Harvard avec adressage direct uniquement]]
Mais dès les années 70, l'adressage indirect est apparu, rendant la programmation bien plus simple. Mais cela a demandé quelques adaptation au niveau du processeur. Avec l'adressage indirect, le bus d'adresse est connecté aux registres. Il a donc fallu rajouter un multiplexeur pour que le processeur décide de relier le bus d'adresse soit aux registres, soit à l'unité de contrôle.
===Un ordinateur peut avoir plusieurs processeurs===
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.
[[File:Architecture de Von Neumann Princeton multi processeurs.svg|centre|vignette|upright=2|Architecture de Von Neumann Princeton multi processeurs]]
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===
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.
Les coprocesseurs les plus connus 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. Ils s'occupaient respectivement de calculer les graphismes des jeux vidéos, et de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un co-processeur sonore. Le processeur principal était un Motorola 68000, alors que le co-processeur sonore était un processeur Z80.
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 d'IO''' soit dédié à l'accès aux périphériques. Un exemple assez récent est celui de la console de jeu Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, d'un coprocesseur pour les divisions qu'on abordera plus bas, et d'un second processeur ARM7. L'ARM 7 était utilisé comme coprocesseur d'I/O, ainsi que pour l'émulation de la console GBA.
[[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]]
Les '''coprocesseurs arithmétiques''' sont un peu à part des autres. 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). 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.
Les coprocesseurs arithmétiques étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans co-processeur. 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. Sans ces coprocesseurs, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. 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 exemple récent 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 co-processeurs arithmétiques se distinguent des autres car ils fonctionnent en tandem avec le processeur principal, pas en parallèle. Les co-processeurs précédents sont autonomes, à savoir qu'ils exécutent un programme différent de celui exécuté par le CPU. Mais les co-processeurs arithmétiques ne sont pas dans ce cas. Il n'y a qu'un seul programme à exécuter, qui contient des instructions à destination du CPU, d'autres à destination du co-processeur. Les instructions sont exécutées soit par le CPU, soit par le co-processeur, une par une.
==Les entrées-sorties==
Tous les circuits vus précédemment traitent 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 traduisent 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.
Les '''entrées-sorties''' incluent toutes les entrées et sorties, et même certains composants qui sont les deux à la fois. Il s'agit d'un terme générique, qui regroupe des composants forts différents. Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties, mais les deux termes ne sont pas équivalents. Dans le détail, les entrées-sorties regroupent :
* 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, la Box internet, etc.
* Les '''cartes d'extension''', 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.
===L'interface avec le reste de l'ordinateur===
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 l'entrée/sortie et le reste de l'ordinateur. L'entrée/sortie est conçu pour réagir automatiquement quand on écrit dans ces registres.
[[File:Registres d'interfaçage.png|centre|vignette|upright=2|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 l'entrée/sortie, 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 à une entrée/sortie, 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 à l'entrée/sortie. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles l'entrée/sortie répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour l'entrée/sortie. 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, l'entrée/sortie contient des ''registres de commande'' qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande à l'entrée/sortie, il écrit la commande en question dans ce ou ces registres.
Enfin, beaucoup d'entrée/sortie ont un ''registre d'état'', lisible par le processeur, qui contient des informations sur l'état de l'entrée/sortie. Ils servent notamment à indiquer au processeur que l'entrée/sortie 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===
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érentes entrées/sorties ne se marchent pas sur les pieds. Chaque entrée/sortie, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel est le destinataire. Certains indiquent quel est l'entrée/sortie voulue, les restants indiquant le registre de destination.
Il existe deux organisations possibles 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.
[[File:Espaces d'adressages séparés entre mémoire et périphérique.png|centre|vignette|upright=2.5|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.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
Pour résumer, communiquer avec une entrée/sortie est similaire à ce qu'on a avec les mémoires. Il suffit de lire ou écrire dans des registres d’interfaçage, qui ont chacun une adresse mémoire. Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'une entrée/sortie : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec l'entrée/sortie, 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.
==Les architectures Harvard et Von Neumann==
Après avoir vu le processeur, les mémoires et les entrées-sorties, voyons voir comment le tout est interconnecté. Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Mais pour comprendre pourquoi, nous devons regarder qui communique avec qui, dans un ordinateur. Pour rappel, les données sont placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. Le processeur lit des instructions dans la mémoire ROM, il lit et écrit dans la mémoire RAM, et accède aux registres d’interfaçage des entrées-sorties. Il y a donc besoins de trois interconnexions : CPU-ROM, CPU-RAM et CPU-IO.
[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre]]
Il parait intéressant d'utiliser trois interconnexions, au minimum CPU-ROM, CPU-RAM et CPU-IO. Néanmoins, faire ainsi a de nombreux désavantages. Déjà, il faut pouvoir brancher tout ça sur le processeur. Et celui-ci n'a pas forcément assez de broches pour. Aussi, il est parfois préférable de mutualiser des bus, à savoir de connecter plusieurs composants sur un même bus. Par exemple, on peut mutualiser le bus pour la mémoire RAM et pour la mémoire ROM. Il faut dire que les deux bus sont des bus mémoire, avec un bus d'adresse, un bus de données, et surtout : des bus de commande similaires. Les mutualiser est alors très simple, et permet d'économiser pas mal de broches.
[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre et une architecture Harvard]]
Cette mutualisation nous amène naturellement à parler de la distinction entre les architectures Harvard d'un côté et les architectures Von Neumann de l'autre. Elle est très liée au fait d'utiliser soit un bus mémoire unique, soit des bus séparés pour la ROM et la RAM. Voyons cela en détail.
===Les architectures Harvard et Von Neumann : des bus séparés ou unifiés===
Avec l''''architecture Harvard''', la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. Il y a un bus RAM pour la mémoire RAM, un bus ROM pour la mémoire ROM. 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. Et cela simplifie fortement la conception du processeur.
[[File:Harvard Architecture.png|centre|vignette|upright=2|Architecture Harvard, avec une ROM et une RAM séparées.]]
Avec l''''architecture Von Neumann''', mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Le bus unique qui relie processeur, RAM et ROM, s'appelle le '''bus mémoire'''. Un défaut de ces architecture est qu'elles ne peuvent pas charger une instruction et une donnée en même temps. Et cela pose quelques problèmes pour la conception du processeur. Par contre, nous verrons dans ce qui suit qu'utiliser un bus mémoire partagé est bien plus flexible et permet des choses que les architectures Harvard ne peuvent pas faire.
[[File:Architecture Von Neumann, avec deux bus séparés.png|centre|vignette|upright=2|Architecture Von Neumann, avec deux bus séparés.]]
===Les architectures Harvard et Von Neumann : des espaces d'adressage séparés ou unifiés===
La distinction précédente se base sur les connexions entre RAM, ROM et processeur. Mais il existe une autre distinction, très liée, qui est souvent utilisée comme seconde définition des architectures Harvard/Von Neumann. Elle est liée aux adresses mémoire que le processeur peut gérer. Prenons un processeur 16 bits, par exemple, qui gère naturellement des adresses de 16 bits. Il peut gérer 2^16 adresses, soit 64 kibioctets de mémoire. L'ensemble de ces adresses est appelé un '''espace d'adressage'''. Mais comment cet espace d'adressage est utilisé pour adresser une RAM et une ROM ?
Sur les architectures Harvard, le processeur voit deux mémoires séparées avec leur lot d'adresses distinctes. Une même adresse peut donc correspondre soit à la mémoire ROM, soit à la mémoire RAM, suivant le bus utilisé. L'espace d'adressage est donc doublé, dupliqué, avec un pour la ROM, un autre pour la RAM. Rien d'étonnant à cela : il y a deux bus d'adresses, chacun correspondant à un espace d'adressage.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Avec l'architecture Von Neumann, la RAM et la ROM doivent se partager les adresses mémoires disponibles. Il n'y a qu'un seul espace d'adressage qui est coupé en deux, avec une partie pour la ROM et une autre pour la RAM. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM occupe une partie des adresses, la mémoire RAM utilise le reste. La répartition des adresses est réalisée par les circuits de décodage d'adresse mentionnés plus haut.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
Les '''architectures Harvard modifiées''' sont des intermédiaires entre architectures Harvard et architectures Von Neumann, bien qu'elles penchent bien plus du côté des architectures Harvard. Précisons que la terminologie n'est pas claire, beaucoup d'auteurs mettent des définitions différentes derrière ces deux termes. Mais dans ce cours, nous utiliserons une définition très stricte de ce qu'est une architecture Harvard modifiée.
Une architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Nous avions vu plus haut que les mémoires ROM peuvent mémoriser, en plus d'un programme exécutable, des données constantes, qui ne varient pas. Les architectures Harvard pures ne permettent pas de lire des données de ce genre depuis la mémoire ROM, alors que les architectures Harvard modifiées le permettent.
Une architecture Harvard modifiée dispose 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. Il y a donc deux versions de l'instruction LOAD, qui copient la donnée dans un registre général, mais dont la source de la donnée est différente. Une autre possibilité, plus rare, est que une instruction de copie, qui copie une constante depuis la mémoire ROM vers la mémoire RAM. Le cas le plus commun est l'utilisation de deux instructions LOAD séparées.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=2.5|Espaces d'adressage sur une archi harvard modifiée]]
Ceci étant dit, revenons à la distinction entre architecture Harvard et Von Neumann. Il faut noter que la RAM et la ROM n'ont pas forcément la même taille. Et ce que ce soit sur une architecture Harvard que sur une architecture Von Neumann, mais c'est plus facile à expliquer sur une architecture Harvard.
On peut par exemple imaginer une architecture Harvard qui utilise des adresses de 16 bits pour la ROM, et seulement 8 bits pour la RAM. Le résultat est qu'il peut adresser 64 kibioctets de ROM, mais seulement 256 octets de RAM. Les deux bus d'adresse sont alors de taille différente, l'un faisant 8 bits, l'autre 16. Quelques processeurs 8 bits étaient dans ce cas, comme on le verra dans le chapitre sur les CPU 8bits. Mais d'autres processeurs utilisent des valeurs différentes, avec par exemple des adresses de 16 bits pour la RAM, mais de 20 bits pour la ROM, ou inversement.
Sur une architecture Von Neumann, tout dépend de comment les adresses sont réparties. La solution la plus simple découpe l'espace d'adressage en deux parties égales, avec la RAM qui est dans la moitié basse (qui part de l'adresse 0 jusqu'à l'adresse au milieu), alors que la ROM est dans la moitié haute (entre l'adresse du milieu et l'adresse maximale). Mais ce n'est pas la seule possibilité, la limite entre RAM et ROM peut être mise n'importe où. Prenons par exemple un processeur 32 bits, capable de gérer 4 milliards d'adresse. Il est parfaitement possible de réserver 128 mébioctets de poids fort à la mémoire ROM, et de laisser le reste à la mémoire RAM.
===Le décodage d'adresse sur les architectures Von Neumann===
Pour résumer, les architectures Harvard et Von Neumann se distinguent sur deux points :
* L'accès à la RAM et à la ROM se font par des bus séparés sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.
* Les adresses pour la mémoire ROM et la mémoire RAM sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
Les architectures Von Neumann utilisent donc un seul bus pour connecter la RAM et la ROM au processeur. Mais cela ne parait pas intuitif : comment deux composants peuvent se connecter aux mêmes fils ? Parce que c'est ce qu'implique le fait de partager un bus. Si je prends une mémoire RAM et une mémoire ROM, toutes deux de 8 bits, elles seront connectées à un bus mémoire de 8 bits. Intuitivement, on se dit qu'il y aura des conflits, du genre : la RAM et la ROM vont accéder au bus en même temps, comment savoir si une adresse est destinée à la RAM ou la ROM, etc ?
Tous ces problèmes sont résolus avec une solution très simple : à chaque instant, seule une mémoire est connectée au bus. L'idée est que les mémoires sont connectées ou déconnectées du bus selon les besoins. Si le processeur veut envoyer lire une donnée en mémoire RAM, il déconnecte la mémoire ROM du bus. Et inversement, s'il veut lire une instruction, il déconnecte la RAM et connecte la ROM.
Pour cela, les mémoires RAM et ROM possèdent une entrée ''Chip Select'' ou ''Output Enable'', qui agit comme une sorte de bouton ON/OFF. Lorsqu'on met un 1 sur cette entrée, la mémoire se connectera au bus. Ses entrées et sorties fonctionneront normalement, elle pourra recevoir des adresses, envoyer ou recevoir des données, tout sera normal. Par contre, si on met un 0 sur cette entrée, la mémoire se "désactive", ses entrée-sorties ne répondent plus aux sollicitations extérieures. Pire que ça : elles sont électriquement déconnectées.
Au total, tout cela demande de gérer deux bit ''Chip Select''/''Output Enable'' : un pour la RAM, un pour la ROM. Et ces deux bits sont configurés pour chaque accès mémoire, pour chaque lecture ou écriture. Pour cela, un circuit de '''décodage d'adresse''' prend en entrée l'adresse mémoire à lire/écrire, et active/désactive les mémoires RAM/ROM selon les besoins. Il prend l'adresse et configure les bits ''Chip Select''/''Output Enable''.
[[File:Décodage d'adresse sur une architecture Von Neumann.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann.]]
L'implémentation la plus simple réserve la moitié des adresses pour la RAM, l'autre moitié pour la ROM. Typiquement, la ROM prend la moitié basse, la RAM la moitié haute. Dans ce cas, activer/désactiver la RAM et la ROM se fait avec seulement le bit de poids fort de l'adresse. Si le bit de poids fort est à 1, alors on accède à la RAM et la ROM doit être désactivée. Mais si ce bit est à 0, alors on accède à la moitié basse et il faut désactiver la RAM.
Une remarque intéressante : le fait de séparer la mémoire en deux parts égales permet de simuler une architecture Harvard à partir d'une architecture Von Neumann. Par exemple, le tout premier processeur d'Intel, le 4004, était l'un de ceux là. La RAM et la ROM sont reliés au même bus, et il y a donc un unique espace d'adressage, qui est séparé en deux parties égales. Le truc est que le processeur traite les deux parties égales comme deux espaces d'adressage séparés. Le processeur se débrouille pour cacher le fait qu'il y a un espace d'adressage unique coupé en deux, ce qui fait que les programmeurs voient bien deux espaces d'adressages distincts.
[[File:Décodage d'adresse sur une architecture Von Neumann basique.png|centre|vignette|upright=2|Décodage d'adresse sur une architecture Von Neumann basique.]]
Pour résumer, quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre et se connecter au bus. Le décodage d'adresse garantit que seule la mémoire adéquate réponde à un accès mémoire. Le décodage d'adresse est réalisé par la carte mère, par un composant dédié.
Le mécanisme peut être utilisé pour combiner plusieurs RAM en une seule, idem avec les ROM. Pour comprendre l'idée, je vais prendre l'exemple de l'IBM PC, un des tout premier PC existant. Nous étudierons ce PC dans une section dédiée, à la fin du chapitre, aussi je vais passer rapidement dessus. Tout ce que je vais faire est vous présenter la carte mère du PC, et vous demander de faire est de compter les mémoires ROM et mémoires RAM sur la carte mère :
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
Si vous remarquerez qu'il y a 5 mémoires ROM et 8 à 32 mémoires RAM. Le fait est que le processeur voit les différentes mémoires ROM comme une seule mémoire ROM. Idem avec les mémoires RAM : elle font chacune 2 kibioctets, et l'ensemble est vu par le processeur comme une seule RAM de 16 à 64 kibioctets. Et cela grâce aux circuits de décodage d'adresse, qui sont situés en haut à droite de la carte mère.
Pour comprendre l'idée, prenons l'exemple d'un processeur 16 bits, capable de gérer 64 kibioctets de mémoire. L'espace d'adressage est découpé en quatre portions, de 16 kibioctets chacune. Une portion est réservée à une ROM de 16 kibioctet, les autres sont chacune réservée à une RAM de 16 kibioctet. Le décodage d'adresse sélectionne alors la mémoire adéquate en utilisant les deux bits de poids fort de l'adresse.
* S'ils valent 00, alors c'est la mémoire ROM qui est activée, connectée au bus.
* S'ils valent 01, alors c'est la première mémoire RAM qui est connectée au bus.
* S'ils valent 10, alors c'est la seconde mémoire RAM qui est connectée au bus.
* S'ils valent 11, alors c'est la troisième mémoire RAM qui est connectée au bus.
[[File:Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM.png|centre|vignette|upright=3|Décodage d'adresse sur une architecture Von Neumann, utilisant plusieurs RAM et une ROM]]
===L'impact sur la conception du processeur===
Plus haut, j'ai parlé d'un des avantages des architectures Harvard : elles peuvent lire une instruction en même temps qu'elles accèdent à une donnée. La donnée est lue/écrite en RAM, alors que l'instruction est lue en ROM. Et cela permet de simplifier l'intérieur du processeur. Pas de beaucoup, mais c'est déjà ça de pris. Voyons maintenant comment cela impacte l'intérieur du processeur. Tout ce dont vous avez à vous rappeler est la séparation entre chemin de données et unité de contrôle, et que les registres généraux sont dans le premier, le ''program counter'' dans la seconde.
Avec une architecture Harvard, les instructions et les données passent par des bus différent : bus ROM pour les instructions, bus RAM pour les données. L'intuition nous dit que le bus pour la mémoire ROM est connecté à l'unité de contrôle, alors que le bus pour la RAM est connecté au chemin de données. Et dans les grandes lignes, c'est vrai. La logique est imparable pour ce qui est des bus de données. Mais il y a une petite subtilité pour les bus d'adresse.
Pour comprendre comment le processeur exploite ces deux bus, voyons ce qui transite dessus. Pour la mémoire ROM, elle reçoit l'adresse de l'instruction à lire, elle renvoie l'instruction adéquate. Pour cela, le ''program counter'' est envoyé sur le bus d'adresse, l'instruction sur le bus de données. Pour la mémoire RAM, elle échange des données avec les registres généraux, les registres pour les données. Les adresses utilisées pour la RAM viennent elles soit du chemin de données, soit de l'unité de contrôle, tout dépend du mode d'adressage. Mais le ''program counter'' n'est pas impliqué.
[[File:Architecture Harvard - échanges de données.png|centre|vignette|upright=2|Architecture Harvard - échanges de données]]
Les architectures Harvard modifiées doivent cependant rajouter une connexion entre le bus ROM et les registres généraux. C'est nécessaire pour charger une donnée constante depuis la mémoire ROM. Rappelons que la donnée constante est copiée dans un registre général, donc dans le chemin de données.
[[File:Architecture Harvard modifiée - implémentation du processeur.png|centre|vignette|upright=2|Architecture Harvard modifiée - implémentation du processeur]]
Avec les architectures Von Neumann, il y a un seul bus qui est relié à la fois au chemin de données et à l'unité de contrôle. Si le processeur lit une instruction, le bus doit être relié à l'unité de contrôle. Par contre, s'il accède à une donnée, il doit être relié au chemin de données (le bus d'adresse peut éventuellement être connecté au séquenceur, si celui-ci fournit l'adresse à lire). Il faut donc utiliser un paquet de multiplexeurs et de démultiplexeurs pour faire la connexion au bon endroit.
[[File:Architecture Von Neumann - implémentation du processeur.png|centre|vignette|upright=2|Architecture Von Neumann - implémentation du processeur]]
Une instruction se fait en deux temps : on charge l'instruction depuis la mémoire ROM, puis on l'exécute. Avec une architecture Harvard, tout cela se fait en un seul cycle d'horloge, vu que charger la ROM et accéder aux données peut se faire en même temps. Pas avec les architectures Von Neumann, qui doivent libérer le bus mémoire après avoir chargé une instruction. Elles n'ont pas le choix : elles chargent l'instruction lors d'un premier cycle d'horloge, puis l'exécutent lors du second.
Pour cela, ils incorporent un registre appelé le '''registre d'instruction''', qui mémorise l'instruction chargée. L'instruction est copiée dans ce registre lors du premier cycle, puis est utilisée lors du second cycle. Le registre permet de ne pas oublier l’instruction entre les deux cycles. Le registre d'instruction est obligatoire sur les architectures Von Neumann. En comparaison, il est facultatif sur les architectures Harvard. Elles peuvent en avoir un, pour des raisons techniques, mais ce n'est pas obligatoire.
[[File:Registre d'instruction.png|centre|vignette|upright=2|Registre d'instruction.]]
===Les architectures Von Neumann sont plus flexibles===
Sur les architectures Harvard, 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.
Par contre, sur les architectures Von Neumann, 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 copié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. Mais cet exemple implique un disque dur, ce qui rend les choses plus compliquées que prévu. Un autre exemple serait la compilation de code à la volée, mais il ne sera pas très parlant.
Un exemple plus adapté serait celui où la ROM mémorise un programme compressée dans la mémoire ROM, qui est décompressé pour être exécuté en mémoire RAM. Le programme de décompression est 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).
Il est aussi possible de créer des programmes qui modifient leurs propres instructions : cela s'appelle du '''code auto-modifiant'''. Ce genre de choses servait autrefois sur des ordinateurs rudimentaires, au tout début de l'informatique. A l'époque, 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 corriger les adresses au besoin avec du code auto-modifiant. De nos jours, le code automodifiant est utilisée occasionnellement pour rendre un programme indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés).
L'impossibilité de séparer données et instructions est à 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 des pirates informatiques arrivent à exploiter des bugs. Il arrive que des pirates informatiques vous fournissent des données corrompues, qui contiennent un virus ou un programme malveillant est caché dans les données. Les bugs en question permettent d'exécuter ces données, donc virus. Pour éviter cela, le système d'exploitation 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. Mais ce n'est pas parfait.
Toujours est-il que tout cela est impossible sur les architectures Harvard. Et ce serait très limitant. Imaginez : pas possible de lancer un programme depuis le disque dur ou une clé USB, le programme doit impérativement être dans une mémoire ROM, pas de compilation à la volée, etc. Que des techniques très utilisées dans l'informatique moderne. Malgré ses défauts, les architectures Von Neumann ne sont pas les plus utilisées pour rien. Les architectures Harvard sont concrètement utilisées uniquement dans l'informatique embarquée, sur des microcontrôleurs très spécifiques.
==Le bus de communication avec les entrées-sorties==
Le processeur, la mémoire et les entrées-sorties sont connectées 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. Pour 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''', sur lequel s'échangent les données entre les composants.
* Le '''bus de commande''' pour configurer la mémoire et les entrées-sorties.
* Le '''bus d'adresse''', facultatif, permet de préciser quelle adresse mémoire il faut lire/écrire.
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. Précisons cependant que le bus de commande n'est pas exactement le même entre des mémoires RAM/ROM et des entrées-sorties.
[[File:Bus general schematic.svg|centre|vignette|upright=2|Contenu d'un bus, généralités.]]
===Le réseau d'interconnexion : généralités===
Reprenons où nous nous étions arrêté. Avant de voir les architectures Harvard et Von Neumann, nous avions dit que le processeur, les mémoires et les entrées-sorties sont reliées entre eux par un réseau d'interconnexion. Nous venons de voir qu'il est possible de mutualiser certains bus, notamment celui de la mémoire RAM et celui de la mémoire ROM. Mais il est possible de faire la même chose pour les entrées-sorties. Là encore, il est possible de regrouper le bus mémoire avec les bus pour les entrées-sorties. Voyons ce que cela implique.
{|
|[[File:Réseau d'interconnexion avec un processeur au centre.png|centre|vignette|upright=2|Réseau d'interconnexion avec une architecture Harvard.]]
|[[File:Réseau d'interconnexion avec un processeur au centre et une architecture Harvard.png|centre|vignette|upright=2|Interconnexions d'une architecture Von Neumann.]]
|}
Avant de poursuivre, nous devons préciser quelque chose d'important. Sur les ordinateurs modernes, les entrées-sorties peuvent accéder à la mémoire RAM. Les ordinateurs modernes intègrent des techniques de '''''Direct Memory Access''''' (DMA) qui permettent aux entrées-sorties de lire ou d'écrire en mémoire RAM. Les transferts DMA se font sans intervention du processeur. Ils permettent de copier un bloc de plusieurs octets, dans deux sens : de la mémoire RAM vers une entrée-sortie, ou inversement. Le DMA demande d'ajouter un circuit dédié sur la carte mère : le contrôleur DMA. Il effectue la copie d'un paquet d'octets de la RAM vers l'entrée-sortie ou dans l'autre sens.
[[File:Réseau d'interconnexion avec un processeur au centre, et direct memory access.png|centre|vignette|upright=2|Réseau d'interconnexion avec un processeur au centre, et direct memory access]]
===Les bus systèmes===
La première solution utilise un bus unique, celui-ci est appelé le '''bus système''', aussi appelé ''backplane bus''. Le bus système est connecté à la mémoire RAM, la mémoire ROM, au processeur, et aux entrées-sorties. Tous les composants présents dans l'ordinateur sont connectés à ce bus, sans exception. De tels bus avaient pour avantage la simplicité. Le processeur n'est connecté qu'à un seul bus, ce qui utilise peu de broches et économise des fils. La mutualisation des bus est totale, le câblage est plus simple, la fabrication aussi.
[[File:Architecture minimale d'un ordinateur.png|centre|vignette|upright=2|Architecture minimale d'un ordinateur.]]
Un bus système contient un bus d'adresse, de données et de commande. Un bus système se marie bien avec des entrées-sorties mappées en mémoire. La conséquence est que 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. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.
[[File:Architecture Von Neumann avec les bus.png|centre|vignette|upright=2|Architecture Von Neumann avec les bus.]]
Un bus système n'a pas de limitations quant aux échanges de données. Le processeur peut communiquer directement avec les mémoires et les entrées-sorties, les entrées-sorties peuvent communiquer avec la mémoire RAM, etc. Notamment, un bus système peut implémenter le ''Direct Memory Access''. Il suffit juste de connecter un contrôleur DMA sur le bus système. Le contrôleur DMA est considéré comme une entrée-sortie, ses registres sont mappés en mémoire et sont donc accessibles directement par le processeur.
[[File:Bus système avec controleur DMA.png|centre|vignette|upright=2|Bus système avec contrôleur DMA.]]
Si on suit la définition à la lettre, un bus système est systématiquement une architecture Von Neumann, vu que la mémoire ROM et la mémoire RAM sont reliées sur le bus système. La conséquence est que les circuits de décodage d'adresse sont présents. Ils sont toujours sur la carte mère, et sont plus ou moins à côté du bus système. Cependant, le décodage d'adresse est parfois étendu pour tenir compte des entrées-sorties.
Les entrées-sorties soudées sur la carte mère ont elles aussi des entrées ''Chip Select'' ou quelque chose de similaire. Le décodage d'adresse peut alors les activer ou les désactiver suivant l'adresse envoyée sur le bus d'adresse. C'est ce qui arrive quand le processeur écrit dans un registre d’interfaçage : il envoie l'adresse de ce registre sur le bus d'adresse, le circuit de décodage d'adresse active seulement l'entrée-sortie associée.
Il faut noter que ce n'est pas systématique, il existe des techniques pour se passer de décodage d'adresse. Mais nous en reparlerons dans le chapitre sur les bus de communication.
[[File:Chipselectfr.png|centre|vignette|upright=1.5|Exemple détaillé.]]
Les bus systèmes sont certes très simples, mais ils ont aussi des désavantages. Par exemple, il faut éviter que le processeur et les entrées-sorties se marchent sur les pieds, ils ne peuvent pas 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.
Elle était 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.
===Les bus d'entrées-sorties===
Les bus systèmes ont de nombreux problèmes, ce qui fait que d'anciens ordinateurs faisaient autrement. A la place d'un bus système unique, ils utilisent un bus séparé pour les mémoires, 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 est appelé le '''bus d'entrées-sorties'''. Le bus mémoire est généralement relié à la fois à la mémoire RAM et à la mémoire ROM, les exceptions ne sont pas rares, cependant.
[[File:Bus mémoire séparé du bus pour les IO.png|centre|vignette|upright=2|Bus mémoire séparé du bus pour les IO]]
Les bus d'entrée-sorties peuvent être spécialisés et simplifiés. Par exemple, ils peuvent avoir un bus de commande différent de celui de la mémoire, qui utilise nettement moins de fils. Le bus d'adresse peut aussi être réduit, et utiliser des adresses plus courtes que celles du bus mémoire. Les bus de données peuvent aussi être de taille différentes. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 64 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! En général, les bus d'entrée-sortie sont assez petits, ils ont une taille de 8 ou 16 bits, même si le bus mémoire est plus grand. Cela permet de ne pas gaspiller trop de broches. Ajouter un bus d'entrée-sortie n'est donc pas très gourmand en broches et en fils.
: Il est en théorie possible d'avoir une fréquence différente pour les deux bus, avec un bus mémoire ultra-rapide et un bus pour les entrées-sorties est un bus moins rapide. Mais il faut que le processeur soit prévu pour, et c'est très rare.
Niveau performances, le processeur peut théoriquement accéder à la mémoire en attendant qu'une entrée/sortie réponde, mais il faut que le processeur soit prévu pour, et ce n'est pas de la tarte. Par contre, cela implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. En clair : pas d'entrée-sortie mappée en mémoire ! 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. En clair : pas de ''Direct Memory Access'' ! Les deux sont des défauts rédhibitoires pour les programmeurs système, notamment pour ceux qui codent les pilotes de périphériques.
Pour résumer, les défauts sont assez problématiques : pas d'entrées-sorties mappées en mémoire, pas de ''Direct Memory Access'', économie de broches limitée. Les deux premiers sont des défauts majeurs, qui font que de tels bus ne sont pas utilisés dans les ordinateurs modernes. A la place, ils utilisent une troisième solution, distincte des bus systèmes et des bus d'entrée-sorties.
===Les bus avec répartiteur===
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.
[[File:IO mappées en mémoire avec séparation des bus.png|centre|vignette|upright=2|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.
L'usage d'un répartiteur ne pose pas de problèmes particuliers pour implémenter le DMA. La seule contrainte est que le contrôleur DMA soit intégré dans le répartiteur. Les échanges entre IO et mémoire passent par le répartiteur, qui fait le pont entre bus mémoire et bus des IO.
[[File:Implémentation du DMA avec un répartiteur.png|centre|vignette|upright=2|Implémentation du DMA avec un répartiteur]]
==Les microcontrôleurs et ''system on chip''==
Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul circuit intégré, un seul boitier. L'ensemble forme alors ce qu'on appelle un '''''System on Chip''''' (système sur une puce), abrévié en SoC. Le nom est assez explicite : un SoC comprend un système informatique complet sur une seule puce de silicium, microprocesseurs, mémoires et périphériques inclus. Ils incorporent aussi des ''timers'', des compteurs, et autres circuits très utiles.
[[File:ARMSoCBlockDiagram.svg|centre|vignette|upright=2|SoC basé sur un processeur ARM, avec des entrées-sorties typiques de celles d'un µ-contrôleur. Le support du bus CAN, d'Ethernet, du bus SPI, d'un circuit de PWM (génération de signaux spécifiques), de convertisseurs analogique-digital et inverse, sont typiques des µ-contrôleurs.]]
Le terme SoC regroupe des circuits imprimés assez variés, aux usages foncièrement différents et à la conception distincte. Les plus simples d’entre eux sont des microcontrôleurs, qui sont utilisés pour des applications à base performance. Les plus complexes sont utilisés pour des applications qui demandent plus de puissance, nous les appellerons SoC haute performance.
La relation entre SoC et microcontrôleurs est assez compliquée à expliquer, la terminologie n'est pas clairement établie. Il existe quelques cours/livres qui séparent les deux, d'autres qui pensent que les deux sont très liés. Dans ce cours, nous allons partir du principe que tous les systèmes qui regroupent processeur, mémoire et quelques périphériques/entrées-sorties sont des SoC. Les microcontrôleurs sont donc un cas particulier de SoC, en suivant cette définition.
===Les microcontrôleurs===
Les '''microcontrôleurs''' sont des composants utilisés dans l'embarqué ou d'informatique industrielle. Leur nom trahit leur rôle. Ils sont utilisés pour contrôler de l'électroménager, des chaines de fabrication dans une usine, des applications robotiques, les alarmes domestiques, les voitures. De manière générale, on les trouve dans tous les systèmes dits embarqués et/ou temps réel. Ils ont besoin de s'interconnecter à un grand nombre de composants et intègrent pour cela un grand nombre d'entrée-sorties. Les microcontrôleurs sont généralement peu puissants, et doivent consommer peu d'énergie/électricité.
[[File:Microcontroller 8051.gif|centre|vignette|upright=2.5|Microcontrôleur Intel 8051.]]
Un microcontrôleur tend à intégrer des entrées-sorties assez spécifiques, qu'on ne retrouve pas dans les SoC destinés au grand public. Un microcontrôleur est typiquement relié à un paquet de senseurs et son rôle est de commander des moteurs ou d'autres composants. Et les entrées-sorties intégrées sont adaptées à cette tâche. Par exemple, ils tendent à intégrer de nombreux convertisseurs numériques-analogiques pour gérer des senseurs. Ils intègrent aussi des circuits de génération de signaux PWM spécialisés pour commander des moteurs, le processeur peut gérer des calculs trigonométriques (utiles pour commander la rotation d'un moteur), etc.
Fait amusant, on en trouve dans certains périphériques informatiques. Par exemple, les anciens disques durs intégraient un microcontrôleur qui contrôlait plusieurs moteurs/ Les moteurs pour faire tourner les plateaux magnétiques et les moteurs pour déplacer les têtes de lecture/écriture étaient commandés par ce microcontrôleur. Comme autre exemple, les claviers d'ordinateurs intègrent un microcontrôleur connecté aux touches, qui détecte quand les touches sont appuyées et qui communique avec l'ordinateur. Nous détaillerons ces deux exemples dans les chapitres dédiés aux périphériques et aux disques durs, tout deviendra plus clair à ce moment là. La majorité des périphériques ou des composants internes à un ordinateur contiennent des microcontrôleurs.
===Les SoC haute performance===
Les SoC les plus performants sont actuellement utilisés dans les téléphones mobiles, tablettes, ''Netbook'', ''smartphones'', ou tout appareil informatique grand public qui ne doit pas prendre beaucoup de place. La petite taille de ces appareils fait qu'ils gagnent à regrouper toute leur électronique dans un circuit imprimé unique. Mais les contraintes font qu'ils doivent être assez puissants. Ils incorporent des processeurs assez puissants, surtout ceux des ''smartphones''. C'est absolument nécessaire pour faire tourner le système d'exploitation du téléphone et les applications installées dessus.
Niveau entrées-sorties, ils incorporent souvent des interfaces WIFI et cellulaires (4G/5G), des ports USB, des ports audio, et même des cartes graphiques pour les plus puissants d'entre eux. Les SoC incorporent des cartes graphiques pour gérer tout ce qui a trait à l'écran LCD/OLED, mais aussi pour gérer la caméra, voire le visionnage de vidéo (avec des décodeurs/encodeurs matériel). Par exemple, les SoC Tegra de NVIDIA incorporent une carte graphique, avec des interfaces HDMI et VGA, avec des décodeurs vidéo matériel H.264 & VC-1 gérant le 720p. Pour résumer, les périphériques sont adaptés à leur utilisation et sont donc foncièrement différents de ceux des microcontrôleurs.
[[File:Phone hardware.png|centre|vignette|upright=2|Hardware d'un téléphone. On voit qu'il est centré autour d'un SoC, complété par de la RAM, un disque dur de faible capacité, de quoi gérer les entrées utilisateurs (l'écran tactile, les boutons), et un modem pour les émissions téléphoniques/2G/3G/4G/5G.]]
Un point important est que les processeurs d'un SoC haute performance sont... performants. Ils sont le plus souvent des processeurs de marque ARM, qui sont différents de ceux utilisés dans les PC fixe/portables grand public qui sont eux de type x86. Nous verrons dans quelques chapitres en quoi consistent ces différences, quand nous parlerons des jeux d'instruction du processeur. Autrefois réservé au monde des PCs, les processeurs multicœurs deviennent de plus en plus fréquents pour les SoC de haute performance. Il n'est pas rare qu'un SoC incorpore plusieurs cœurs. Il arrive même qu'ils soient foncièrement différents, avec plusieurs cœurs d'architecture différente.
La frontière entre SoC haute performance et microcontrôleur est de plus en plus floue. De nombreux appareils du quotidien intègrent des SoC haute performance, d'autres des microcontrôleurs. Par exemple, les lecteurs CD/DVD/BR et certains trackers GPS intègrent un SoC ou des processeurs dont la performance est assez pêchue. À l'opposé, les systèmes domotiques intègrent souvent des microcontrôleurs simples. Malgré tout, les deux cas d'utilisation font que le SoC/microcontrôleur est connecté à un grand nombre d'entrées-sorties très divers, comme des capteurs, des écrans, des LEDs, etc.
[[File:GPS tracker Hardware Architecture.png|centre|vignette|upright=2|Hardware d'un tracker GPS.]]
==Étude de quelques exemples d'architectures==
Après avoir vu la théorie, nous allons voir des exemples réels d'ordinateurs. Dans ce qui suit, nous allons voir des ordinateurs assez anciens, pour une raison simple : ils collent assez bien à l''''architecture de base''' vue plus haut, avec un CPU, une RAM et une ROM, quelques entrées-sorties. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent une architecture grandement modifiée et améliorée, avec un grand nombre de périphériques, disques durs/SSD, un grand nombre de mémoires différentes, etc.
Il pourrait sembler pertinent d’étudier des microcontrôleurs ou des ''System On Chip'', en premier lieu. Mais nous éviterons soigneusement de tels systèmes pour le moment. La raison est qu'ils ont un grand nombre d'entrées-sorties, qui sont peu familières. Attendez-vous à avoir près d'une vingtaine ou centaine d'entrée-sorties différentes pour de tels systèmes. Le tout est très complexe, bien trop pour un premier exemple. A la place, nous allons voir précisément des exemples plus simples : les premiers PC, et des consoles de jeu 8 et 16 bits.
Bien que ce soit des systèmes très simples, ils sont cependant plus complexes que l'architecture de base. Et leur avantages/désavantages sont un peu inverse l'un de l'autre. Si on devait résumer les différences, on aurait ceci :
* Les PC ont plus d'entrées-sorties que les consoles, bien que nettement moins que pour les microcontrôleurs/SoC.
* Les PC utilisent des disques durs, les consoles font avec soit des cartouches de jeu, soit des CD/DVD.
* Les PC utilisent des cartes électroniques séparées pour le son et l'écran, les consoles utilisent des circuits soudés sur la carte mère, qui sont souvent des co-processeurs.
* Les PC ont une mémoire ROM soudées sur la carte mère, les consoles 8 bits font sans.
Les PC et micro-ordinateurs ont plus d'entrées-sorties que les consoles. Même si on mets de côté les périphériques, ils ont aussi beaucoup de composants soudées sur la carte mère. En comparaison, les consoles de jeu 8/16 bits se débrouillent avec : une cartouche de jeu et une manette en entrée, une sortie vidéo et une sortie son.
Un autre point important est l'absence de disque dur ou de lecteur CD. La présence d'un disque dur ou d'un lecteur CD/DVD complexifie tout de suite l'architecture des PC. Il faut leur réserver un bus dédié ou les connecter à un bus système, cela demande d'ajouter des circuits sur la carte mère, etc. Et surtout, il faut expliquer comment l'ordinateur exécute des programmes, ce qui demande de parler de l'interaction avec le disque dur et la ROM du BIOS. Rien de tout cela sur les consoles de jeu 8 et 16 bits. Elles utilisent à la place des cartouches de jeu, qui intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Pas besoin de parler des mémoires de stockage, on est beaucoup plus proche de l'architecture de base avec une ROM unique.
Par contre, n'allez pas croire que tout est rose avec les consoles 8/16 bits. Il y a quelques différences qui font qu'elles sont plus complexes qu'un PC sur certains points.
Les PC utilisent des cartes électroniques à brancher sur la carte mère pour alimenter l'écran et les hauts-parleurs/casques, alors que les consoles de jeu utilisent des souvent co-processeurs dédiés pour le son et les graphismes. La différence parait mineure, mais elle avantage les consoles. Nous avons déjà expliqué ce que sont les co-processeurs plus haut, aussi les co-processeurs des consoles nous paraitrons familiers. On n'a pas à s’embêter à expliquer ce que sont les cartes d'extension, les bus associés et tout ce qui va avec, cela peut être retardé pour la section sur l'architecture des PC.
La gestion de la cartouche de jeu est aussi un peu subtile à comprendre, bien que ce soit bien plus simple à comprendre qu'un système avec un disque dur. Les cartouches de jeu intègrent une mémoire ROM, pour mémoriser les données du jeu, voire son code. Et le processeur doit exécuter le code depuis cette mémoire ROM. La conséquence est que les consoles 8/16 bits utilisent une architecture Harvard, avec un bus relié à la cartouche pour lire les instructions. Mais si ce n'était que ça... Les cartouches mémorisent aussi les données pour les graphismes, ce qui fait que le co-processeur vidéo doit lui aussi lire la cartouche pour récupérer ces données...
===L'architecture de la TurboGraphX-16===
La console PC Engine, aussi appelée TurboGraphX, est une ancienne console 8 bits. Elle contient un processeur 65C02, 8 kibioctets de RAM, un port manettes, 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 est en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs, ce sont des circuits électroniques dits fixes. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.
Bien que la carte graphique ne soit pas un processeur, elle a 64 kibioctets de RAM rien que pour elle. La RAM en question est séparée de la RAM normale, c'est un circuit intégré séparé. Et c'est un cas très fréquent, qui reviendra par la suite. La majeure partie des cartes graphiques dispose de leur propre '''mémoire vidéo''', totalement réservée à la carte graphique. La RAM vidéo est connectée à la carte graphique via un bus séparé. Le processeur est souvent connecté à ce bus, afin de pouvoir écrire des données dedans, mais ce n'est pas le cas ici.
[[File:Architecture de la PC Engine, aussi appelée TurboGrafx-16.png|centre|vignette|upright=2.5|Architecture de la PC Engine, aussi appelée TurboGrafx-16]]
L'architecture de la console était particulièrement simple. Le processeur était le centre de l'architecture, tout était connecté dessus. Il y a un bus pour la cartouche de jeu, un autre pour la RAM, un autre pour les manettes, un autre pour carte son, et un dernier pour la carte graphique. Le fait d'avoir un bus par composant est assez rare et ce n'est le cas ici que parce des conditions particulières sont remplies. Déjà, il y a peu d'entrée-sorties. Ensuite, les bus font tous 8 bits, vu que le processeur est un CPU 8 bits. Avec 5 connexions de 8 bits, le tout utilise 40 broches, ce qui est beaucoup, mais totalement gérable. Par contre, les choses changerons pour les autres consoles.
Au final, l'organisation des bus peut s'expliquer avec ce qu'on a vu dans la section sur les bus de communication. La console utilise une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, il y a des bus dédiés aux entrées-sorties, séparés des bus mémoire. Enfin, la carte graphique a droit à ses propres bus pour lire dans la cartouche et dans sa RAM vidéo dédiée.
===L'architecture de la console de jeu NES===
Maintenant, nous allons voir la console de Jeu Famicom, aussi appelée la NES en occident. Elle a une architecture centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Le processeur est associé à 2 KB de mémoire RAM.
Sur certaines cartouches, on trouve une RAM utilisée pour les sauvegardes, qui est adressée par le processeur directement. Première variation par rapport à l'architecture de la console précédente : l'ajout de la RAM pour les sauvegardes dans les cartouches.
Niveau carte graphique, une différence importante est que la carte graphique est connectée à la cartouche de jeu via un autre bus, afin de pouvoir lire les sprites et textures du jeu dans la cartouche.
[[File:Architecture de la NES.png|centre|vignette|upright=2.5|Architecture de la NES]]
La différence avec l'architecture précédente est que des bus ont été fusionnés. Comme dit plus haut, le système utilise une architecture Harvard, vu que la ROM est dans la cartouche, alors que la RAM est soudée à la carte mère. Par contre, la Famicon utilise un bus dédié aux entrées-sorties. Il est utilisé pour la carte son et la carte graphique, seules les manettes sont sur un bus à part. Ce qui fait qu'on devrait plutôt parler de bus de sorties, mais passons... L'essentiel est qu'on n'est plus tout à fait dans le cas de la console précédente, avec un bus par composant.
===L'architecture de la SNES===
L'architecture de la SNES est illustrée ci-dessous. Les changements pour le processeur et la RAM sont mineurs.La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. Par contre, on remarque un changement complet au niveau des bus, de la carte graphique et de la carte son.
[[File:Architecture de la SNES.png|centre|vignette|upright=2|Architecture de la SNES]]
La console utilise un '''bus système unique''', 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 transition vers un bus système s'explique par le fait que la console est maintenant de 16 bits, ce qui fait que les bus doivent être plus larges. Le processeur adresse des mémoires RAM et ROM plus grandes, ce qui double la taille de leurs bus. De plus, les entrées-sorties aussi ont besoin d'un bus plus large. Le processeur n'ayant pas un nombre illimité de broches, la seule solution est de fusionner les bus en un seul bus système.
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.
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.
===L'architecture de la Megadrive et de la néo-géo===
Passons maintenant la console de jeu Megadrive, une console 16 bits. Elle a une architecture similaire à celle de la néo-géo, une autre console bien plus puissante, sorti à peu près en même temps. Elle intègre deux processeurs : un CPU Motorola 68000, et un co-processeur audio Z80. Le Z80 et le Motorola 68000 étaient deux processeurs très populaires à l'époque. Le Z80 est une sorte de version améliorée de l'Intel 8088 utilisé sur les anciens PC et de nombreuses consoles utilisaient des Z80 comme processeur principal. Mais ici, il est utilisé comme co-processeur audio, sans doute car il était familier pour les programmeurs de l'époque, pour son cout réduit, sa bonne disponibilité, et bien d'autres avantages liés à sa production de masse.
Le Motorola 68000 était un processeur 16 bits, alors que le Z80 est un processeur 8 bits. Et cette différence fait que l'on ne peut pas connecter directement les deux sur le même bus, ou du moins pas facilement. La solution retenue est d'utiliser deux bus séparés : un bus de 16 bits connecté au 68000, un bus de 8 bits connecté au Z80. Le premier bus est un bus système sur lequel est connecté le 68000, 64 kibioctets de RAM, la cartouche de jeu, et la carte graphique. Le second bus est un bus de 8 bits, plus court, relié au Z80, à un synthétiseur sonore, et 8 kibioctets de RAM. Les deux bus sont connectés à un '''''chipset''''', un circuit répartiteur, qui fait le pont entre les deux bus. Les manettes sont connectées sur le ''chipset''.
[[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]]
Cet exemple nous montre que les bus systèmes sont certes très simples, mais aussi inflexibles. Ils fonctionnent bien quand les composants branchés dessus sont tous des composants 8 bits, ou sont tous de 16 bits, ou tous 32 bits. Mais dès qu'on mélange composants 8, 16, 32 ou 64 bits, les choses deviennent plus compliquées. Il est alors préférable d'utiliser des bus séparés, avec des répartiteurs pour faire le pont entre les différents bus. Et nous verrons que le problème s'est posé lui aussi sur les PC.
===L'architecture des anciennes consoles Playstation : beaucoup de co-processeurs===
Les consoles que nous venons d'aborder étaient des consoles 8 ou 16 bits. A partir des consoles 32 bits, leur architecture s'est rapprochée de celle des PC, avec un usage plus complexes de répartiteurs. La XBOX était très semblable à un PC : le processeur était un Pentium 3 modifié, la carte graphique était une Geforce 3 modifiée, les 64 mébioctets de RAM était la même mémoire DDR que celle des PC, le répartiteur secondaire était un ''chipset'' nForce de NVIDIA, etc. Mais les Playstation 1, 2 et 3 se distinguent de leur contemporains. Elles disposent de très nombreux co-processeurs, qui sont en plus très variés.
La Playstation 1 a été une des premières console à utiliser les CD-ROM comme support de stockage, en remplacement des cartouches. La conséquence est que la console contient une mémoire ROM, soudée à la carte mère, de 512 kibioctets. Elle contient aussi 2 mébioctets de RAM, une carte graphique avec 1 mébioctet de mémoire vidéo, un processeur, et de quoi gérer les périphériques. Il y a un co-processeur audio spécialisé, avec 512 kibioctets de RAM, ce qui nous est familier. Par contre, les autres co-processeurs ne le sont pas.
Déjà, le lecteur de CD-ROM est associé à des circuits sur la carte mère, il y a tout un sous-système dédié au lecteur de CD. Il y a un contrôleur qui sert d'interface avec le lecteur proprement dit, mais aussi deux co-processeurs audio et 32 kibioctets de RAM. Les co-processeurs audio servent à lire des CD sans trop utiliser le second co-processeur audio, ils lui servent de complément.
Ensuite, le processeur incorpore plusieurs cœurs, avec un cœur principal et plusieurs co-processeurs. Le premier est un co-processeur système, qui est utilisé pour gérer la mémoire cache intégrée au processeur, pour des fonctionnalités appelées interruptions et exceptions, ainsi que pour configurer le processeur. Le second est un co-processeur arithmétique spécialisé dans les calculs en virgule flottante, très importants pour le rendu 3D. Enfin, il y a un décodeur vidéo, qui n'est pas un co-processeur, mais un circuit non-programmable, spécialisé dans le décodage vidéo. De nos jours, ce circuit aurait été intégré dans la carte graphique, mais il était intégré dans le processeur sur la Playstation 2.
Pour le reste, le processeur est la figure centrale de la console. Il est connecté à 4 bus : un pour la RAM, un pour la carte graphique, un pour les manettes, un autre pour le reste. Le dernier bus est connecté au système audio et au système pour le lecteur CD. Ce serait un bus d'entrée-sortie, s'il n'était pas connecté à la mémoire ROM. Vous avez bien lu : la mémoire ROM est reliée au bus d'entrée-sortie.
[[File:Architecture de la Playstation.png|centre|vignette|upright=2.5|Architecture de la Playstation]]
La Playstation 2 est composé d'un processeur, couplé à 32 Mébioctets de RAM, et d'un paquet de co-processeurs. Plus de co-processeurs que la PS1. Le processeur principal n'est pas la même que celui de la PS1, mais il a une architecture similaire. Il intègre un décodeur vidéo sur le même circuit intégré, ainsi que deux co-processeur. Les co-processeurs ne sont cependant pas les mêmes.
Le co-processeur système disparait et est remplacé par un second co-processeur arithmétique. Les deux co-processeurs arithmétiques sont spécialisés dans les nombres flottants, avec quelques différences entre les deux. Par exemple, le second co-processeur gérait des calculs trigonométriques, des exponentielles, des logarithmes, et d'autres fonctions complexes du genre ; mais pas le premier co-processeur. Ils sont reliés à 4 kibioctets de RAM pour le premier, 16 kibioctets de RAM pour le second ; qui sont intégrées dans le processeur et non-représentés dans le diagramme ci-dessous.
La PS2 intègre aussi un co-processeur d'entrées-sorties. Pour information, il s'agit du processeur principal de la Playstation 1, qui est ici utilisé différemment, suivant que l'on place un jeu PS1 ou PS1 dans la console. Si on met un jeu PS1, il est utilisé pour émuler la Playstation 1, afin de faire tourner le jeu PS1 sur la PS2. Si on met un jeu PS2, il est utilisé comme co-processeur d'entrée-sortie et fait l'interface entre CPU et entrées-sorties. Il est relié à 2 mébioctets de RAM, soit exactement la même quantité de mémoire que la Playstation 1.
Tous les périphériques sont connectés au co-processeur d'entrées-sortie. Pour cela, le co-processeur d'entrées-sortie est relié à deux bus dédiés aux périphériques. Le premier bus est relié aux manettes, aux ports USB et aux ports pour cartes mémoires. Le second bus est relié à la carte son, la carte réseau, le lecteur DVD, et un port PCMIA. Notons que la carte son intègre un co-processeur audio, qui n'est pas représenté dans le diagramme ci-dessous.
[[File:Playstation 2 architecture.png|centre|vignette|upright=2.5|Playstation 2 architecture]]
==L'architecture des PC et son évolution==
Après avoir vu les consoles, nous allons maintenant voir les anciens PC, des années 80 ou 90. Le tout premier PC était techniquement l''''IBM PC'''. Par la suite, de nombreux ordinateurs ont tenté de reproduire l'IBM PC originel, avec parfois quelques modifications mineures. De tels ordinateurs ''IBM PC compatibles'', ont été très nombreux, pour des raisons diverses. Le fait d'utiliser des composants banalisés, facilement disponibles, ainsi qu'une bonne documentation de l'IBM PC originel, a grandement aidé. Les IBM PC compatibles ont progressivement évolué pour donner les PC actuels. L'IBM PC compatible a donné naissance à de nombreux standards divers.
===L'IBM PC originel et l'IBM PC XT===
[[File:IBM PC XT 02.jpg|vignette|IBM PC XT.]]
Nous allons commencer par voir l'IBM PC originel, et son successeur : l'IBM Personal Computer XT. Nous les appelerons tous deux l'IBM PC. L'IBM PC utilisait un processeur Intel 8088, qui était un processeur 8 bits. Ils utilisaient un bus système unique, appelé le '''bus XT'''. Le bus système allait à 4.77 MHz, soit la même fréquence que le processeur. C'était un bus de 8 bits, ce qui collait parfaitement avec les processeurs 8 bits commercialisés par Intel à l'époque.
L'IBM PC comprenait une mémoire ROM avec de quoi faire fonctionner le PC. La ROM en question contenait un programme minimal, appelé le '''BIOS''', sans lequel le PC ne fonctionnait pas du tout. Il servait de base pour le système d'exploitation et MS-DOS ne fonctionnait pas sans elle. De nos jours, son rôle est plus limité : sans elle, le PC ne démarre pas. Mais nous détaillerons cela dans le prochain chapitre.
En plus de la ROM pour le BIOS, l'IBM PC avait quatre mémoires ROM dédiée au langage de programmation BASIC. Lorsque le PC démarrait, il ne bootait pas un système d'exploitation, mais lançait l'interpréteur pour le langage BASIC. De nos jours, ce serait l'équivalent d'un ordinateur qui boote directement sur du Python, à savoir la console Python que vous avez peut-être déjà utilisé si vous avez testé Python. Ceux qui ont déjà touché à un ordinateur de l'époque savent ce que ca veut dire, mais c'est malheureusement très difficile à expliquer sans ce genre d'expérience. Toujours est-il que c'était une sorte de norme à l'époque
: les ordinateurs bootaient généralement sur un interpréteur BASIC.
[[File:XT Bus pins.svg|vignette|Connecteur du bus XT.]]
Les PC étaient conçus pour qu'on branche des '''cartes d'extension''', à savoir des cartes électroniques qu'on branchait sur la carte mère, à l'intérieur du PC. Les cartes d'extension de l'époque étaient surtout des cartes son ou des cartes graphiques, mais aussi des cartes pour brancher des péripéhriques. par exemple, on pouvait ajouter deux cartes graphiques dans l'IBM PC originel : l'''IBM Monochrome Display Adapter'' et/ou la ''IBM Color Graphics Adapter''. De nos jours, les cartes son sont intégrées à la carte mère, mais les cartes graphiques sont restées des cartes d'extension.
Les cartes d'extension étaient branchées sur un '''connecteur XT''', qui était directement relié au bus XT. Le connecteur XT est illustré ci-contre, mais ne vous en souciez pas trop pour le moment. La carte mère de l'IBM PC avait 5 connecteurs de ce type, qu'on pouvait peupler avec autant de cartes d'extension. L'IBM Personal Computer XT est passé à 8 connecteurs XT, soit trois de plus.
Pour ce qui est des périphériques, l'IBM PC avait plusieurs connecteurs : un port série, un port parallèle, un port pour le clavier, et un port pour un lecteur cassette. Le clavier et le lecteur cassette étaient connectés directement sur la carte mère, qui contenait quelques circuits pour gérer le clavier. Par contre, les deux premiers n'étaient pas connectés à la carte mère. Le port série était en réalité une carte d'extension, branchée sur un connecteur XT. Et il en est de même pour le port parallèle.
Pour ce qui est des supports de stockage, l'IBM PC originel n'avait pas de disque dur et n'avait que des lecteurs de disquette. De plus, le lecteur de disquette n'était pas connecté directement sur la carte mère, mais était connecté à une carte d'extension, branchée sur un connecteur XT. La carte d'extension avait deux connecteurs, un par lecteur de disquette, ce qui fait que les deux lecteurs de disquettes pouvaient être branchés sur une seule carte d'extension. L'IBM Personal Computer XT a ajouté un disque dur, sauf sur quelques sous-modèles spécifiques.
Le PC avait aussi un petit haut-parleur capable de faire des bips.
Pour résumer, l'IBM PC originel se reposait beaucoup sur les cartes d'extension, sa carte mère contenait peu de choses. Enfin, peu de choses... Il y avait un processeur Intel 8088, éventuellement un coprocesseur flottant 8087, de la RAM, de la ROM, et des circuits intégrés assez divers. En voici la liste, certains vous seront familiers, d'autres vous seront inconnus à ce stade du cours :
* les circuits de décodage d'adresse ;
* un contrôleur DMA intel 8273 ;
* un contrôleur d'interruption 8259 ;
* un contrôleur de bus Intel 8288 pour gérer le bus XT ;
* un générateur d'horloge Intel 8284 et un diviseur de fréquence ;
* un ''timer'' Intel 8253, le même que celui étudié dans le chapitre sur les ''timers'' ;
* un contrôleur parallèle 8255.
Les multiplexeurs, registres et portes logiques, sont des circuits de décodage d'adresse, qui permettent de combiner plusieurs RAM en une seule, idem avec la mémoire ROM. Si vous verrez qu'il y a 5 mémoires ROM : une ROM pour le BIOS, et quatre autres ROM pour le BASIC. Les 4 ROM du BASIC sont combinées en une seule mémoire ROM. Pour les RAM, il y en a 8 à 32, qui sont combinées en une seule RAM de 16 à 64 kibioctets.
[[File:IBM 5150 Motherboard.svg|centre|vignette|upright=3|Carte mère de l'IBM 5150, un modèle de l'IBM PC.]]
===L'architecture d'un IBM PC compatible 16 bits===
Les PC suivants sont passés à des processeurs 16 bits, mais c'était toujours des processeurs x86 d'Intel, à savoir des Intel 286 et 386. La RAM a grossi, quelques entrées-sorties ont été ajoutées, mais l'architecture globale est plus moins resté le même. C'est surtout au niveau du bus et des périphériques que les changements majeurs ont eu lieu.
[[File:ISA Bus pins.svg|vignette|Connecteur ISA.]]
Les PC 16 bits utilisaient un bus système unique, sur lequel tout était connecté : le processeur, la RAM, la ROM, les cartes d'extension et tout le reste. Le bus en question s'appelait le '''bus AT''', mais il a rapidement été renommé en '''bus ISA''' (''Industry Standard Architecture''). Le bus ISA était prévu pour avoir une compatibilité avec le bus 8 bits de l'IBM PC originel. D'ailleurs, cela se ressent jusque dans le connecteur utilisé : le connecteur ISA est un connecteur XT qu'on a fusionné avec un second connecteur pour l'étendre de 8 à 16 bits.
Les PC 16 bits avaient toujours un port série, un port parallèle, un clavier, un lecteur de disquette et des cartes d'extension. Des disques durs pouvaient être ajoutés, aussi. Mais pour ces périphériques, un changement majeur a eu lieu comparé à l'IBM PC originel. L'IBM PC originel utilisait des cartes d'extension pour tout, sauf le clavier. Mais maintenant, les périphériques ne sont plus connectés à une carte d'extension. A la place, les circuits de la carte d'extension sont déplacés sur la carte mère. Mais n'allez pas croire qu'ils étaient connectés directement au bus ISA, il y avait des intermédiaires.
Le clavier était relié à un '''contrôleur de clavier''', qui faisait l'interface entre le connecteur du clavier et le bus ISA. Le contrôleur de clavier était appelé le ''Keyboard Controler'', abrévié en KB. Il recevait ce qui est tapé au clavier et traduisait cela en quelque chose de compréhensible par l'ordinateur.
Les autres périphériques étaient connectés à un circuit intégré dédié : l''''Intel 82091AA'''. Il était connecté au lecteur de disquette, au port série et au port parallèle. Il servait d'intermédiaire entre ces périphériques et le bus ISA. Vous pouvez le voir comme une sorte de répartiteur, mais qui ne serait pas connecté sur le processeur et la RAM
Enfin, il ne faut pas oublier les autres composants présents sur l'IBM PC originel. Le BIOS est toujours là, de même que les ''timers'' Intel 8253 PIT, le contrôleur d'interruption Intel 8259 et le contrôleur DMA Intel 8237. Les PC 16 bits ont aussi intégré une ''Real Time Clock'' (RTC). Pour rappel, c'est un composant qui permet au PC de mémoriser la date et l'heure courante, à la seconde près. Le tout est résumé dans le schéma ci-dessous.
[[File:Architecture de l'IBM PC compatible.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible]]
Un point important est que le bus ISA allait à la même fréquence que le processeur, vu que c'était un bus système. Les processeurs de l'époque étaient des CPU 286 d'Intel, ou le 386 d'Intel. Les Intel 286 allaient de 4 MHz minimum, à 25 MHz maximum. Le 386, quant à lui, allait de 12 à 40 MHz. Le bus ISA devait aller à cette fréquence, il était synchrone avec le processeur.
Par la suite, les processeurs ont gagné en performance, ce qui fait que le bus ISA est devenu trop lent pour le processeur. Une idée a alors été de conserver le bus ISA, pour des raisons de compatibilité, mais de le reléguer comme bus secondaire. L'ordinateur contient alors deux bus : un bus système, et un bus ISA secondaire. Le lien entre les deux est réalisé par un '''pont ISA''', ''ISA Bridge'' en anglais. Le bus ISA fonctionnait alors sa fréquence usuelle, alors que le bus système était beaucoup plus rapide. Le bus système fonctionnait à une fréquence bien plus élevée, ce qui fait que le processeur pouvait communiquer à pleine vitesse, notamment avec la RAM. Le processeur n'était alors plus forcé à aller à la même fréquence que le bus ISA
[[File:Architecture de l'IBM PC compatible avec bridge ISA.png|centre|vignette|upright=2.5|Architecture de l'IBM PC compatible avec bridge ISA]]
Les PC de l'époque intégraient donc plusieurs bus séparés. Vous avez bien lu : plusieurs bus ! Ici, il s'agit de ce que j'appelle des '''bus en cascade''', à savoir qu'un bus est connecté à un autre bus par un intermédiaire. Au passage, si j'aborde ces exemples, car c'est pareil sur les ordinateurs modernes. Le pont ISA a été remplacé par des circuits différents, mais qui ont un rôle assez similaire. Le ''chipset'' de votre carte mère n'est qu'un lointain descendant du pont ISA, qui s'interface avec des bus différents.
===L'arrivée des standards AT et IDE pour les disques durs===
Initialement, les disques durs étaient placés dans l'ordinateur et étaient connectés sur le bus ISA, via une carte d'extension ISA. En clair, il fallait connecter le disque dur sur une carte d'extension, et non sur la carte mère. Les cartes d'extension en question permettaient de connecter un ou plusieurs disques durs, parfois des lecteurs de disquette supplémentaires. Les cartes ISA de ce type faisaient juste l'interface entre le bus ISA et les disques durs, rien de plus. L'interface en question a été standardisée, ce qui a donné le standard ''AT Bus Attachment'', qui a été abrévié en ATA.
Et ce n'était pas que pour les disques durs, de nombreux composants étaient dans ce cas. Une carte d'extension servait d'intermédiaire entre eux et la carte mère. Les cartes d'extension en question étaient appelées des ''Host bus adapter''.
[[File:Acculogic sIDE-4 Controller ISA.jpg|centre|vignette|upright=2|Carte ISA d'interface disque dur, de marque Acculogic.]]
Mais les choses ont rapidement évoluées, que ce soit du côté des cartes mères que du côté des disques durs. Le '''standard IDE''' a permis de brancher un disque dur directement sur la carte mère, sans passer par une carte d'interface ISA. Pour cela, la carte mère réservait un connecteur ISA pour le disque dur, renommé '''connecteur ATA'''. Pour que cela soit possible, il a fallu rajouter des circuits sur la carte mère. Tout ce qui était sur les cartes d'interface ISA s'est retrouvé sur la carte mère.
[[File:Ajout des ports IDE sur la carte mère.png|centre|vignette|upright=2|Ajout des ports IDE sur la carte mère]]
En réalité, les connecteurs ATA étaient des connecteurs ISA simplifiés. Un connecteur ISA avait en tout 98 broches, alors qu'un connecteur ATA n'en contient que 40. Les broches qui étaient inutiles pour les disques durs ont simplement été enlevées. Et qui dit connecteur spécialisé, dit câble spécialisé. Les disques durs étaient branchés sur le connecteur AT grâce à un câble ATA, sur lequel on pouvait connecter deux disques durs.
[[File:ATA Plug.svg|centre|vignette|upright=2|Connecteur ATA.]]
[[File:ATA cables.jpg|centre|vignette|upright=2|Cable ATA.]]
Il était donc possible de connecter deux disques durs sur un seul connecteur ATA. Et cette possibilité est devenue d'autant plus utile par la suite. A partir de la version 2, ATA supportait aussi les lecteurs de disquettes, les lecteurs de CD/DVD, et bien d'autres supports de stockage. Il était alors possible de connecter un lecteur CD et un disque dur sur un seul connecteur. Les cartes mères avaient généralement deux connecteurs ATA, et n'avaient pas besoin de plus. C'était suffisant pour connecter un disque dur, un lecteur de disquette et un lecteur CD, configuration courante entre les années 90 et 2000.
Un câble est donc connecté à deux supports de stockage. Pour distinguer les deux, le standard ATA ajoute une possibilité de configuration. Sur un câble, il doit y avoir un support de stockage "maitre" et un support "esclave". C'était la terminologie de l'époque, que je reproduis ici, même si elle est fortement trompeuse. N'allez pas croire que cela implique que l'un ait des avantages sur l'autre. Le support 'maitre" n'a pas droit à plus de bande passante, il n'a pas la priorité sur l'autre, rien du tout. Il s'agit juste d'un nombre qui permet de savoir avec qui le processeur communique, qui vaut 0 pour le premier support, 1 pour l'autre. Une sorte d'adresse de 1 bit, si l'on veut.
[[File:ATA-Konfiguration02.png|centre|vignette|upright=2|Configuration ATA.]]
Pour configurer un support de stockage en mode "maitre" ou "esclave", le support de stockage avait quelques pins dédiés. Il suffisait de placer un détrompeur en plastique sur les pins adéquats. Les pins se trouvaient à l'arrière du disque dur ou du lecteur de CD/DVD/Disquette/autre.
[[File:HDD Master and Slave Description.jpg|centre|vignette|upright=2|Configuration ''Master/Slave''.]]
===L'architecture d'un PC avec un processeur Intel 486===
Maintenant, passons aux ordinateurs 32 bits, avec l'exemple d'un PC avec un processeur 486 d'Intel. A cette époque, le bus ISA était devenu trop limité et était en place d'être remplacé par le bus PCI, qui avait la même fonction. De nombreuses cartes d'extension utilisaient déjà ce standard et étaient branchées sur des connecteurs PCI dédiés, différents des connecteurs ISA. Intuitivement, on se dit que le bus PCI remplaçait le bus ISA, mais les choses étaient plus compliquées. Les disques durs gardaient leur connecteur ATA, et ne passaient pas par le bus PCI. Ils avaient un bus IDE séparé, qui était un bus ISA modifié.
Là encore, les processeurs étaient devenus beaucoup plus rapides que le bus PCI. Les deux allaient à des fréquences assez différentes, ce qui fait que le bus PCI était séparé du bus système. Il y avait alors deux implémentations possibles.
* La première utilise un répartiteur unique, relié au processeur, à la RAM, au bus PCI, et au bus IDE.
* La seconde utilise un bus système séparé du bus PCI, avec un '''pont PCI''' pour faire l'interface entre les deux.
Le '''''System Controler''''' était un circuit intégré, placé sur la carte mère, qui peut servir soit de pont PCI, soit de répartiteur. Le répartiteur PCI sert d'intermédiaire avec le bus PCI, mais aussi avec le bus IDE, utilisé pour les disques durs, aussi appelé le bus ''Parallel ATA''. Il peut aussi être connecté au processeur, à la mémoire RAM, ainsi qu'à la mémoire cache, mais cela ne sert que quand il est utilisé comme répartiteur.
[[File:Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur.png|centre|vignette|upright=2|Architecture d'un PC utilisant un bus PCI, implémentation avec un répartiteur]]
Pour des raisons de compatibilité, le bus ISA avait été conservé, aux côtés du bus PCI. Il y avait un pont ISA en plus du pont/répartiteur PCI. Une implémentation possible aurait été de connecter les deux ponts ISA et PCI à un bus système unique. Mais cette solution n'a pas été retenue. La raison est que le bus PCI et le bus ISA ont des performances très différentes. Le bus PCI est très rapide, le bus ISA beaucoup plus lent. La différence est d'un ordre de grandeur, environ. Dans ces conditions, il est possible de faire passer les communications ISA à travers le bus PCI. Pour cela, le pont ISA est directement connecté sur le pont PCI, comme illustré ci-dessous.
Et il en est de même pour le bus dédié aux disques durs. En effet, les disques durs étaient autrefois reliés au bus ISA, mais cela a changé depuis. Ils disposent maintenant de leur propre bus dédié, le '''bus IDE''', qui est un bus ISA simplifié. Et ce bus ISA simplifié était connecté directement sur le pont PCI.
[[File:Architecture de l'IBM PC compatible avec pont PCI.png|centre|vignette|upright=2|Architecture de l'IBM PC compatible avec pont PCI]]
Dans ce qui va suivre, nous allons étudier un exemple qui utilise un bus système séparé, avec un pont PCI, sans répartiteur. Voilà pour les grandes lignes, mais le schéma ci-dessous montre que tout est plus complexe. Vous remarquerez des connexions optionnelles entre le pont PCI et la mémoire RAM et la mémoire cache. La raison est que le pont PCI peut aussi servir de répartiteur en remplacement du bus système. Concrètement, on peut alors retirer le bus système. La mémoire, le bus PCI, le bus ISA, le bus IDE, le processeur et la RAM sont alors connectés au répartiteur PCI, qui sert d'intermédiaire central entre tous ces composants. Mais ce n'est pas la solution qui a été retenue dans notre exemple.
[[File:Intel486-Typ PCI System.png|centre|vignette|upright=2|PC IBM compatible avec un 486, un bus PCI et un bus ISA. Le ''host bus'' est le bus système.]]
Le pont ISA sert ici d'intermédiaire entre le bus système et le bus ISA. De plus, il a été amélioré sur de nombreux points. Il inclut notamment des circuits qui étaient autrefois sur la carte mère, à savoir le contrôleur DMA 82C87 et le contrôleur d'interruption 82C59, ainsi que les ''timers'' Intel 82C54. Les composants restants sont eux reliés sur un quatrième bus : le bus X, l'ancêtre du bus ''Low Pin Count''. Le bus X était celui du BIOS, du contrôleur de clavier, de la ''Real Time Clock'', et du contrôleur de périphérique 82091AA d'Intel.
[[File:ISA Bridge schematic.png|centre|vignette|upright=2|ISA Bridge.]]
===L'architecture des PC des années 90-2000===
Par la suite, les ponts PCI et ISA ont évolué avec l'évolution des bus de l'ordinateur. Le bus ISA a progressivement été remplacé par d'autres bus, comme le bus ''Low Pin Count'', le bus PCI a été remplacé par le PCI Express, d'autres bus ont été ajoutés, etc. Mais la séparation du ''chipset'' en deux a été conservée.
[[File:Chipset schematic.svg|vignette|upright=1.0|Chipset séparé en northbridge et southbridge.]]
Le pont PCI et le pont ISA ont été remplacés respectivement par le '''pont nord''' et le '''pont sud''', plus connus par leurs noms anglais de ''northbridge'' et de ''southbridge''. Le pont nord servait d'interface entre le processeur, la mémoire et la carte graphique et est connecté à chacun par un bus dédié. Il intégrait aussi le contrôleur mémoire. Le pont sud est le répartiteur pour les composants lents, à savoir l'USB, l'Ethernet, etc. Le bus qui relie le processeur au pont nord était appelé le '''''Front Side Bus''''', abrévié en FSB.
[[File:IMac Chipset.png|centre|vignette|upright=2|Chipset séparé en northbridge et southbridge.]]
Un point important est que le bus PCI est devenu un bus assez lent, ce qui fait qu'il a finit par être connecté au pont sud. Le pont PCI est donc devenu le pont sud, dans le courant des années 2000. Durant un moment, un équivalent du pont ISA a subsisté dans un circuit de '''''Super IO'''''. Concrètement, il s'occupait du lecteur de disquette, du port parallèle, du port série, et des ports PS/2 pour le clavier et la souris. Mais il ne gérait pas le bus ISA, mais son remplaçant, le bus ''Low Pin Count''.
[[File:Motherboard diagram fr.svg|centre|vignette|upright=1.5|Carte mère avec circuit Super IO.]]
===L'architecture des PC depuis les années 2000===
Depuis la sortie du processeur AMD Athlon 64, le pont nord a été fusionné dans le processeur. La fusion ne s'est pas faite en une fois, des fonctionnalités ont progressivement été progressivement intégrées dans le processeur. Le pont sud est resté, mais il a alors été progressivement connecté directement au processeur. La raison derrière cette intégration est que les processeurs avaient de plus en plus de transistors à leur disposition. Ils en ont profité pour intégrer le pont nord. Et cela permettait de simplifier le câblage des cartes mères, sans pour autant rendre vraiment plus complexe la fabrication du processeur. Les industriels y trouvent leur compte.
La première étape a été l'intégration du contrôleur mémoire a été intégré au processeur. Concrètement, le résultat était que la mémoire RAM n'était plus connectée au pont nord, mais était connectée directement au processeur ! Il y a donc eu un retour d'un bus mémoire, mais spécialisé pour la mémoire RAM. En théorie, une telle intégration permet diverses optimisations quant aux transferts avec la mémoire RAM. Les transferts ne passent pas par un répartiteur, ce qui réduit le temps d'accès à la mémoire RAM. Ajoutons de sombres histoires de prefetching, d'optimisation des commandes, et j'en passe. Toujours est-il que le pont nord ne servait alors d'intermédiaire que pour les ports PCI Express, et le pont sud.
[[File:X58 Block Diagram.png|centre|vignette|upright=2|Chipset X58 d'Intel.]]
Par la suite, la carte graphique fût aussi connectée directement sur le processeur. Le processeur incorpore pour cela des contrôleurs PCI-Express. Le pont nord a alors disparu complétement, son intégration dans le processeur était complète. Sur les cartes mères Intel récentes, le pont sdud subsiste, il est appelé le ''Platform Controler Hub'', ou PCH. L'organisation des bus sur la carte mère qui résulte de cette connexion du processeur à la carte graphique, est illustrée ci-dessous, avec l'exemple du PCH.
[[File:Intel 5 Series architecture.png|centre|vignette|upright=2|Intel 5 Series architecture]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'interface électrique entre circuits intégrés et bus
| prevText=L'interface électrique entre circuits intégrés et bus
| next=La hiérarchie mémoire
| nextText=La hiérarchie mémoire
}}
</noinclude>
hifq22id2qz3iqsqprlp8ud68zbx1w9
Planétologie/La planète Vénus
0
69632
762722
679212
2026-04-01T14:00:40Z
Mewtow
31375
/* La tectonique vénusienne */
762722
wikitext
text/x-wiki
[[File:Venus (7544560662).jpg|vignette|Vénus]]
Vu de l'extérieur, Vénus est complètement cachée par une atmosphère tellement nuageuse qu'elle nous empêche de voir la surface ! Les missions d'exploration ont dû recourir à des analyses radar pour observer indirectement sa surface. Par contre, l'analyse de l'atmosphère est bien plus simple, vu que les mouvements des nuages trahissent les mouvements de l'air. L'analyse de la composition chimique de l'atmosphère est aussi assez simple, l'analyse de la lumière (spectroscopique) n'étant pas trop perturbée par les reflets de la surface. En conséquence, l'atmosphère de Vénus est assez bien connue, bien plus que sa surface.
==L'atmosphère de Vénus==
La température et la pression à la surface de Vénus sont extrêmement importantes. L'épaisseur de l'atmosphère est très importante, au point qu'elle limite les variations de la température de surface. La température ne varie pas beaucoup entre l'équateur et les pôles, de même qu'entre le jour et la nuit ou entre saisons. De plus, la pression au sol atteint 9,3 MPa, soit 91,8 fois la pression atmosphérique terrestre ! Pour comparaison, cette pression est du même ordre que la pression sous-marine à une profondeur de {{formatnum:1000}} mètres. La température de surface est tout aussi hostile, variant de 450°C à de plus de 500°C. Ces conditions extrêmes sont liées à l'effet de serre et à la composition chimique de l'atmosphère. Ajoutons à cela que la planète est littéralement recouverte de nuages d'acide sulfurique et de dioxyde de soufre, et que les orages relativement « courants » donnent naissance à de splendides éclairs rougeâtres. De quoi légitimement qualifier Vénus d'« enfer céleste ».
===La structure verticale de l'atmosphère de Vénus===
L’atmosphère de Vénus est stratifiée en plusieurs couches, à l'image de ce que l'on observe sur Terre. Il est possible de subdiviser l'atmosphère à partir de la relation température-altitude. Mais on peut aussi utiliser d'autres critères, comme l'ionisation des molécules, pour subdiviser l'atmosphère de Vénus.
L'évolution de la température avec l'altitude est relativement claire et permet de découper l'atmosphère en quatre couches distinctes, similaires à celles observées sur Terre. En partant de la surface, la température baisse avec l’altitude dans la '''troposphère''' puis se stabilise au niveau de la tropopause. Au-delà de la tropopause, dans la '''mésosphère''', la température diminue encore avec l'altitude mais à un rythme différent de la troposphère. La température remonte avec l'altitude dans la '''thermosphère'''. Il est important de remarquer qu'il n'y a pas de stratosphère sur Vénus, liée à l'absence de couche d'ozone. Par contre, la transition entre troposphère et mésosphère existe bel et bien et se voit quand on analyse la manière dont la température évolue avec l'altitude. Pour résumer, on peut diviser l’atmosphère vénusienne en plusieurs couches principales, comme suit :
{|class="wikitable"
|-
! Couche atmosphérique
! Altitude
! Comportement thermique
! Opacité
|-
! Troposphère
| De la surface du sol à 50-60 km d'altitude
| Baisse de la température avec l'altitude.
| Couche subdivisée en sous-couches claires et sous-couches denses et sombres.
|-
! Mésosphère
| Base à 70 kilomètres d'altitude, plafond à 90-120 km.
| Baisse de la température avec l'altitude, sauf à sa base.
| rowspan="2" | Couche claire, transparente aux rayons solaires, non-ionisée, peu dense.
|-
! Thermosphère
| Base à 90-120 km, plafond à 220-350 kilomètres.
| Hausse de la température avec l'altitude.
|}
L'état d'ionisation des molécules varie avec l'altitude. Avec ce critère, on peut distinguer l'ionosphère et le reste. Entre 115 km et 260 kilomètres d'altitude, les gaz atmosphériques s'ionisent, donnant naissance à une dernière couche : l''''ionosphère'''. Le reste de l'atmosphère de Vénus n'est pas ionisé.
===La circulation atmosphérique de Vénus===
La circulation atmosphérique de Vénus est semblable à celle de la Terre, dans le sens où elle s'organise autour de courants de convection qui redistribuent la chaleur de l'équateur vers les pôles. Mais les courants de convection sont différents entre la troposphère et le reste de l'atmosphère.
Dans la haute atmosphère, il existe deux courants de convection qui vont de la face éclairée vers la face sombre, du jour à la nuit. Le Soleil chauffe la surface de la face éclairée et les courants de convection redistribuent cette chaleur vers la face non-éclairée. Rappelons que les nuits vénusiennes sont très longues : une nuit vénusienne dure autant que 58 jours terrestres. Pas étonnant donc que cette convection du jour vers la nuit se soit mise en place.
Dans la troposphère, les cellules de convection ont de l'équateur vers les pôles. L'équateur est chauffé plus efficacement que les pôles, en raison de l'inclinaison des rayons solaires (perpendiculaires à la surface au niveau de l'équateur et beaucoup incliné au niveau des pôles). Les mouvements d'airs redistribuent la chaleur de l'équateur vers les pôles, comme ce qu'on peut observer sur Terre. Mais à la différence de ce qu'on observe sur Terre, la vitesse de rotation de Vénus fait qu'il n'existe qu'une seule cellule de convection par hémisphère. Ces cellules s'arrêtent au niveau des pôles, qui sont entourés par des courants-jets polaires similaires à ceux observés sur Terre.
[[File:Circulation atm Venus.svg|centre|vignette|upright=2.0|Circulation atmosphérique sur Venus.]]
===La composition chimique de l'atmosphère de Vénus===
La composition chimique de l’atmosphère vénusienne est illustrée dans le schéma ci-dessous. On voit qu'oxygène et eau y sont clairement minoritaires, l'atmosphère vénusienne étant surtout composée de dioxyde de carbone, de diazote et de vapeur d'eau. Les composés soufrés sont aussi très présents, notamment l'acide sulfurique et le dioxyde de soufre. À noter que l'acide sulfurique se forme quand le dioxyde de Soufre se combine avec de l'eau (sous forme vapeur). Ces derniers sont vraisemblablement émis par le volcanisme vénusien, autant lors des périodes récentes qu'anciennes. La majorité des composés soufrés se trouve actuellement dans les nuages. Les nuages vénusiens donnent naissance à de nombreuses pluies acides, chargées en acide sulfurique, mais qui s'évaporent avant de toucher la surface à cause des fortes températures.
[[File:Venus atmosphere compo.svg|centre|vignette|upright=2.0|Composition chimique de l'atmosphère de Venus.]]
: ''Les molécules de l'air vénusien absorbent la lumière bleue, ce qui fait que l'atmosphère vénusienne a une couleur orange.''
====Une atmosphère riche en dioxyde de carbone====
Vénus a une atmosphère plus riche en dioxyde de carbone que la Terre, alors que les deux planètes sont pourtant très semblables. Et diverses estimations nous disent que les deux planètes possèdent une quantité similaire de dioxyde de carbone. La différence est que celui-ci n'est pas réparti de la même manière entre l'atmosphère et la lithosphère.
Sur Terre, une partie du <chem>CO2</chem> est stocké dans l'atmosphère, une autre dans la biosphère, une autre dans les océans et une autre dans les roches de la croute. Le carbone passe d'un réservoir à l'autre, par divers mécanismes regroupés dans ce qu'on appelle le cycle du carbone. Une grande quantité de carbone est stocké sous la forme de carbonates ou d'énergie fossile (charbon, pétrole). La formation de ces roches est liée à la fabrication de matière organique par les êtres vivants, ou tout simplement à la présence d'eau liquide.
Sur Vénus, il n'y a pas de cycle de carbone du fait de l'absence d'eau et de vie, ce qui fait que la séquestration de <chem>CO2</chem> dans les roches est inexistante. En clair, tout le <chem>CO2</chem> se retrouve dans l'atmosphère de Vénus. La concentration en <chem>CO2</chem> de l'atmosphère de Vénus est donc plus grande que celle observée sur Terre.
====Une faible teneur en oxygène moléculaire et en monoxyde de carbone====
La teneur en <chem>O2</chem> de l'atmosphère de Vénus est extrêmement rare, alors qu'on devrait trouver le contraire. En théorie, le <chem>CO2</chem> est photolysé, c'est à dire cassé par le rayonnement solaire. La réaction chimique en question est la suivante :
: <chem>CO2 + photon -> CO + O</chem>
L'oxygène libéré par la réaction est sous forme atomique. Or, les atomes d'oxygène se combinent pour donner une molécule d'oxygène. La réaction précédente peut donc se réécrire comme suit, pour en tenir compte :
: <chem>2 CO2 + photon -> 2 CO + O2</chem>
Avec cette réaction, les données nous disent que l'on devrait trouver deux fois plus de <chem>CO</chem> que d'<chem>O2</chem> dans l'atmosphère de Vénus, soit un ratio <chem>CO/O2</chem> de 2:1. Mais il n'en est rien ! Le ratio mesuré est bien plus élevé, d'environ 150, voire plus. La raison est que l'oxygène est éliminé de l'atmosphère de Vénus par divers mécanismes, dont le principal est la formation d'acide sulfurique, comme nous allons le voir immédiatement.
====La formation d'acide sulfurique====
Ce n'est pas marqué dans les schémas ci-dessus, mais l'atmosphère de Vénus contient beaucoup d'acide sulfurique. Celui-ci se forme au sommet de l'atmosphère, par une série de réactions chimiques assez complexes. La réaction complète peut se résumer avec cette équation :
: <chem>2 SO2 + O2 + 2 H2O -> 2 H2SO4</chem>
On voit que de l'oxygène est utilisé dans cette équation. C'est en effet une des raisons qui explique que l'oxygène soit aussi rare dans l'atmosphère de Vénus. La formation d'acide sulfurique est donc un des mécanismes qui élimine l'oxygène de l'atmosphère, en l'incorporant dans les molécules d'acide sulfurique. Mais il ne peut pas à lui seul expliquer pourquoi l'oxygène moléculaire est aussi rare. De plus, on voit que de l'eau est utilisée comme réactif, ce qui explique en partie pourquoi on trouve aussi peu d'eau sur Vénus. L'eau est consommée, au même titre que l'oxygène, lors de la formation d'acide sulfurique.
Toujours est-il que la formation d'acide sulfurique dans l'atmosphère de Vénus se fait en trois étapes, par trois réactions chimiques couplées. La première réaction implique la dissociation du dioxyde de carbone par le rayonnement solaire. Ce qui explique que l'acide sulfurique se forme au sommet de la couche nuageuse, avant de retomber vers la surface.
: <chem>CO2 + photon -> C O + O</chem>
La seconde combine l'oxygène de la réaction précédente avec du dioxyde de soufre :
: <chem>SO2 + O -> SO3</chem>
La troisième combine le trioxyde de soufre <math>S O_3</math> avec de l'eau :
: <chem>2 SO3 + 4 H2O -> 2 H2SO4 + 2 H2O</chem>
Le processus est assez bien compris, sauf sur un point : les réactions précédentes devraient se produire lentement dans les conditions théoriques de l'atmosphère de Vénus. La seule explication est qu'il y a un catalyseur, une substance qui accélère les réactions chimiques précédentes, dans l'atmosphère de Vénus. Ce catalyseur est supposé être du chlore ou des molécules dérivées.
===L'effet de serre sur Vénus===
L’atmosphère vénusienne est riche en gaz à effet de serre : dioxyde de carbone, soufre, etc. On peut s'en rendre compte en regardant leur spectre d'absorption. La lumière visible est peu absorbée, mais elle est en revanche fortement réfléchie. Par contre, la plupart des gaz absorbent une grande partie des rayonnements infrarouge, le dioxyde de carbone étant le principal responsable. Cela induit un fort effet de serre, qui explique que l’atmosphère de Vénus est un véritable enfer avec une température de surface de plus de 500°C.
[[File:Synthetic Venus atmosphere absorption spectrum.gif|centre|vignette|upright=2.0|Spectre d'absorption lumineuse de l'atmosphère de Venus.]]
L'albédo de l'atmosphère vénusienne est importante : plus de 2/3 de la lumière solaire incidente est renvoyée vers l’espace. La composition soufrée des nuages explique que les nuages vénusiens ont un albédo très fort, ce qui limite l'arrivée du rayonnement solaire à la surface, mais qui est aussi à l’origine d'un effet de serre particulièrement important, qui s'ajoute à l'effet de serre lié aux gaz à effet de serre carbonés.
[[File:Effet de serre sur Venus-2.svg|centre|vignette|upright=2.0|Effet de serre sur Venus-2]]
===Les nuages sur Vénus===
L'atmosphère de Vénus est extrêmement riche en nuages, localisés dans la troposphère et dans la mésosphère. Contrairement à ce qu'on observe sur Terre, où les nuages sont tous dans la troposphère, les nuages de Vénus se trouvent à la fois dans la troposphère et la mésosphère. De plus, là où les nuages terrestres peuvent atteindre le sol, ce n'est pas le cas sur Vénus. Les nuages vénusiens ne descendent pas en-deça de 30 kilomètres d'altitude. On n'en trouve pas à la base de la troposphère, car les gouttelettes qui forment les nuages s'évaporent avec la température. Pour résumer, les nuages sont regroupés dans une '''couche nuageuse''' assez épaisse, localisée entre 30 et 70 kilomètres d'altitude. Elle est localisée dans la haute troposphère et la basse mésosphère, à savoir au sommet de la troposphère et à la base de la mésosphère. En dessous de la couche nuageuse, on trouve la basse atmosphère, complètement transparente du fait de l'absence de nuages. La couche nuageuse au-dessus est bien plus opaque, ce qui fait que c'est là qu'à lieu la majorité de l'effet de serre sur Vénus. Enfin, la couche nuageuse est surmontée par la haute atmosphère, qui s’étend de la base de la couche nuageuse vers l'exosphère (la limite de l'atmosphère).
{|class="wikitable"
|-
!
! Altitude
! Transparence/opacité
|-
! Basse atmosphère
| De la surface du sol à 30 km d'altitude
| Couche claire, transparente aux rayons solaires, dense, non-ionisée.
|-
! Couche nuageuse
| Entre 30 et 70 kilomètres d'altitude.
| Couche opaque aux rayons solaires, lieu de l'absorption du rayonnement solaire et de l'effet de serre.
|-
! Haute atmosphère
| De 70 km d'altitude à l'exosphère.
| Couche claire, transparente aux rayons solaires, dense, non-ionisée.
|}
La couche nuageuse contient de nombreux nuages, qui ne sont pas formés d'eau comme sur Terre, mais qui sont surtout composés de dioxyde de soufre et d'acide sulfurique. Les nuages sont surtout composés d'acide sulfurique <chem>H2SO4</chem>, qui se forme à la surface de la couche nuageuse. Au sommet de la couche nuageuse, diverses réactions chimiques forment de l'acide sulfurique à partir de dioxyde de soufre, d'eau et de dioxyde de carbone. L'acide sulfurique formé ainsi se condense en gouttelettes, qui tombent. À une altitude d'environ 48 à 52 kilomètres les gouttelettes se regroupent et coalescent pour former des nuages. Il se forme donc une couche nuageuse située à une altitude située entre 48 et 52 kilomètres d'altitude, là où se trouve la plus grande densité de gouttelettes.
Notons que les gouttelettes peuvent tomber des nuages pour donner des pluies acides. Les pluies tombent alors vers la surface, mais elles s'évaporent rapidement avant d'atteindre la surface. En dessous de 30 kilomètres d'altitude, les pluies acides sont totalement évaporées, ce qui fait qu'elles n'atteignent jamais la surface. La couche située en dessous de 30 kilomètres est donc totalement claire, sans nuages ni pluies. Entre 30 et 48 kilomètres d'altitude, l'atmosphère est remplie de pluies acides et d'une brume résiduelle, ce qui fait qu'on lui donne le nom de '''couche brumeuse'''.
Avec ce qu'on vient de dire, on peut grossièrement diviser la couche nuageuse en trois sections :
* La '''couche supérieure''', au sommet de la couche nuageuse, où se forment les gouttelettes d'acide sulfurique.
* La '''couche centrale''', zone de formation des pluies, très dense et riche en nuages, d'une épaisseur très mince (48 à 52 kilomètres).
* La '''couche brumeuse''', où les pluies acides tombent vers la surface et où se forment des brumes de faible densité (30 à 48 kilomètres).
[[File:Venus atmosphere-fr.svg|centre|vignette|upright=2.0|Atmosphère vénusienne.]]
==La géologie de Vénus==
Des observations radar, il ressort que la planète est peu cratérisée et a donc une activité tectonique et/ou volcanique assez importante. Le comptage des cratères suggère que tous les terrains à la surface de Vénus datent de moins de 500 millions d'années. Cela indique que toute la croûte entière de Vénus a été renouvelée en moins de 500 millions d'années. Et cela vaut pour toute la surface de Vénus : les cratères d'impact sont uniformément répartis à la surface de Vénus, ce qui indique que le renouvellement de la croûte vénusienne a été global. Cela indique une activité géologique récente et un volcanisme intense.
===La topographie de Vénus===
La surface de Vénus est relativement lisse, avec quelques zones surélevées. Ces zones surélevées sont généralement des zones volcaniques, mais pas seulement. On voit notamment les volcans Thea et Rhea Mons, ainsi que les « continents » Ishtar et les Monts Maxwell, deux structures formées de roches volcaniques superposées et plissées. Pour résumer, la surface de Vénus montre des plaines formées probablement par des épanchements de lave, quelques structures surélevées appelées« Highlands » (similaires à des continents) et quelques montagnes pour la plupart d'origine volcanique.
[[File:Venus map with labels.jpg|centre|vignette|upright=2.0|Carte topographique de Vénus.]]
===La structure interne de Vénus===
[[File:Venus structure.jpg|vignette|Structure interne de Vénus]]
Faute d'études sismologiques, les savants doivent se rabattre sur le minimum vital de données qu'ils ont en leur possession. Celles-ci disent que l'intérieur de Vénus n'est pas différent des autres planètes telluriques : on y trouve une croûte et un manteau silicaté, et un noyau ferreux. Du fait de sa taille, Vénus produit toujours de la chaleur radioactive et est encore active géologiquement. Preuve en est la faible cratérisation de la surface, qui prouve que le volcanisme doit être encore actif. Vu que Venus a une taille similaire à celle de la Terre, sa chaleur et sa température interne doivent être similaires. Cela permet de supposer une structure interne similaire à celle de la Terre, avec un noyau au moins partiellement liquide.
Mais alors, on peut se demander pourquoi Vénus n'a pas de champ magnétique contrairement à la Terre, alors que les deux planètes ont des noyaux similaires de taille similaire. La raison reste un mystère pour les chercheurs. Il est supposé que l'absence de convection dans le noyau soit à l'origine de cette absence de champ magnétique. Reste que l'absence de convection serait liée au fait que le noyau ne se refroidisse pas assez rapidement ou à l'absence d'une graine solide centrale. L'absence de tectonique des plaques pourrait jouer un rôle en limitant le refroidissement du manteau, et donc indirectement du noyau. Le noyau restant suffisamment chaud, des mouvements de convection ne peuvent pas se développer. De plus, cela garde le noyau suffisamment chaud pour empêcher sa solidification : il n'y aurait pas de graine solide au centre de Venus, contrairement à ce qu'on observe sur Terre.
===Le volcanisme vénusien===
La surface de Vénus montre peu de structures accidentées comme des montagnes, des failles ou des plis. Il y en a, mais l'ensemble de la surface semble surtout composé de plaines formées par des épanchements de lave basaltique qui recouvrent plus de 70% de la surface. Ces '''plaines de lave''' sont semblables aux trapps observés sur terre, ainsi qu'aux mers lunaires et aux plaines martiennes. Les sondes Venera et Vega ont effectué des prélèvements sur les plaines de lave et en ont analysé les roches. De ces analyses, il ressort que les plaines sont composées de basaltes, très semblables aux basaltes terrestres.
Des volcans sont aussi observés, sur l'ensemble de la surface de Vénus. Les structures volcaniques ont quelques ressemblances avec les volcans terrestres, mais certaines se démarquent franchement de leurs homologues terrestres. On retrouve des '''volcans boucliers''', à savoir des volcans à faible pente très étalés, communs sur la Terre. Les volcans vénusiens se distinguent cependant par la large taille de leurs caldéras, de plusieurs centaines de kilomètres pour certaines !
[[File:Maat Mons on Venus.jpg|centre|vignette|upright=2.0|Volcan Maat Mons.]]
Certaines structures sont exclusives de Vénus, les '''dômes de lave aplatis''' en étant le meilleur exemple. Ceux-ci sont formés par des dômes de lave visqueuse, qui s'accumule au point de sortie éruptif. Sous l'effet de la pression atmosphérique extrême de Vénus, la lave s'étale mollement, formant des dômes aplatis. Il existe des équivalents sur Terre, mais qui ne sont pas aplatis par la faible pression atmosphérique. De plus, les dômes vénusiens ont un pic à leur sommet, chose qui n'existe que sur Vénus. L'origine des pics sommitaux n'est pas encore comprise, mais ils semblent s'être formés après le dôme.
[[File:PIA00084 Eistla region pancake volcanoes.jpg|centre|vignette|upright=2.0|Dômes de lave aplatis.]]
===Les ''coronaes'' et arachnoïdes===
Sur la surface vénusienne, on trouve des effondrements concentriques, entourés de fissures par lesquelles sortent des flots de lave, l'ensemble étant appelé des '''coronaes'''. Ces structures seraient la manifestation de panaches mantelliques, des remontées de matériau peu denses à travers le manteau. On peut les voir comme des rifts circulaires.
[[File:VenusianArachnoid.png|centre|vignette|upright=2.0|Coronae.]]
===La tectonique vénusienne===
Venus n'a pas de tectonique des plaques, comme pour toutes les autres planètes telluriques à l'exception de la Terre. Vénus reste une planète à une plaque, même si ses caractéristiques (masse, densité, volume) sont similaires à celle de la Terre. Une explication vraisemblable serait que les roches de Vénus ne contiendraient pas d'eau. On sait que l'atmosphère et la surface de Vénus sont pauvres en eau et on peut raisonnablement extrapoler la même chose au manteau et à la lithosphère de Vénus.
L'eau a tendance à abaisser le point de fusion des roches et à modifier leurs propriétés, particulièrement pour les roches mantelliques. En conséquence, Vénus aurait une lithosphère et un manteau difficiles à faire fondre, ce qui ne favorise pas la mise en place d'une tectonique des plaques. Cela expliquerait pourquoi la Terre aurait une tectonique des plaques et pas Vénus, la Terre ayant beaucoup plus d'eau que Vénus.
Mais absence de tectonique des plaques ne signifie pas absence de tectonique tout court. On observe à sa surface des zones de plissement ou d'étirement de grande ampleur, localisées à des endroits distincts de la planète, généralement dans les zones volcaniques. On suppose que ces plis et failles soient causées par des mouvements d'extension et/ou de compression induits par les mouvements mantelliques. Le manteau de Vénus serait en convection, de par sa température, les cellules de convection entraînant la croûte molle qui les surplombe.
<noinclude>
{{NavChapitre | book=Planétologie
| prev=La planète Mercure
| prevText=La planète Mercure
| next=La planète Mars
| nextText=La planète Mars
}}{{autocat}}
</noinclude>
kfm32p1ncuebfyyx71srwtmsd94r7pd
762723
762722
2026-04-01T14:01:06Z
Mewtow
31375
/* La tectonique vénusienne */
762723
wikitext
text/x-wiki
[[File:Venus (7544560662).jpg|vignette|Vénus]]
Vu de l'extérieur, Vénus est complètement cachée par une atmosphère tellement nuageuse qu'elle nous empêche de voir la surface ! Les missions d'exploration ont dû recourir à des analyses radar pour observer indirectement sa surface. Par contre, l'analyse de l'atmosphère est bien plus simple, vu que les mouvements des nuages trahissent les mouvements de l'air. L'analyse de la composition chimique de l'atmosphère est aussi assez simple, l'analyse de la lumière (spectroscopique) n'étant pas trop perturbée par les reflets de la surface. En conséquence, l'atmosphère de Vénus est assez bien connue, bien plus que sa surface.
==L'atmosphère de Vénus==
La température et la pression à la surface de Vénus sont extrêmement importantes. L'épaisseur de l'atmosphère est très importante, au point qu'elle limite les variations de la température de surface. La température ne varie pas beaucoup entre l'équateur et les pôles, de même qu'entre le jour et la nuit ou entre saisons. De plus, la pression au sol atteint 9,3 MPa, soit 91,8 fois la pression atmosphérique terrestre ! Pour comparaison, cette pression est du même ordre que la pression sous-marine à une profondeur de {{formatnum:1000}} mètres. La température de surface est tout aussi hostile, variant de 450°C à de plus de 500°C. Ces conditions extrêmes sont liées à l'effet de serre et à la composition chimique de l'atmosphère. Ajoutons à cela que la planète est littéralement recouverte de nuages d'acide sulfurique et de dioxyde de soufre, et que les orages relativement « courants » donnent naissance à de splendides éclairs rougeâtres. De quoi légitimement qualifier Vénus d'« enfer céleste ».
===La structure verticale de l'atmosphère de Vénus===
L’atmosphère de Vénus est stratifiée en plusieurs couches, à l'image de ce que l'on observe sur Terre. Il est possible de subdiviser l'atmosphère à partir de la relation température-altitude. Mais on peut aussi utiliser d'autres critères, comme l'ionisation des molécules, pour subdiviser l'atmosphère de Vénus.
L'évolution de la température avec l'altitude est relativement claire et permet de découper l'atmosphère en quatre couches distinctes, similaires à celles observées sur Terre. En partant de la surface, la température baisse avec l’altitude dans la '''troposphère''' puis se stabilise au niveau de la tropopause. Au-delà de la tropopause, dans la '''mésosphère''', la température diminue encore avec l'altitude mais à un rythme différent de la troposphère. La température remonte avec l'altitude dans la '''thermosphère'''. Il est important de remarquer qu'il n'y a pas de stratosphère sur Vénus, liée à l'absence de couche d'ozone. Par contre, la transition entre troposphère et mésosphère existe bel et bien et se voit quand on analyse la manière dont la température évolue avec l'altitude. Pour résumer, on peut diviser l’atmosphère vénusienne en plusieurs couches principales, comme suit :
{|class="wikitable"
|-
! Couche atmosphérique
! Altitude
! Comportement thermique
! Opacité
|-
! Troposphère
| De la surface du sol à 50-60 km d'altitude
| Baisse de la température avec l'altitude.
| Couche subdivisée en sous-couches claires et sous-couches denses et sombres.
|-
! Mésosphère
| Base à 70 kilomètres d'altitude, plafond à 90-120 km.
| Baisse de la température avec l'altitude, sauf à sa base.
| rowspan="2" | Couche claire, transparente aux rayons solaires, non-ionisée, peu dense.
|-
! Thermosphère
| Base à 90-120 km, plafond à 220-350 kilomètres.
| Hausse de la température avec l'altitude.
|}
L'état d'ionisation des molécules varie avec l'altitude. Avec ce critère, on peut distinguer l'ionosphère et le reste. Entre 115 km et 260 kilomètres d'altitude, les gaz atmosphériques s'ionisent, donnant naissance à une dernière couche : l''''ionosphère'''. Le reste de l'atmosphère de Vénus n'est pas ionisé.
===La circulation atmosphérique de Vénus===
La circulation atmosphérique de Vénus est semblable à celle de la Terre, dans le sens où elle s'organise autour de courants de convection qui redistribuent la chaleur de l'équateur vers les pôles. Mais les courants de convection sont différents entre la troposphère et le reste de l'atmosphère.
Dans la haute atmosphère, il existe deux courants de convection qui vont de la face éclairée vers la face sombre, du jour à la nuit. Le Soleil chauffe la surface de la face éclairée et les courants de convection redistribuent cette chaleur vers la face non-éclairée. Rappelons que les nuits vénusiennes sont très longues : une nuit vénusienne dure autant que 58 jours terrestres. Pas étonnant donc que cette convection du jour vers la nuit se soit mise en place.
Dans la troposphère, les cellules de convection ont de l'équateur vers les pôles. L'équateur est chauffé plus efficacement que les pôles, en raison de l'inclinaison des rayons solaires (perpendiculaires à la surface au niveau de l'équateur et beaucoup incliné au niveau des pôles). Les mouvements d'airs redistribuent la chaleur de l'équateur vers les pôles, comme ce qu'on peut observer sur Terre. Mais à la différence de ce qu'on observe sur Terre, la vitesse de rotation de Vénus fait qu'il n'existe qu'une seule cellule de convection par hémisphère. Ces cellules s'arrêtent au niveau des pôles, qui sont entourés par des courants-jets polaires similaires à ceux observés sur Terre.
[[File:Circulation atm Venus.svg|centre|vignette|upright=2.0|Circulation atmosphérique sur Venus.]]
===La composition chimique de l'atmosphère de Vénus===
La composition chimique de l’atmosphère vénusienne est illustrée dans le schéma ci-dessous. On voit qu'oxygène et eau y sont clairement minoritaires, l'atmosphère vénusienne étant surtout composée de dioxyde de carbone, de diazote et de vapeur d'eau. Les composés soufrés sont aussi très présents, notamment l'acide sulfurique et le dioxyde de soufre. À noter que l'acide sulfurique se forme quand le dioxyde de Soufre se combine avec de l'eau (sous forme vapeur). Ces derniers sont vraisemblablement émis par le volcanisme vénusien, autant lors des périodes récentes qu'anciennes. La majorité des composés soufrés se trouve actuellement dans les nuages. Les nuages vénusiens donnent naissance à de nombreuses pluies acides, chargées en acide sulfurique, mais qui s'évaporent avant de toucher la surface à cause des fortes températures.
[[File:Venus atmosphere compo.svg|centre|vignette|upright=2.0|Composition chimique de l'atmosphère de Venus.]]
: ''Les molécules de l'air vénusien absorbent la lumière bleue, ce qui fait que l'atmosphère vénusienne a une couleur orange.''
====Une atmosphère riche en dioxyde de carbone====
Vénus a une atmosphère plus riche en dioxyde de carbone que la Terre, alors que les deux planètes sont pourtant très semblables. Et diverses estimations nous disent que les deux planètes possèdent une quantité similaire de dioxyde de carbone. La différence est que celui-ci n'est pas réparti de la même manière entre l'atmosphère et la lithosphère.
Sur Terre, une partie du <chem>CO2</chem> est stocké dans l'atmosphère, une autre dans la biosphère, une autre dans les océans et une autre dans les roches de la croute. Le carbone passe d'un réservoir à l'autre, par divers mécanismes regroupés dans ce qu'on appelle le cycle du carbone. Une grande quantité de carbone est stocké sous la forme de carbonates ou d'énergie fossile (charbon, pétrole). La formation de ces roches est liée à la fabrication de matière organique par les êtres vivants, ou tout simplement à la présence d'eau liquide.
Sur Vénus, il n'y a pas de cycle de carbone du fait de l'absence d'eau et de vie, ce qui fait que la séquestration de <chem>CO2</chem> dans les roches est inexistante. En clair, tout le <chem>CO2</chem> se retrouve dans l'atmosphère de Vénus. La concentration en <chem>CO2</chem> de l'atmosphère de Vénus est donc plus grande que celle observée sur Terre.
====Une faible teneur en oxygène moléculaire et en monoxyde de carbone====
La teneur en <chem>O2</chem> de l'atmosphère de Vénus est extrêmement rare, alors qu'on devrait trouver le contraire. En théorie, le <chem>CO2</chem> est photolysé, c'est à dire cassé par le rayonnement solaire. La réaction chimique en question est la suivante :
: <chem>CO2 + photon -> CO + O</chem>
L'oxygène libéré par la réaction est sous forme atomique. Or, les atomes d'oxygène se combinent pour donner une molécule d'oxygène. La réaction précédente peut donc se réécrire comme suit, pour en tenir compte :
: <chem>2 CO2 + photon -> 2 CO + O2</chem>
Avec cette réaction, les données nous disent que l'on devrait trouver deux fois plus de <chem>CO</chem> que d'<chem>O2</chem> dans l'atmosphère de Vénus, soit un ratio <chem>CO/O2</chem> de 2:1. Mais il n'en est rien ! Le ratio mesuré est bien plus élevé, d'environ 150, voire plus. La raison est que l'oxygène est éliminé de l'atmosphère de Vénus par divers mécanismes, dont le principal est la formation d'acide sulfurique, comme nous allons le voir immédiatement.
====La formation d'acide sulfurique====
Ce n'est pas marqué dans les schémas ci-dessus, mais l'atmosphère de Vénus contient beaucoup d'acide sulfurique. Celui-ci se forme au sommet de l'atmosphère, par une série de réactions chimiques assez complexes. La réaction complète peut se résumer avec cette équation :
: <chem>2 SO2 + O2 + 2 H2O -> 2 H2SO4</chem>
On voit que de l'oxygène est utilisé dans cette équation. C'est en effet une des raisons qui explique que l'oxygène soit aussi rare dans l'atmosphère de Vénus. La formation d'acide sulfurique est donc un des mécanismes qui élimine l'oxygène de l'atmosphère, en l'incorporant dans les molécules d'acide sulfurique. Mais il ne peut pas à lui seul expliquer pourquoi l'oxygène moléculaire est aussi rare. De plus, on voit que de l'eau est utilisée comme réactif, ce qui explique en partie pourquoi on trouve aussi peu d'eau sur Vénus. L'eau est consommée, au même titre que l'oxygène, lors de la formation d'acide sulfurique.
Toujours est-il que la formation d'acide sulfurique dans l'atmosphère de Vénus se fait en trois étapes, par trois réactions chimiques couplées. La première réaction implique la dissociation du dioxyde de carbone par le rayonnement solaire. Ce qui explique que l'acide sulfurique se forme au sommet de la couche nuageuse, avant de retomber vers la surface.
: <chem>CO2 + photon -> C O + O</chem>
La seconde combine l'oxygène de la réaction précédente avec du dioxyde de soufre :
: <chem>SO2 + O -> SO3</chem>
La troisième combine le trioxyde de soufre <math>S O_3</math> avec de l'eau :
: <chem>2 SO3 + 4 H2O -> 2 H2SO4 + 2 H2O</chem>
Le processus est assez bien compris, sauf sur un point : les réactions précédentes devraient se produire lentement dans les conditions théoriques de l'atmosphère de Vénus. La seule explication est qu'il y a un catalyseur, une substance qui accélère les réactions chimiques précédentes, dans l'atmosphère de Vénus. Ce catalyseur est supposé être du chlore ou des molécules dérivées.
===L'effet de serre sur Vénus===
L’atmosphère vénusienne est riche en gaz à effet de serre : dioxyde de carbone, soufre, etc. On peut s'en rendre compte en regardant leur spectre d'absorption. La lumière visible est peu absorbée, mais elle est en revanche fortement réfléchie. Par contre, la plupart des gaz absorbent une grande partie des rayonnements infrarouge, le dioxyde de carbone étant le principal responsable. Cela induit un fort effet de serre, qui explique que l’atmosphère de Vénus est un véritable enfer avec une température de surface de plus de 500°C.
[[File:Synthetic Venus atmosphere absorption spectrum.gif|centre|vignette|upright=2.0|Spectre d'absorption lumineuse de l'atmosphère de Venus.]]
L'albédo de l'atmosphère vénusienne est importante : plus de 2/3 de la lumière solaire incidente est renvoyée vers l’espace. La composition soufrée des nuages explique que les nuages vénusiens ont un albédo très fort, ce qui limite l'arrivée du rayonnement solaire à la surface, mais qui est aussi à l’origine d'un effet de serre particulièrement important, qui s'ajoute à l'effet de serre lié aux gaz à effet de serre carbonés.
[[File:Effet de serre sur Venus-2.svg|centre|vignette|upright=2.0|Effet de serre sur Venus-2]]
===Les nuages sur Vénus===
L'atmosphère de Vénus est extrêmement riche en nuages, localisés dans la troposphère et dans la mésosphère. Contrairement à ce qu'on observe sur Terre, où les nuages sont tous dans la troposphère, les nuages de Vénus se trouvent à la fois dans la troposphère et la mésosphère. De plus, là où les nuages terrestres peuvent atteindre le sol, ce n'est pas le cas sur Vénus. Les nuages vénusiens ne descendent pas en-deça de 30 kilomètres d'altitude. On n'en trouve pas à la base de la troposphère, car les gouttelettes qui forment les nuages s'évaporent avec la température. Pour résumer, les nuages sont regroupés dans une '''couche nuageuse''' assez épaisse, localisée entre 30 et 70 kilomètres d'altitude. Elle est localisée dans la haute troposphère et la basse mésosphère, à savoir au sommet de la troposphère et à la base de la mésosphère. En dessous de la couche nuageuse, on trouve la basse atmosphère, complètement transparente du fait de l'absence de nuages. La couche nuageuse au-dessus est bien plus opaque, ce qui fait que c'est là qu'à lieu la majorité de l'effet de serre sur Vénus. Enfin, la couche nuageuse est surmontée par la haute atmosphère, qui s’étend de la base de la couche nuageuse vers l'exosphère (la limite de l'atmosphère).
{|class="wikitable"
|-
!
! Altitude
! Transparence/opacité
|-
! Basse atmosphère
| De la surface du sol à 30 km d'altitude
| Couche claire, transparente aux rayons solaires, dense, non-ionisée.
|-
! Couche nuageuse
| Entre 30 et 70 kilomètres d'altitude.
| Couche opaque aux rayons solaires, lieu de l'absorption du rayonnement solaire et de l'effet de serre.
|-
! Haute atmosphère
| De 70 km d'altitude à l'exosphère.
| Couche claire, transparente aux rayons solaires, dense, non-ionisée.
|}
La couche nuageuse contient de nombreux nuages, qui ne sont pas formés d'eau comme sur Terre, mais qui sont surtout composés de dioxyde de soufre et d'acide sulfurique. Les nuages sont surtout composés d'acide sulfurique <chem>H2SO4</chem>, qui se forme à la surface de la couche nuageuse. Au sommet de la couche nuageuse, diverses réactions chimiques forment de l'acide sulfurique à partir de dioxyde de soufre, d'eau et de dioxyde de carbone. L'acide sulfurique formé ainsi se condense en gouttelettes, qui tombent. À une altitude d'environ 48 à 52 kilomètres les gouttelettes se regroupent et coalescent pour former des nuages. Il se forme donc une couche nuageuse située à une altitude située entre 48 et 52 kilomètres d'altitude, là où se trouve la plus grande densité de gouttelettes.
Notons que les gouttelettes peuvent tomber des nuages pour donner des pluies acides. Les pluies tombent alors vers la surface, mais elles s'évaporent rapidement avant d'atteindre la surface. En dessous de 30 kilomètres d'altitude, les pluies acides sont totalement évaporées, ce qui fait qu'elles n'atteignent jamais la surface. La couche située en dessous de 30 kilomètres est donc totalement claire, sans nuages ni pluies. Entre 30 et 48 kilomètres d'altitude, l'atmosphère est remplie de pluies acides et d'une brume résiduelle, ce qui fait qu'on lui donne le nom de '''couche brumeuse'''.
Avec ce qu'on vient de dire, on peut grossièrement diviser la couche nuageuse en trois sections :
* La '''couche supérieure''', au sommet de la couche nuageuse, où se forment les gouttelettes d'acide sulfurique.
* La '''couche centrale''', zone de formation des pluies, très dense et riche en nuages, d'une épaisseur très mince (48 à 52 kilomètres).
* La '''couche brumeuse''', où les pluies acides tombent vers la surface et où se forment des brumes de faible densité (30 à 48 kilomètres).
[[File:Venus atmosphere-fr.svg|centre|vignette|upright=2.0|Atmosphère vénusienne.]]
==La géologie de Vénus==
Des observations radar, il ressort que la planète est peu cratérisée et a donc une activité tectonique et/ou volcanique assez importante. Le comptage des cratères suggère que tous les terrains à la surface de Vénus datent de moins de 500 millions d'années. Cela indique que toute la croûte entière de Vénus a été renouvelée en moins de 500 millions d'années. Et cela vaut pour toute la surface de Vénus : les cratères d'impact sont uniformément répartis à la surface de Vénus, ce qui indique que le renouvellement de la croûte vénusienne a été global. Cela indique une activité géologique récente et un volcanisme intense.
===La topographie de Vénus===
La surface de Vénus est relativement lisse, avec quelques zones surélevées. Ces zones surélevées sont généralement des zones volcaniques, mais pas seulement. On voit notamment les volcans Thea et Rhea Mons, ainsi que les « continents » Ishtar et les Monts Maxwell, deux structures formées de roches volcaniques superposées et plissées. Pour résumer, la surface de Vénus montre des plaines formées probablement par des épanchements de lave, quelques structures surélevées appelées« Highlands » (similaires à des continents) et quelques montagnes pour la plupart d'origine volcanique.
[[File:Venus map with labels.jpg|centre|vignette|upright=2.0|Carte topographique de Vénus.]]
===La structure interne de Vénus===
[[File:Venus structure.jpg|vignette|Structure interne de Vénus]]
Faute d'études sismologiques, les savants doivent se rabattre sur le minimum vital de données qu'ils ont en leur possession. Celles-ci disent que l'intérieur de Vénus n'est pas différent des autres planètes telluriques : on y trouve une croûte et un manteau silicaté, et un noyau ferreux. Du fait de sa taille, Vénus produit toujours de la chaleur radioactive et est encore active géologiquement. Preuve en est la faible cratérisation de la surface, qui prouve que le volcanisme doit être encore actif. Vu que Venus a une taille similaire à celle de la Terre, sa chaleur et sa température interne doivent être similaires. Cela permet de supposer une structure interne similaire à celle de la Terre, avec un noyau au moins partiellement liquide.
Mais alors, on peut se demander pourquoi Vénus n'a pas de champ magnétique contrairement à la Terre, alors que les deux planètes ont des noyaux similaires de taille similaire. La raison reste un mystère pour les chercheurs. Il est supposé que l'absence de convection dans le noyau soit à l'origine de cette absence de champ magnétique. Reste que l'absence de convection serait liée au fait que le noyau ne se refroidisse pas assez rapidement ou à l'absence d'une graine solide centrale. L'absence de tectonique des plaques pourrait jouer un rôle en limitant le refroidissement du manteau, et donc indirectement du noyau. Le noyau restant suffisamment chaud, des mouvements de convection ne peuvent pas se développer. De plus, cela garde le noyau suffisamment chaud pour empêcher sa solidification : il n'y aurait pas de graine solide au centre de Venus, contrairement à ce qu'on observe sur Terre.
===Le volcanisme vénusien===
La surface de Vénus montre peu de structures accidentées comme des montagnes, des failles ou des plis. Il y en a, mais l'ensemble de la surface semble surtout composé de plaines formées par des épanchements de lave basaltique qui recouvrent plus de 70% de la surface. Ces '''plaines de lave''' sont semblables aux trapps observés sur terre, ainsi qu'aux mers lunaires et aux plaines martiennes. Les sondes Venera et Vega ont effectué des prélèvements sur les plaines de lave et en ont analysé les roches. De ces analyses, il ressort que les plaines sont composées de basaltes, très semblables aux basaltes terrestres.
Des volcans sont aussi observés, sur l'ensemble de la surface de Vénus. Les structures volcaniques ont quelques ressemblances avec les volcans terrestres, mais certaines se démarquent franchement de leurs homologues terrestres. On retrouve des '''volcans boucliers''', à savoir des volcans à faible pente très étalés, communs sur la Terre. Les volcans vénusiens se distinguent cependant par la large taille de leurs caldéras, de plusieurs centaines de kilomètres pour certaines !
[[File:Maat Mons on Venus.jpg|centre|vignette|upright=2.0|Volcan Maat Mons.]]
Certaines structures sont exclusives de Vénus, les '''dômes de lave aplatis''' en étant le meilleur exemple. Ceux-ci sont formés par des dômes de lave visqueuse, qui s'accumule au point de sortie éruptif. Sous l'effet de la pression atmosphérique extrême de Vénus, la lave s'étale mollement, formant des dômes aplatis. Il existe des équivalents sur Terre, mais qui ne sont pas aplatis par la faible pression atmosphérique. De plus, les dômes vénusiens ont un pic à leur sommet, chose qui n'existe que sur Vénus. L'origine des pics sommitaux n'est pas encore comprise, mais ils semblent s'être formés après le dôme.
[[File:PIA00084 Eistla region pancake volcanoes.jpg|centre|vignette|upright=2.0|Dômes de lave aplatis.]]
===Les ''coronaes'' et arachnoïdes===
Sur la surface vénusienne, on trouve des effondrements concentriques, entourés de fissures par lesquelles sortent des flots de lave, l'ensemble étant appelé des '''coronaes'''. Ces structures seraient la manifestation de panaches mantelliques, des remontées de matériau peu denses à travers le manteau. On peut les voir comme des rifts circulaires.
[[File:VenusianArachnoid.png|centre|vignette|upright=2.0|Coronae.]]
===La tectonique vénusienne===
Venus n'a pas de tectonique des plaques, comme pour toutes les autres planètes telluriques à l'exception de la Terre. Vénus reste une planète à une plaque, même si ses caractéristiques (masse, densité, volume) sont similaires à celle de la Terre. Une explication vraisemblable serait que les roches de Vénus ne contiendraient pas d'eau. On sait que l'atmosphère et la surface de Vénus sont pauvres en eau et on peut raisonnablement extrapoler la même chose au manteau et à la lithosphère de Vénus.
L'eau a tendance à abaisser le point de fusion des roches et à modifier leurs propriétés, particulièrement pour les roches mantelliques. En conséquence, Vénus aurait une lithosphère et un manteau difficiles à faire fondre, ce qui ne favorise pas la mise en place d'une tectonique des plaques. Et ça expliquerait pourquoi la Terre aurait une tectonique des plaques et pas Vénus, la Terre ayant beaucoup plus d'eau que Vénus.
Mais absence de tectonique des plaques ne signifie pas absence de tectonique tout court. On observe à sa surface des zones de plissement ou d'étirement de grande ampleur, localisées à des endroits distincts de la planète, généralement dans les zones volcaniques. On suppose que ces plis et failles soient causées par des mouvements d'extension et/ou de compression induits par les mouvements mantelliques. Le manteau de Vénus serait en convection, de par sa température, les cellules de convection entraînant la croûte molle qui les surplombe.
<noinclude>
{{NavChapitre | book=Planétologie
| prev=La planète Mercure
| prevText=La planète Mercure
| next=La planète Mars
| nextText=La planète Mars
}}{{autocat}}
</noinclude>
175dfbs640nqshbzdmvktkvb7qeypkg
Mathc initiation/c34a3
0
76355
762760
715333
2026-04-02T07:55:06Z
Xhungab
23827
762760
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer ce fichier dans votre répertoire de travail.
{| class="wikitable"
|+ Texte de la légende
|-
|
{{Fichier|fa.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as fa.h */
/* ---------------------------------- */
#define LOOP 2*100
/* ---------------------------------- */
double g(
double r,
double k)
{
return( (4 - r*r) );
}
char geq[] = "4 - r**2";
/* ---------------------------------- */
/* ---------------------------------- */
double v(
double k)
{
return( (2) );
}
char veq[] = "2";
/* ---------------------------------- */
double u(
double k)
{
return( (0) );
}
char ueq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
double b = PI/2.; char beq[] = "PI/2";
double a = 0.; char aeq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
||
{{Fichier|fb.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as fb.h */
/* ---------------------------------- */
#define LOOP 2*100
/* ---------------------------------- */
double g(
double r,
double k)
{
return( (7. - 7./25. * r*r) );
}
char geq[] = "7 - 7./25 * r**2";
/* ---------------------------------- */
/* ---------------------------------- */
double v(
double k)
{
return( (5) );
}
char veq[] = "5";
/* ---------------------------------- */
double u(
double k)
{
return( (0) );
}
char ueq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
double b = 2*PI; char beq[] = "2*PI";
double a = 0.; char aeq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
|-
|
{{Fichier|fc.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as fc.h */
/* ---------------------------------- */
#define LOOP 2*100
/* ---------------------------------- */
double g(
double r,
double k)
{
return( (4 - r*r) );
}
char geq[] = "4 - r**2";
/* ---------------------------------- */
/* ---------------------------------- */
double v(
double r)
{
return( (PI/2) );
}
char veq[] = "Pi/2";
/* ---------------------------------- */
double u(
double r)
{
return( (0) );
}
char ueq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
double b = 2.; char beq[] = "2";
double a = 0.; char aeq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
||
{{Fichier|fd.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as fd.h */
/* ---------------------------------- */
#define LOOP 2*100
/* ---------------------------------- */
double g(
double r,
double k)
{
return( (7. - 7./25. * r*r) );
}
char geq[] = "7 - 7./25 * r**2";
/* ---------------------------------- */
/* ---------------------------------- */
double v(
double r)
{
return( (2*PI) );
}
char veq[] = "2*Pi";
/* ---------------------------------- */
double u(
double r)
{
return( (0) );
}
char ueq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
double b = 5.; char beq[] = "5";
double a = 0.; char aeq[] = "0";
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
|-
|
||
|}
{{AutoCat}}
4i3hqie5z07508jnn5bml7jgq71wfcm
Mathc initiation/Fichiers h : c51a1
0
76622
762756
713812
2026-04-02T07:47:41Z
Xhungab
23827
762756
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer ce fichier dans votre répertoire de travail.
{{Fichier|x_afile.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as x_afile.h */
/* ---------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#include <string.h>
/* ---------------------------------- */
#include "x_def.h"
#include "x_strcp.h"
/* ---------------------------------- */
#include "x_fxy.h"
#include "x_sdrk.h"
#include "x_sdkr.h"
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
{{AutoCat}}
7govokye6xi1m16ce3j1sqjvo656fco
Mathc initiation/Fichiers h : c51a5
0
76626
762757
713813
2026-04-02T07:49:51Z
Xhungab
23827
762757
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer ce fichier dans votre répertoire de travail.
{{Fichier|x_sdrk.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as x_sdrk.h */
/* ---------------------------------- */
double Sint_drdk(
double (*P_g)(double r, double k),
double (*P_u)(double k),
double (*P_v)(double k),
int nr,
double k
)
{
pt2d p;
int i = 0;
double m = 0.;
double M = 0.;
for(i = 0; i <= nr; i++)
{
if(i ==0 || i== nr){m = 1.;}
else if(fmod(i,2) == 0 ){m = 2.;}
else {m = 4.;}
p.x = ((*P_u)(k))+
i*(((*P_v)(k))-((*P_u)(k)))/nr;
p.y = k;
M += m * (sqrt( pow(fxy_x((*P_g),H,p),2) +
pow(fxy_y((*P_g),H,p),2) +
1) *
p.x) ;
}
return( ((((*P_v)(k))-((*P_u)(k)))*M)
/ (3*nr) );
}
/* ---------------------------------- */
double S_drdk(
double (*P_g)(double r, double k),
double (*P_u)(double k),
double (*P_v)(double k),
int nr,
double ak,
double bk,
int nk
)
{
int i = 0;
double m = 0.;
double M = 0.;
for(i = 0; i <= nk; i++)
{
if(i ==0 || i== nk){m = 1.;}
else if(fmod(i,2) == 0 ){m = 2.;}
else {m = 4.;}
M += m * Sint_drdk((*P_g),
(*P_u),(*P_v),nr,
(ak+i*(bk-ak)/nk));
}
return( ((bk -ak)*M) / (3*nk) );
}
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
{{AutoCat}}
sm4x9zk0gtr2yuspklicseqo26011mw
Mathc initiation/Fichiers h : c51a6
0
76627
762758
713814
2026-04-02T07:50:43Z
Xhungab
23827
762758
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer ce fichier dans votre répertoire de travail.
{{Fichier|x_sdkr.h|largeur=70%|info=|icon=Crystal Clear mimetype source h.png}}
<syntaxhighlight lang="c">
/* ---------------------------------- */
/* save as x_sdkr.h */
/* ---------------------------------- */
double Sint_dkdr(
double (*P_g)(double r, double k),
double (*P_u)(double r),
double (*P_v)(double r),
int nk,
double r
)
{
pt2d p;
int i = 0;
double m = 0.;
double M = 0.;
for(i = 0; i <= nk; i++)
{
if(i ==0 || i== nk){m = 1.;}
else if(fmod(i,2) == 0 ){m = 2.;}
else {m = 4.;}
p.y = ((*P_u)(r))+
i*(((*P_v)(r))-((*P_u)(r)))/nk;
p.x = r;
M += m * (sqrt(pow(fxy_x((*P_g),H,p),2) +
pow(fxy_y((*P_g),H,p),2) +
1) *
p.x);
}
return( ((((*P_v)(r))-((*P_u)(r)))*M)
/ (3*nk) );
}
/* ---------------------------------- */
double S_dkdr(
double (*P_g)(double r, double k),
double (*P_u)(double r),
double (*P_v)(double r),
int nk,
double ar,
double br,
int nr
)
{
int i = 0;
double m = 0.;
double M = 0.;
for(i = 0; i <= nr; i++)
{
if(i ==0 || i== nr){m = 1.;}
else if(fmod(i,2) == 0 ){m = 2.;}
else {m = 4.;}
M += m * Sint_dkdr((*P_g),
(*P_u),(*P_v),nk,
(ar + i*(br-ar)/nr));
}
return( ((br -ar)*M) / (3*nr) );
}
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
{{AutoCat}}
4lfxjq7jpbz53l632j6blxocboxqgav
Mathc initiation/Fichiers h : c52a1
0
76633
762761
736231
2026-04-02T07:58:51Z
Xhungab
23827
762761
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer et compiler ces fichiers dans votre répertoire de travail.
{{Fichier|c00a.c|largeur=70%|info=|icon=Crystal128-source-c.svg}}
<syntaxhighlight lang="c">
/* --------------------------------- */
/* save as c00a.c */
/* --------------------------------- */
#include "x_afile.h"
#include "fa.h"
/* --------------------------------- */
int main(void)
{
clrscrn();
printf(" Find the surface area for the given functions\n");
printf(" g : (r,k)-> %s\n\n", geq);
printf(" v : (k)-> %s \n", veq);
printf(" u : (k)-> %s\n\n", ueq);
printf(" b = %+.1f\n a = %+.1f\n\n\n",b,a);
printf(" Polar form : (* r)\n\n\n");
printf(" (b (v(k)\n");
printf(" int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) drdk = %.6f\n",
S_drdk(g, u,v,LOOP, a,b,LOOP));
printf(" (a (u(k)\n\n\n");
stop();
return 0;
}
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Find the surface area for the given functions
g : (r,k)-> 4 - r**2
v : (k)-> 2
u : (k)-> 0
b = +1.6
a = +0.0
Polar form : (* r)
(b (v(k)
int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) drdk = 9.044226
(a (u(k)
Press return to continue.
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Verify with maple
> restart:
>
> g := (r,k)->4-r^2:
> Int(
> Int(
>
> sqrt( (diff(g(r,k),r)^2 + diff(g(r,k),k)^2 + 1) ) * r,
>
> r = 0 .. 2),
> k = 0 .. Pi/2);
1/2 Pi 2
/ /
| | 2
| | sqrt(4 r + 1) r dr dk
| |
/ /
0 0
> evalf(value(%));
>
9.044225805
>
</syntaxhighlight>
{{AutoCat}}
qlnukz109aqqn1106877xtsvo9dexrd
Mathc initiation/Fichiers h : c52a5
0
76637
762762
736235
2026-04-02T08:01:14Z
Xhungab
23827
762762
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer et compiler ces fichiers dans votre répertoire de travail.
{{Fichier|c00b.c|largeur=70%|info=|icon=Crystal128-source-c.svg}}
<syntaxhighlight lang="c">
/* --------------------------------- */
/* save as c00b.c */
/* --------------------------------- */
#include "x_afile.h"
#include "fb.h"
/* --------------------------------- */
int main(void)
{
clrscrn();
printf(" Find the surface area for the given functions\n");
printf(" g : (r,k)-> %s\n\n", geq);
printf(" v : (k)-> %s \n", veq);
printf(" u : (k)-> %s\n\n", ueq);
printf(" b = %+.1f\n a = %+.1f\n\n\n",b,a);
printf(" Polar form : (* r)\n\n\n");
printf(" (b (v(k)\n");
printf(" int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) drdk = %.6f\n",
S_drdk(g, u,v,LOOP, a,b,LOOP));
printf(" (a (u(k)\n\n\n");
stop();
return 0;
}
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Find the surface area for the given functions
g : (r,k)-> 7 - 7./25 * r**2
v : (k)-> 5
u : (k)-> 0
b = +6.3
a = +0.0
Polar form : (* r)
(b (v(k)
int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) drdk = 168.855326
(a (u(k)
Press return to continue.
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Verify with maple
> restart:
>
> g := (r,k)-> 7-7/25*r^2:
> Int(
> Int(
>
> sqrt( (diff(g(r,k),r)^2 + diff(g(r,k),k)^2 + 1) ) * r,
>
> r = 0 .. 5),
> k = 0 .. 2*Pi);
2 Pi 5
/ /
| | 2
| | 1/25 sqrt(196 r + 625) r dr dk
| |
/ /
0 0
> evalf(value(%));
>
168.8553261
>
</syntaxhighlight>
----
{{AutoCat}}
jv9jtair4d5oklrqtwjp32fuyllwpig
Mathc initiation/Fichiers h : c52a6
0
76638
762763
736236
2026-04-02T08:02:45Z
Xhungab
23827
762763
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer et compiler ces fichiers dans votre répertoire de travail.
{{Fichier|c00c.c|largeur=70%|info=|icon=Crystal128-source-c.svg}}
<syntaxhighlight lang="c">
/* --------------------------------- */
/* save as c00c.c */
/* --------------------------------- */
#include "x_afile.h"
#include "fc.h"
/* --------------------------------- */
int main(void)
{
clrscrn();
printf(" Find the surface area for the given functions\n");
printf(" g : (r,k)-> %s\n\n", geq);
printf(" v : (r)-> %s \n", veq);
printf(" u : (r)-> %s\n\n", ueq);
printf(" b = %+.1f\n a = %+.1f\n\n\n",b,a);
printf(" Polar form : (* r)\n\n\n");
printf(" (b (v(r)\n");
printf(" int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) dkdr = %.6f\n",
S_dkdr(g, u,v,LOOP, a,b,LOOP));
printf(" (a (u(r)\n\n\n");
stop();
return 0;
}
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Find the surface area for the given functions
g : (r,k)-> 4 - r**2
v : (r)-> Pi/2
u : (r)-> 0
b = +2.0
a = +0.0
Polar form : (* r)
(b (v(r)
int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) dkdr = 9.044226
(a (u(r)
Press return to continue.
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Verify with maple
> restart:
>
> g := (r,k)->4-r^2:
> Int(
> Int(
>
> sqrt( (diff(g(r,k),r)^2 + diff(g(r,k),k)^2 + 1) ) * r,
>
> k = 0 .. Pi/2),
> r = 0 .. 2);
2 1/2 Pi
/ /
| | 2
| | sqrt(4 r + 1) r dk dr
| |
/ /
0 0
> evalf(value(%));
>
9.044225803
>
</syntaxhighlight>
----
{{AutoCat}}
lq6hvjzv9ldfa0lquv3q399249s3sh5
Mathc initiation/Fichiers h : c53a1
0
76644
762764
736240
2026-04-02T08:04:27Z
Xhungab
23827
762764
wikitext
text/x-wiki
[[Catégorie:Mathc initiation (livre)]]
[[Mathc initiation/Fichiers h : c53a5| Sommaire]]
Installer et compiler ces fichiers dans votre répertoire de travail.
{{Fichier|c00d.c|largeur=70%|info=|icon=Crystal128-source-c.svg}}
<syntaxhighlight lang="c">
/* --------------------------------- */
/* save as c00d.c */
/* --------------------------------- */
#include "x_afile.h"
#include "fd.h"
/* --------------------------------- */
int main(void)
{
clrscrn();
printf(" Find the surface area for the given functions\n");
printf(" g : (r,k)-> %s\n\n", geq);
printf(" v : (r)-> %s \n", veq);
printf(" u : (r)-> %s\n\n", ueq);
printf(" b = %+.1f\n a = %+.1f\n\n\n",b,a);
printf(" Polar form : (* r)\n\n\n");
printf(" (b (v(r)\n");
printf(" int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) dkdr = %.6f\n",
S_dkdr(g, u,v,LOOP, a,b,LOOP));
printf(" (a (u(r)\n\n\n");
stop();
return 0;
}
/* ---------------------------------- */
/* ---------------------------------- */
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Find the surface area for the given functions
g : (r,k)-> 7 - 7./25 * r**2
v : (r)-> 2*Pi
u : (r)-> 0
b = +5.0
a = +0.0
Polar form : (* r)
(b (v(r)
int( int( sqrt(g_r()**2 + g_k()**2 + 1) (* r) dkdr = 168.855326
(a (u(r)
Press return to continue.
</syntaxhighlight>
'''Exemple de sortie écran :'''
<syntaxhighlight lang="C">
Verify with maple
> restart:
>
> g := (r,k)-> 7-7/25*r^2:
> Int(
> Int(
>
> sqrt( (diff(g(r,k),r)^2 + diff(g(r,k),k)^2 + 1) ) * r,
>
> k = 0 .. 2*Pi),
> r = 0 .. 5);
5 2 Pi
/ /
| | 2
| | 1/25 sqrt(196 r + 625) r dk dr
| |
/ /
0 0
> evalf(value(%));
>
168.8553261
>
</syntaxhighlight>
{{AutoCat}}
tijaylc5lqtp20gdopa1f8zxy5g6mew
Fonctionnement d'un ordinateur/La hiérarchie mémoire
0
78257
762734
755760
2026-04-01T15:44:54Z
Mewtow
31375
/* Les principes de localité spatiale et temporelle */
762734
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
Les architectures à accumulateur étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide, ce qui permettait de se passer de hiérarchie mémoire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeur sont devenus plus rapides que la mémoire RAM. Et pour s'adapter, ils ont évolués pour accueillir plus de registres.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
snplx6holpbla6565tq4kyix1owpk5w
762736
762734
2026-04-01T15:45:16Z
Mewtow
31375
/* Introduction historique : les processeurs à accumulateur */
762736
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
2ty5g6ohhgnyo17hoi4lsraiqhkdt5d
762737
762736
2026-04-01T15:46:27Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762737
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide, ce qui permettait de se passer de hiérarchie mémoire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeur sont devenus plus rapides que la mémoire RAM. Et pour s'adapter, ils ont évolués pour accueillir plus de registres. Et l'ajout de registres a eu des conséquences assez importante sur la manière dont le processeur fonctionne. Notamment, les programmeurs et compilateur ont du s'adapter à la présence de plusieurs registres, à savoir qu'ils doivent utiliser les registres de données explicitement, comme ils le feraient pour la RAM.
Les architectures à accumulateur sont sous-optimales, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
mamgcmg9n0svv91lbrb07yd2s226vfp
762738
762737
2026-04-01T15:50:02Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762738
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide, ce qui permettait de se passer de hiérarchie mémoire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeur sont devenus plus rapides que la mémoire RAM. Et pour s'adapter, ils ont évolués pour accueillir plus de registres. Et l'ajout de registres a eu des conséquences assez importante sur la manière dont le processeur fonctionne. Notamment, les programmeurs et compilateur ont du s'adapter à la présence de plusieurs registres, à savoir qu'ils doivent utiliser les registres de données explicitement, comme ils le feraient pour la RAM.
La mémoire RAM étant devenue plus lente, les processeur doivent éviter de faire des accès mémoire à chaque instruction. Par exemple, prenons une mémoire 5 fois plus lente que le processeur. Concrètement, imaginons que la mémoire RAM mette 5 cycles d'horloge pour lire une donnée, alors que le processeur met un cycle d'horloge pour exécuter une instruction (lecture des opérande exclue). Dans ce cas, le seul moyen pour gagner en performance est que seule une instruction sur 5 accède à la mémoire.
Mais les processeurs à accumulateur ne permettent pas cela, il y a un accès mémoire par instruction, pour lire une opérande. Ils sont sous-optimaux, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première.
Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les numéros de registre sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette posibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
d3q46ikyefdtonm79vokamrcg1ad3p6
762739
762738
2026-04-01T15:52:40Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762739
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide, ce qui permettait de se passer de hiérarchie mémoire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeur sont devenus plus rapides que la mémoire RAM. Et pour s'adapter, ils ont évolués pour accueillir plus de registres. Et l'ajout de registres a eu des conséquences assez importante sur la manière dont le processeur fonctionne. Notamment, les programmeurs et compilateur ont du s'adapter à la présence de plusieurs registres, à savoir qu'ils doivent utiliser les registres de données explicitement, comme ils le feraient pour la RAM.
La mémoire RAM étant devenue plus lente, les processeur doivent éviter de faire des accès mémoire à chaque instruction. Par exemple, prenons une mémoire 5 fois plus lente que le processeur. Concrètement, imaginons que la mémoire RAM mette 5 cycles d'horloge pour lire une donnée, alors que le processeur met un cycle d'horloge pour exécuter une instruction (lecture des opérande exclue). Dans ce cas, le seul moyen pour gagner en performance est que seule une instruction sur 5 accède à la mémoire.
Mais les processeurs à accumulateur ne permettent pas cela, il y a un accès mémoire par instruction, pour lire une opérande. Ils sont sous-optimaux, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première. Les processeurs RISC sont donc plus simples, dans le sens où toutes les instructions de calcul savent que leurs opérandes sont dans les registres. Les processeurs CISC, par contre, doivent préciser dans quel cas ils sont. La solution la plus simple utilise un bit, intégré dans l'instruction, qui dit dans quel cas l'instruction est. Une autre solution assez similaire utilise deux instructions différentes, selon la position de l'opérande dans l'ordinateur.
Mais ce n'est pas le seul problème que les processeurs doivent résoudre. Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les '''numéros de registre''' sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
Autre problème : les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette possibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
Un point important est qu'il y a plusieurs registres généraux, au lieu d'un accumulateur unique. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Pour ceux qui se rappellent du chapitre "Les registres et mémoires adressables", nous avons déjà vu comment créer un banc de registre. Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire.
Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Au final, on a deux multiplexeurs, un par sortie de lecture, un par entrée de l'unité de calcul. Les multiplexeurs et le démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Ils sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
0kmot6lifk9ubu0tz98cbh2c0zn7evx
762740
762739
2026-04-01T15:55:01Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762740
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide, ce qui permettait de se passer de hiérarchie mémoire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeur sont devenus plus rapides que la mémoire RAM. Et pour s'adapter, ils ont évolués pour accueillir plus de registres. Et l'ajout de registres a eu des conséquences assez importante sur la manière dont le processeur fonctionne. Notamment, les programmeurs et compilateur ont du s'adapter à la présence de plusieurs registres, à savoir qu'ils doivent utiliser les registres de données explicitement, comme ils le feraient pour la RAM.
La mémoire RAM étant devenue plus lente, les processeur doivent éviter de faire des accès mémoire à chaque instruction. Par exemple, prenons une mémoire 5 fois plus lente que le processeur. Concrètement, imaginons que la mémoire RAM mette 5 cycles d'horloge pour lire une donnée, alors que le processeur met un cycle d'horloge pour exécuter une instruction (lecture des opérande exclue). Dans ce cas, le seul moyen pour gagner en performance est que seule une instruction sur 5 accède à la mémoire.
Mais les processeurs à accumulateur ne permettent pas cela, il y a un accès mémoire par instruction, pour lire une opérande. Ils sont sous-optimaux, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première. Les processeurs RISC sont donc plus simples, dans le sens où toutes les instructions de calcul savent que leurs opérandes sont dans les registres. Les processeurs CISC, par contre, doivent préciser dans quel cas ils sont. La solution la plus simple utilise un bit, intégré dans l'instruction, qui dit dans quel cas l'instruction est. Une autre solution assez similaire utilise deux instructions différentes, selon la position de l'opérande dans l'ordinateur.
Mais ce n'est pas le seul problème que les processeurs doivent résoudre. Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les '''numéros de registre''' sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
L'intérieur du processeur est aussi modifié de manière à tenir compte de la présence de plusieurs registres. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Nous avons déjà vu comment créer un banc de registre, dans le chapitre nommé "Les registres et mémoires adressables". Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Les multiplexeurs/démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Les numéros de registre sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
Autre problème : les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette possibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme. Elle est alors soit calculée, soit lue depuis la mémoire RAM, soit déterminée autrement. Toujours est-il qu'elle se retrouve dans un registre général.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
44rwlyiyppabzo9nso25mtmifso9rx3
762743
762740
2026-04-01T16:16:01Z
Mewtow
31375
/* Les processeurs modernes : les processeurs à registres généraux */
762743
wikitext
text/x-wiki
Sur la plupart des systèmes embarqués ou des tous premiers ordinateurs, on n'a que deux mémoires : une mémoire RAM et une mémoire ROM, comme indiqué dans le chapitre précédent. Mais ces systèmes sont très simples et peuvent se permettre d'implémenter l'architecture de base sans devoir y ajouter quoi que ce soit. Ce n'est pas le cas sur les ordinateurs plus puissants.
Un ordinateur moderne ne contient pas qu'une seule mémoire, mais plusieurs. Entre le disque dur, la mémoire RAM, les différentes mémoires cache, et autres, il y a de quoi se perdre. Et de plus, toutes ces mémoires ont des caractéristiques, voire des fonctionnements totalement différents. Certaines mémoires seront très rapides, d'autres auront une grande capacité mémoire (elles pourront conserver beaucoup de données), certaines s'effacent quand on coupe le courant et d'autres non.
La raison à cela est que plus une mémoire peut contenir de données, plus elle est lente. On doit faire le choix entre une mémoire de faible capacité et très performante, ou une mémoire très performante mais très petite. Les cas intermédiaires, avec une capacité et des performances intermédiaires, existent aussi. Le fait est que si l'on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait trop lente et l'ordinateur serait inutilisable. Pour résoudre ce problème, il suffit d'utiliser plusieurs mémoires de taille et de vitesse différentes, qu'on utilise suivant les besoins. Des mémoires très rapides de faible capacité seconderont des mémoires lentes de capacité importante.
Finalement, l'architecture d'un ordinateur moderne diffère de l'architecture de base par la présence d'une grande quantité de mémoires, organisées sous la forme d'une hiérarchie qui va des mémoires très rapides mais très petites à des mémoires de forte capacité très lentes. Le reste de l’architecture ne change pas trop par rapport à l'architecture de base : on a toujours un processeur, des entrées-sorties, un bus de communication, et tout ce qui s'en suit. Les mémoires d'un ordinateur moderne sont les suivantes :
{|class="wikitable"
|-
! Type de mémoire
! Temps d'accès
! Capacité
! Relation avec la mémoire primaire/secondaire
|-
| Registres
| 1 nanosecondes
| Entre 1 et 512 bits
| Mémoire incorporée dans le processeur
|-
| Caches
| 10 - 100 nanosecondes
| Kibi- ou mébi-octets
| Mémoire incorporée dans le processeur, sauf pour d'anciens processeurs
|-
| Mémoire RAM
| 1 microsecondes
| Gibioctets
| Mémoire primaire
|-
| Mémoires de masse (Disque dur, disque SSD, autres)
| 1 millisecondes
| Dizaines à centaines de gibioctets
| Mémoire secondaire
|}
Précisons cependant que le compromis capacité-performance n'est pertinent que quand on compare des mémoires avec des capacités très différentes, avec au moins un ordre de grandeur de différence. Entre un ordinateur avec 16 gibioctets de RAM et un autre avec 64 gibioctets, les différences de performances sont marginales. Par contre, la différence entre un cache de quelques mébioctets et une RAM de plusieurs gibioctets, la différence est très importante. Ce qui fait que l'ensemble des mémoires de l'ordinateur est organisé en plusieurs niveaux, avec des registres ultra-rapides, des caches intermédiaires, une mémoire RAM un peu lente, et des mémoires de masse très lentes.
==La distinction entre mémoire primaire et secondaire==
La première amélioration de l'architecture de base consiste à rajouter un niveau de mémoire. Il n'y a alors que deux niveaux de mémoire : les '''mémoires primaires''' directement accessibles par le processeur, et la '''mémoire secondaire''' accessible comme les autres périphériques. La mémoire primaire, correspond aux mémoire RAM et ROM de l'ordinateur, dans laquelle se trouvent les programmes en cours d’exécution et les données qu'ils manipulent. Les mémoires secondaires correspondent aux disques durs, disques SSD, clés USB et autres. Ce sont des périphériques connectés sur la carte mère ou via un connecteur externe.
[[File:CPT-System-Architecture-Stored-Program.svg|centre|vignette|upright=2|Distinction entre mémoire primaire et mémoire secondaire.]]
Les mémoires secondaires sont généralement confondues avec les '''mémoires de masse''', des mémoires de grande capacité qui servent à stocker de grosses quantités de données. De plus, elles conservent des données qui ne doivent pas être effacés et sont donc des mémoire de stockage permanent (on dit qu'il s'agit de mémoires non-volatiles). Concrètement, elles conservent leurs données mêmes quand l'ordinateur est éteint et ce pendant plusieurs années, voir décennies. Les disques durs, mais aussi les CD/DVD et autres clés USB sont des mémoires de masse.
Du fait de leur grande capacité, les mémoires de masse sont très lentes. Leur lenteur pachydermique fait qu'elles n'ont pas besoin de communiquer directement avec le processeur, ce qui fait qu'il est plus pratique d'en faire de véritables périphériques, plutôt que de les souder/connecter sur la carte mère. C'est la raison pour laquelle mémoires de masse et mémoires secondaires sont souvent confondues.
Les mémoires de masse se classent en plusieurs types : les mémoires secondaires proprement dit, les mémoires tertiaires et les mémoires quaternaires. Toutes sont traitées comme des périphériques par le processeur, la différence étant dans l’accessibilité.
* Une '''mémoire secondaire''' a beau être un périphérique, elle est située dans l'ordinateur, connectée à la carte mère. Elle s'allume et s'éteint en même temps que l'ordinateur et est accessible tant que l'ordinateur est allumé. Les disques durs et disques SSD sont dans ce cas.
* Une '''mémoire tertiaire''' est un véritable périphérique, dans le sens où on peut l'enlever ou l'insérer dans un connecteur externe à loisir. Par exemple, les clés USB, les CD/DVD ou les disquettes sont dans ce cas. Une mémoire tertiaire est donc rendue accessible par une manipulation humaine, qui connecte la mémoire à l'ordinateur. Le système d'exploitation doit alors effectuer une opération de montage (connexion du périphérique à l’ordinateur) ou de démontage (retrait du périphérique).
* Quant aux '''mémoires quaternaires''', elles sont accessibles via le réseau, comme les disques durs montés en ''cloud''.
===Les technologies de fabrication des mémoires secondaires sont à part===
Les mémoires de masse sont par nature des mémoires non-volatiles, à savoir qui ne s'effacent pas quand on coupe l'alimentation électrique, à l'opposé des mémoires RAM qui elles s'effacent quand on coupe le courant. Et ce fait nous dit quelque chose de très important : les mémoires de masse ne sont pas fabriquées de la même manière que les mémoires volatiles.
Les mémoires volatiles sont presque toutes électroniques, à quelques exceptions qui appartiennent à l'histoire de l'informatique. Elles sont fabriquées avec des transistors, que ce soit des transistors CMOS ou bipolaire. Et quand on cesse de l'alimenter en courant, les transistors repasse en état inactif, de repos, qui est soit fermé ou ouvert. Ils ne mémorisent pas l'état qu'ils avaient avant qu'on coupe le courant. On ne peut donc pas fabriquer de mémoire non-volatile avec des transistors ! Et ce genre de chose vaut pour les ancêtres du transistors, comme les thrysistors, les triodes, les tubes à vide et autres : ils permettaient de fabriquer des mémoires volatiles, mais rien d'autres.
: Les mémoires ROM ne sont pas concernées par ce problème vu que ce sont de simples circuits combinatoires, qui n'ont pas besoin d'avoir de capacité de mémorisation proprement dit. Elles sont donc non-volatiles, mais le fait qu'on ne puisse pas modifier leur contenu rend la solution aisée.
Aussi, pour fabriquer des mémoires de masse, on doit utiliser des technologies différentes, on ne peut pas utiliser de transistors CMOS ou bipolaire normaux. Et le moins qu'on puisse dire est que les technologies des mémoires de masse sont très nombreuses, absolument tous les supports de mémorisation possibles ont été essayés et commercialisés. L'évolution des technologies de fabrication est difficile à résumer pour les mémoires de masse. Mais dans les grandes lignes, on peut distinguer quatre grandes technologies.
La solution la plus ancienne était d'utiliser un support papier, avec les cartes perforées. Mais cette solution a rapidement été remplacée par l'usage de d'un support de mémorisation magnétique, à savoir que chaque bit était attribué à un petit morceau de matériau magnétique. Le matériau magnétique peut être magnétisé dans deux sens N-S ou S-N, ce qui permet d'encoder un bit. C'est ainsi que sont nées les toutes premières mémoire de masse magnétique : les bandes magnétiques (similaires à celles utilisées dans les cassettes audio), les tambours magnétiques, les mémoires à tore de ferrite, et quelques autres. Par la suite, sont apparues les disquettes et les disques durs.
Par la suite, les CD-ROM, puis les DVD sont apparus sur le marchés. Ils sont regroupés sous le terme de mémoires optiques, car leur fonctionnement utilise les propriétés optiques du support de mémorisation, on les lit en faisant passer un laser très fin dessus. Ils n'ont cependant pas remplacé les disques durs, leur usage était tout autre. En effet, les mémoires optiques ne peuvent pas être effacées et réécrites. Sauf dans le cas des CD/DVD réincriptibles, mais on ne peut les effacer qu'un nombre limité de fois, mettons une dizaine. De plus, il faut les effacer intégralement avant de réécrire complétement leur contenu. Cette limitation fait qu'ils n'étaient pas utilisés pour mémoriser le système d'exploitation ou les programmes installés.
Toutes ces mémoires sont totalement obsolètes de nos jours, à l'exception des disques durs magnétiques. Et encore ces derniers tendent à disparaitre. Les mémoires de masse actuelles sont toutes... électroniques ! J'ai dit plus haut qu'il n'était pas possible de fabriquer des mémoires de masse/secondaires avec des transistors CMOS, je n'ai pas mentit. Les mémoires électronique actuelle sont des mémoires FLASH, qui sont fabriquées avec des transistors CMOS à grille flottante. Leur fonctionnement est différent des transistors CMOS normaux, ils ont une capacité de mémorisation que les transistors CMOS normaux n'ont pas. Par contre, leur procédé de fabrication est différent, ils ne sont pas fabriqués dans les mêmes usines que les transistors CMOS normaux.
===Le démarrage de l'ordinateur à partir d'une mémoire secondaire===
L'ajout de deux niveaux de mémoire pose quelques problèmes pour le démarrage de l'ordinateur : comment charger les programmes depuis un périphérique ?
Les tout premiers ordinateurs pouvaient démarrer directement depuis un périphérique. Ils étaient conçus pour cela, directement au niveau de leurs circuits. Ils pouvaient automatiquement lire un programme depuis une carte perforée ou une mémoire magnétique, et le copier en mémoire RAM. Par exemple, l'IBM 1401 lisait les 80 premiers caractères d'une carte perforée et les copiait en mémoire, avant de démarrer le programme copié. Si un programme faisait plus de 80 caractères, les 80 premiers caractères contenaient un programme spécialisé, appelé le '''chargeur d’amorçage''', qui s'occupait de charger le reste. Sur l'ordinateur Burroughs B1700, le démarrage exécutait automatiquement le programme stocké sur une cassette audio, instruction par instruction.
Les processeurs "récents" ne savent pas démarrer directement depuis un périphérique. À la place, ils contiennent une mémoire ROM utilisée pour le démarrage, qui contient un programme qui charge les programmes depuis le disque dur. Rappelons que la mémoire ROM est accessible directement par le processeur.
Sur les premiers ordinateurs avec une mémoire secondaire, le programme à exécuter était en mémoire ROM et la mémoire secondaire ne servait que de stockage pour les données. Le système d'exploitation était dans la mémoire ROM, ce qui fait que l'ordinateur pouvait démarrer même sans mémoire secondaire. La mémoire secondaire était utilisée pour stocker données comme programmes à exécuter. Les programmes à utiliser étaient placés sur des disquettes, des cassettes audio, ou tout autre support de stockage. Les premiers ordinateurs personnels, comme les Amiga, Atari et Commodore, étaient de ce type.
Par la suite, le système d'exploitation aussi a été déporté sur la mémoire secondaire, à savoir qu'il est installé sur le disque dur, voire un SSD. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les logiciels que vous utilisez au quotidien sont mémorisés sur le disque dur. Mais vu qu'aucun ordinateur ne démarre directement depuis le disque dur ou une clé USB, il y a forcément une mémoire ROM dans un ordinateur moderne, qui n'est autre que le BIOS sur les ordinateurs anciens, l'UEFI sur les ordinateurs récents. Elle est utilisée lors du démarrage de l'ordinateur pour le configurer à l'allumage et démarrer son système d'exploitation. La ROM en question ne sert donc qu'au démarrage de l'ordinateur, avant que le système d'exploitation prenne la relève. L'avantage, c'est qu'on peut modifier le contenu du disque dû assez facilement, tandis que ce n'est pas vraiment facile de modifier le contenu d'une ROM (et encore, quand c'est possible). On peut ainsi facilement installer ou supprimer des programmes, en rajouter, en modifier, les mettre à jour sans que cela ne pose problème.
Le fait de mettre les programmes et le système d'exploitation sur des mémoires secondaire a quelques conséquences. La principale est que le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez. Impossible de faire autrement pour les exécuter. Les systèmes de ce genre sont donc des architectures de type ''Von Neumann'' ou de type ''Harvard modifiée'', qui permettent au processeur d’exécuter du code depuis la RAM. Vu que le programme s’exécute en mémoire RAM, l'ordinateur n'a aucun moyen de séparer données et instructions, ce qui amène son lot de problèmes, comme nous l'avons dit au chapitre précédent.
[[File:CPT-Von neumann architecture.svg|centre|vignette|upright=2|Ce schéma illustre l'organisation mémoire d'un ordinateur moderne, en très simplifié. On voit qu'il y a un disque dur (mémoire secondaire), qui contient le système d'exploitation. La RAM et la ROM sont toutes deux reliées au processeur par un bus unique. La ROM contient le ''firmware/BIOS'', ainsi qu'un chargeur d'amorcage qui permet de charger l'OS dans la RAM. Le processeur, quant à lui, contient divers circuits que vous ne connaissez pas encore. Contentons-nous de dire qu'il contient plusieurs mémoires caches, ainsi que des registres (en violet).]]
==L'ajout des mémoires caches et des ''local stores''==
[[File:Scratch-Pad-Memory.jpg|vignette|Illustration des mémoires caches et des ''local stores''. Le cache est une mémoire spécialisée, de type SRAM, intercalée entre la RAM et le processeur. Les ''local stores'' sont dans le même cas, mais ils sont composés du même type de mémoire que la mémoire principale (ce qui fait qu'ils sont abusivement mis au même niveau sur ce schéma).]]
La hiérarchie mémoire d'un ordinateur moderne est une variante de la hiérarchie à deux niveaux de la section précédente (primaire et secondaire) à laquelle on a rajouté une ou plusieurs mémoires intermédiaires. Le niveau intermédiaire entre les registres et la mémoire principale regroupe deux types distincts de mémoires : les mémoires caches et les ''local stores''. Les premiers sont des mémoires qui ne sont pas adressables et fonctionnent très différemment des mémoires RAM et ROM normales. Leur fonctionnement sera expliqué rapidement dans la section suivante, et détaillé dans un chapitre à part. À l'opposé, les ''local store'' sont des mémoires RAM adressables, très semblables à la mémoire principale, mais avec une plus fiable capacité et une vitesse plus importante.
Le rajout de ces niveaux supplémentaires est une question de performance. Les processeurs anciens pouvaient se passer de mémoires caches. Mais au fil du temps, les processeurs ont gagné en performances plus rapidement que la mémoire RAM et les processeurs ont incorporé des mémoires caches pour compenser la différence de vitesse entre processeur et mémoire RAM. Les caches sont beaucoup plus utilisés que les ''local store'', ces derniers étant absent des processeurs commerciaux modernes, sauf peut-être dans quelques CPU dédiés aux applications embarquées. Ils sont présents dans les cartes graphiques modernes, l'ont été dans le CPU de la console Playstation 3, mais guère plus. À l'inverse, tous les processeurs disposent d'une ou plusieurs mémoires cache depuis au moins les années 90.
[[File:Hiérarchie mémoire.png|centre|vignette|upright=2.0|Hiérarchie mémoire]]
===Les mémoires caches===
Dans la majorité des cas, la mémoire intercalée entre les registres et la mémoire RAM/ROM est ce qu'on appelle une '''mémoire cache'''. Aussi bizarre que cela puisse paraître, elle n'est jamais adressable ! Le contenu du cache est géré par un circuit spécialisé et le programmeur ne peut pas gérer directement le cache. Le cache contient une copie de certaines données présentes en RAM et cette copie est accessible bien plus rapidement, le cache étant beaucoup plus rapide que la RAM. Tout accès mémoire provenant du processeur est intercepté par le cache, qui vérifie si une copie de la donnée demandée est présente ou non dans le cache. Si c'est le cas, on accède à la copie le cache : on a un '''succès de cache''' (cache hit). Sinon, c'est un '''défaut de cache''' (cache miss) : on est obligé d’accéder à la RAM et/ou de charger la donnée de la RAM dans le cache.
Le fonctionnement interne d'un cache sera expliqué dans le chapitre dédié aux mémoires caches. Pour le moment, tout ce qu'on peut dire est que la majorité des processeurs utilise des caches dit partiellement associatifs. Ils contiennent en leur sein une ou plusieurs mémoire RAM de petite taille, qui sont entourées par des circuits qui font fonctionner le tout comme un cache. Un cache est donc plus complexe qu'une RAM normale, du fait des circuit en plus. Il est plus gourmand en transistors, en consommation énergétique, etc.
Plus haut, on a vu que les mémoires secondaires ne sont pas fabriqués avec les mêmes technologies que les mémoires volatiles/RAM. Il en est de même avec les mémoires caches, ce qui explique la différence de performance entre RAM et cache. Les caches sont plus rapides, non seulement car ils sont plus petits, mais aussi car ils ne sont pas fabriqués comme des mémoires RAM. Les mémoires RAM actuelles sont des mémoires dites DRAM, alors que les caches sont fabriqués avec des mémoires dites SRAM. La différence sera expliquée dans quelques chapitres, retenez simplement que les procédés de fabrication sont différents. La SRAM est rapide, mais a une faible capacité, la DRAM est lente et de forte capacité. La raison est que 1 bit de SRAM prend beaucoup de place et utilise beaucoup de circuits, alors que les DRAM sont plus économes en circuits et en espace.
Les caches peuvent ou non être intégrés au processeur. Il a existé des caches séparés du processeur, connectés sur la carte mère. Un exemple était le cache du processeur Pentium 2, qui avait son propre "socket". Mais de nos jours, les caches sont incorporés au processeur, pour des raisons de performance. Les caches devant être très rapides, avec des temps d'accès proches de la nanoseconde, il fallait réduire drastiquement la distance entre le processeur et ces mémoires. Cela n'a l'air de rien, mais l'électricité met quelques dizaines ou centaines de nanosecondes pour parcourir les connexions entre le processeur et le cache, si le cache est en dehors du processeur. En intégrant les caches dans le processeur, on s'assure que le temps d'accès est minimal, la mémoire étant la plus proche possible des circuits de calcul.
===Les ''local store'' et les caches RAM-configurables===
Sur certains processeurs, les mémoires caches sont remplacées par des mémoires RAM appelées des '''local stores'''. Ce sont des mémoires RAM, identiques à la mémoire RAM principale, mais qui sont plus petites et plus rapides. Contrairement aux mémoires caches, il s'agit de mémoires adressables, ce qui fait qu'elles ne sont plus gérées automatiquement par le processeur : c'est le programme en cours d'exécution qui prend en charge les transferts de données entre local store et mémoire RAM.
Les local stores sont plus économes en circuits et consomment moins d'énergie que les caches à taille équivalente. En effet, ils n'ont pas besoin de circuits compliqués pour gérer automatiquement les échanges avec la RAM, contrairement aux caches. Ils sont adressables, ce qui est assez simple à implémenter avec un décodeur et des registres. Côté inconvénients, ces local stores peuvent entraîner des problèmes de compatibilité : un programme conçu pour fonctionner avec des local stores ne fonctionnera pas sur un ordinateur qui en est dépourvu.
Il faut noter que certains caches peuvent être configurés pour fonctionner comme des ''local store''. En effet, une mémoire cache est souvent fabriquée en prenant une ou plusieurs mémoires SRAM adressables et en ajoutant des circuits autour. Mais il est possible d'utiliser les mémoires SRAM adressables telles quelles, en les adressant directement. Il s'agit de la technique du '''cache RAM-configurable''.
L'usage de cache RAM-configurable est fréquent sur les cartes graphiques récentes. Elles incorporent un ou plusieurs processeurs multicœurs, dont le cache L1 de données est un cache RAM-configurable. Les CPU commerciaux incorporent aussi des caches de ce type, bien que cela ne soit utilisé que lors du démarrage de l'ordinateur. Au démarrage, le BIOS n'a pas immédiatement accès à la mémoire RAM principale, qui demande d'être configurée du fait de technicalités des mémoires DDR. Aussi, le BIOS utilise alors le cache du processeur comme une mémoire RAM. Les registres de configuration du CPU sont configurés de manière à ce que le cache soit utilisé comme ''local store''. Du code s'exécute, vérifie la présence de mémoire RAM, configure le contrôleur DDR, fait quelques manipulations, puis met le cache à l'état normal.
===Les principes de localité spatiale et temporelle===
Utiliser au mieux la hiérarchie mémoire demande placer les données accédées souvent, ou qui ont de bonnes chances d'être accédées dans le futur, dans la mémoire la plus rapide possible. Le tout est de faire en sorte de placer les données intelligemment, et les répartir correctement dans cette hiérarchie des mémoires. Ce placement se base sur deux principes qu'on appelle les principes de localité spatiale et temporelle :
* un programme a tendance à réutiliser les instructions et données accédées dans le passé : c'est la '''localité temporelle''' ;
* et un programme qui s'exécute sur un processeur a tendance à utiliser des instructions et des données consécutives, qui sont proches, c'est la '''localité spatiale'''.
Pour donner un exemple, les instructions d'un programme sont placées en mémoire dans l’ordre dans lequel on les exécute : la prochaine instruction à exécuter est souvent placée juste après l'instruction en cours (sauf avec les branchements). La localité spatiale est donc respectée tant qu'on a pas de branchements qui renvoient assez loin dans la mémoire (appels de sous-programmes). De même, les boucles (des fonctionnalités des langages de programmation qui permettent d’exécuter en boucle un morceau de code tant qu'une condition est remplie) sont un bon exemple de localité temporelle. Les instructions de la boucle sont exécutées plusieurs fois de suite et doivent être lues depuis la mémoire à chaque fois.
On peut exploiter ces deux principes pour placer les données dans la bonne mémoire. Par exemple, si on a accédé à une donnée récemment, il vaut mieux la copier dans une mémoire plus rapide, histoire d'y accéder rapidement les prochaines fois : on profite de la localité temporelle. On peut aussi profiter de la localité spatiale : si on accède à une donnée, autant précharger aussi les données juste à côté, au cas où elles seraient accédées. Ce placement des données dans la bonne mémoire peut être géré par le matériel de notre ordinateur, mais aussi par le programmeur.
De nos jours, le temps que passe le processeur à attendre la mémoire principale devient de plus en plus un problème au fil du temps, et gérer correctement la hiérarchie mémoire est une nécessité, particulièrement sur les processeurs multi-cœurs. Il faut dire que la différence de vitesse entre processeur et mémoire est très importante : alors qu'une simple addition ou multiplication va prendre entre 1 et 5 cycles d'horloge, une lecture en mémoire RAM fera plus dans les 400-1000 cycles d'horloge. Les processeurs modernes utilisent des techniques avancées pour masquer ce temps de latence, qui reviennent à exécuter des instructions pendant ce temps d'attente, mais elles ont leurs limites.
Bien évidement, optimiser au maximum la conception de la mémoire et de ses circuits dédiés améliorera légèrement la situation, mais n'en attendez pas des miracles. Il faut dire qu'il n'y a pas vraiment de solution facile à implémenter. Par exemple, changer la taille d'une mémoire pour contenir plus de données aura un effet désastreux sur son temps d'accès qui peut se traduire par une baisse de performance. Par exemple, les processeurs Nehalem d'Intel ont vus leurs performances dans les jeux vidéos baisser de 2 à 3 % malgré de nombreuses améliorations architecturales très évoluées : la latence du cache L1 avait augmentée de 2 cycles d'horloge, réduisant à néant de nombreux efforts d'optimisations architecturales.
Une bonne utilisation de la hiérarchie mémoire repose en réalité sur le programmeur qui doit prendre en compte les principes de localités vus plus haut dès la conception de ses programmes. La façon dont est conçue un programme joue énormément sur sa localité spatiale et temporelle. Un programmeur peut parfaitement tenir compte du cache lorsqu'il programme, et ce aussi bien au niveau :
* de son algorithme : on peut citer l'existence des algorithmes cache oblivious ;
* du choix de ses structures de données : un tableau est une structure de donnée respectant le principe de localité spatiale, tandis qu'une liste chaînée ou un arbre n'en sont pas (bien qu'on puisse les implémenter de façon à limiter la casse);
* ou de son code source : par exemple, le sens de parcours d'un tableau multidimensionnel peut faire une grosse différence.
Cela permet des gains très intéressants pouvant se mesurer avec des nombres à deux ou trois chiffres. Je vous recommande, si vous êtes programmeur, de vous renseigner le plus possible sur les optimisations de code ou algorithmiques qui concernent le cache : il vous suffira de chercher sur Google. Quoi qu’il en soit, il est quasiment impossible de prétendre concevoir des programmes optimisés sans tenir compte de la hiérarchie mémoire. Et cette contrainte va se faire de plus en plus forte quand on devra passer aux architectures multicœurs.
==Les registres du processeur==
Pour finir ce chapitre, nous allons voir le sommet de la hiérarchie mémoire : les registres du processeur. Il peut paraitre étranger que l'on mette les registres du processeur au sommet. En effet, nous avons vu que le processeur a besoin de registres pour faire son travail. Il a besoin d'un ''program counter'', d'un registre d'instruction, ainsi que d'autres de registres de contrôle. Sans cela, impossible d’exécuter des instructions. Mais il ne s'agit pas des registres dont nous allons parler ici. La hiérarchie mémoire ne se préoccupe des registres qui mémorisent les données. Il pour le coup, voyons voir ce qu'il en est.
===Introduction historique : les processeurs à accumulateur===
Intuitivement, on se dit que si les registres de données font partie de la hiérarchie mémoire, c'est que certains processeurs peuvent faire sans. Reste à voir si c'est possible. Rappelons que la RAM et les registres sont surtout utilisés par les instructions de calcul. Elles mémorisent les opérandes et les résultats des instructions de calcul. Pour se passer de registres, rien de bien sorcier : il suffit de lire les opérandes dans la mémoire RAM, puis d'enregistrer le résultat là aussi en RAM. Cependant, bien qu'intuitive, cette solution a un gros problème.
La majorité des opérations, comme l'addition ou la multiplication ont deux opérandes. Elles sont dites ''dyadiques''. Pour les exécuter, le processeur doit lire deux opérandes en même temps, puis écrire le résultat. Mais les mémoires RAM ne peuvent faire qu'un seul accès à la fois, ce qui implique qu'elles ne peuvent pas lire deux opérandes à la fois.
Du moins, les mémoires RAM utilisées comme mémoire principale ne peuvent pas le faire. Il existe des mémoires dites multiports, qui peuvent faire plusieurs accès mémoire à la fois. Il existe des mémoires capables de faire deux lectures et une écriture, ce qui collerait parfaitement pour les instructions dyadiques. Le problème, c'est que les mémoires de ce genre sont presque toutes des mémoires SRAM. En clair, elles servent pour la mémoire cache ou pour les registres du processeur, mais pas comme mémoire principale. Le problème est donc entier : la mémoire principale ne permet de lire qu'une seule opérande à la fois.
[[File:Isaccumulator.png|vignette|Processeur avec un accumulateur.]]
Il y a donc un problème qu'il faut résoudre. Et il n'a pas 36 solutions, le seul moyen de le résoudre est de lire les deux opérandes l'une après l'autre, quitte à mémoriser un opérande dans le processeur. Pour mémoriser l'opérande, les tout premiers processeurs utilisaient un registre unique appelé l''''accumulateur'''. La seconde opérande était lue depuis la mémoire RAM, la première était lue depuis l'accumulateur, et le résultat était mémorisé dans le registre accumulateur. Les instructions de calcul ne faisaient ainsi qu'un seul accès à la mémoire RAM, par opération.
En plus des instructions de calcul, le processeur a des '''instructions mémoire''' pour échanger des données entre la mémoire RAM et l'accumulateur. Les échanges de données peuvent se faire dans les deux sens : lecture comme écriture. Le processeur a une instruction pour la lecture et une autre instruction pour l'écriture. L'instruction de lecture s'appelle LOAD, elle copie une donnée de la RAM dans l'accumulateur, elle lit une adresse mémoire. L'instruction d'écriture s'appelle STORE, elle copie le contenu de l'accumulateur en mémoire RAM, à une adresse mémoire précisée par l'instruction.
Il est maintenant temps de répondre à une question qui s'était posée dans la section sur l'adressage : d'où viennent les adresses envoyées à la mémoire ? Sur les architectures à accumulateur, il n'y a qu'une seule possibilité : l''''adressage direct'''. L'idée est que l'adresse est une constante, qui est intégrée dans l’instruction elle-même. Les instructions LOAD/STORE précisent donc l'adresse à lire ou écrire. Mais il y a la même chose pour les instructions arithmétiques : chaque instruction arithmétique précise où se trouve la seconde opérande en mémoire RAM. Les instructions sont donc du genre :
* ''LOAD 56'' - lit l'adresse numéro 56 et copie son contenu dans l'accumulateur ;
* ''STORE adress 99'', copie l'accumulateur dans l'adresse 99 ;
* ''ADD adress 209'' : additionne l'accumulateur avec le contenu de l'adresse 209.
Dans les trois cas précédents, l'adresse est connue avant d’exécuter le programme, le programme a été codé pour utiliser cette adresse pour telle donnée, on a réservé une adresse pour la donnée voulue. C'est la seule possibilité possible sur les architectures à accumulateur, si on omet des capacités de calcul d'adresse très limitée qu'on détaillera dans le chapitre sur les accumulateurs.
L'intérieur d'un processeur à accumulateur est relativement simple. Il y a une unité de calcul, le registre accumulateur, et l'unité de contrôle qui commande tout le reste. Le tout est relié comme indiqué ci-dessous. L'accumulateur est relié à l'unité de calcul, mais aussi à la mémoire RAM pour les instructions mémoire LOAD et STORE. L'unité de contrôle reçoit une instruction, lue depuis la mémoire ROM, et configure le reste processeur pour qu'il exécute cette instruction. Elle envoie aussi l'adresse à lire/écrire sur le bus d'adresse, adresse qui est extraite de l'instruction lue.
[[File:Architecture à accumulateur, microarchitecture.png|centre|vignette|upright=2|Architecture à accumulateur, microarchitecture]]
Il faut noter que l'accumulateur n'est pas présent pour une raison d'optimisation. Il est là car le processeur n'a pas le choix. S'il veut s'interfacer avec une mémoire RAM normale, il doit utiliser un registre accumulateur. Dans ces conditions, difficile de dire si l'accumulateur fait partie de la hiérarchie mémoire. Personnelement, je vais dire que non, l'accumulateur ne fait pas partie de la hiérarchie mémoire. Avec un accumulateur, le processeur effectue toujours un accès mémoire par instruction, sauf en de rares exceptions. La performance du processeur est donc dépendante de celle de la mémoire RAM. La mémoire RAM doit être capable d'alimenter le processeur au rythme d'une lecture/écriture par cycle d'horloge. Par contre, avec les processeurs disposant de plus de registres, il y a une économie niveau accès mémoire.
===Les processeurs modernes : les processeurs à registres généraux===
Les architectures à accumulateur étaient très simples, faciles à concevoir, et marchaient bien à une époque où la mémoire était rapide, ce qui permettait de se passer de hiérarchie mémoire. Mais elles sont devenues plus confidentielles, de nos jours. La raison est que les processeur sont devenus plus rapides que la mémoire RAM. Et pour s'adapter, ils ont évolués pour accueillir plus de registres. Et l'ajout de registres a eu des conséquences assez importante sur la manière dont le processeur fonctionne. Notamment, les programmeurs et compilateur ont du s'adapter à la présence de plusieurs registres, à savoir qu'ils doivent utiliser les registres de données explicitement, comme ils le feraient pour la RAM.
La mémoire RAM étant devenue plus lente, les processeur doivent éviter de faire des accès mémoire à chaque instruction. Par exemple, prenons une mémoire 5 fois plus lente que le processeur. Concrètement, imaginons que la mémoire RAM mette 5 cycles d'horloge pour lire une donnée, alors que le processeur met un cycle d'horloge pour exécuter une instruction (lecture des opérande exclue). Dans ce cas, le seul moyen pour gagner en performance est que seule une instruction sur 5 accède à la mémoire.
Mais les processeurs à accumulateur ne permettent pas cela, il y a un accès mémoire par instruction, pour lire une opérande. Ils sont sous-optimaux, dans le sens où de nombreux accès mémoires pourraient être évités si on disposait de plus de registres. Par exemple, prenons le calcul suivant : A * B + C * D. Le processeur doit faire les deux multiplications, et additionner leurs résultats. Le problème est que le résultat de la première multiplication doit être enregistré en mémoire RAM, pour être relu lors de l'addition finale. Si on avait un second registre accumulateur, on aurait pu éviter cela, en mémorisant les deux résultats dans un accumulateur chacun.
Comme autre exemple, si un opérande est utilisé par deux ou trois instructions, les architectures à accumulateur imposent de la lire plusieurs fois, une fois par instruction. Si on disposait d'un second ou troisième accumulateur, voire d'un troisième, on pourrait éviter ça. Et les exemples de ce type sont vraiment nombreux. En soi, rien de bien grave, mais les performances ne sont pas terribles. Le processeur est alors très dépendant de la performance de la mémoire RAM. Et autant cela passait au tout début de l'informatique, où processeur et RAM avaient une vitesse comparable, autant ce n'est plus le cas de nos jours.
[[File:Isreg2reg.png|vignette|Processeur avec des registres généraux.]]
Pour éviter ces problèmes, les processeurs modernes disposent de plusieurs '''registres généraux''', chacun mémorisant un opérande. Les opérations lisent leurs opérandes depuis les registres et enregistrent leur résultat dans les registres. Notons qu'il est parfaitement possible de lire deux opérandes depuis les registres, ce n'est pas un problème. Les registres sont même l'idéal pour ça.
L'avantage est que cela réduit beaucoup les lectures en mémoire RAM. Si je reprends l'exemple de l'opération A * B + C * D, on élimine totalement les accès mémoire. Les deux multiplications enregistrent leurs résultats dans des registres généraux, la troisième lit ces deux registres. Pas besoin d'enregistrer un résultat en RAM pour le relire ensuite. Et il en est de même pour l'exemple où un opérande utilisé par plusieurs opérations : l'opérande est copéié dans les registres une seule fois, les opérations utiliseront la copie dans les registres.
La capacité des registres généraux détermine la taille des données manipulée par le processeur. Quand on parle de ''processeur 8, 16, 32 ou 64 bits'', on parle de la taille des registres généraux. Idem quand on parle d'''ordinateur ou de console de jeu 8, 16, 32 bits''. Au tout début de l'informatique, il n'était pas rare de voir des registres généraux de 3, 4, voire 8 bits. Par la suite, la taille de ces registres a augmenté, passant rapidement de 16 à 32 bits, voire 48 bits sur certains processeurs spécialisés. De nos jours, les processeurs des PC utilisent des registres de 64 bits, même s'il existe toujours des processeurs de faible performance avec des registres relativement petits, de 8 à 16 bits.
Cependant, la présence de plusieurs registres est une source de complication assez importante. En effet, avec un accumulateur unique, la première opérande est lue directement depuis l'accumulateur, la seconde est lue depuis la RAM. Il y a juste à préciser l'adresse de la seconde opérande. Mais avec des registres généraux, il faut préciser où se trouvent les deux opérandes ! Il y a alors deux solutions :
* soit les deux opérandes sont dans des registres ;
* soit la première est dans un registre et la seconde est en mémoire RAM.
Les processeurs CISC autorisent les deux possibilités, alors que les processeurs RISC n'autorisent que la première. Les processeurs RISC sont donc plus simples, dans le sens où toutes les instructions de calcul savent que leurs opérandes sont dans les registres. Les processeurs CISC, par contre, doivent préciser dans quel cas ils sont. La solution la plus simple utilise un bit, intégré dans l'instruction, qui dit dans quel cas l'instruction est. Une autre solution assez similaire utilise deux instructions différentes, selon la position de l'opérande dans l'ordinateur.
Mais ce n'est pas le seul problème que les processeurs doivent résoudre. Prenons l'exemple d'un processeur RISC, qui lit les deux opérandes sont lues depuis les registres. Il faut alors préciser dans quel registre se trouve la première opérande, et dans quel registre se trouve la seconde. De plus, il faut aussi préciser dans quel registre écrire le résultat. Pour cela, la solution est de numéroter les registres. Les instructions précisent les numéros des registres qu'elles utilisent. Les '''numéros de registre''' sont un équivalent pour les registres des adresses mémoire, mais les deux sont séparés.
L'intérieur du processeur est aussi modifié de manière à tenir compte de la présence de plusieurs registres. Les registres sont regroupés dans un circuit unique, appelé le '''banc de registres'''. Nous avons déjà vu comment créer un banc de registre, dans le chapitre nommé "Les registres et mémoires adressables". Rien de bien compliqué : il suffit de relier les registres à un multiplexeur et un démultiplexeur. Le multiplexeur permet de sélectionner quel registre lire, le démultiplexeur sélectionne le registre à écrire. Si on souhaite lire deux registres à la fois, il suffit de rajouter un second multiplexeur. Les multiplexeurs/démultiplexeur sont commandés en utilisant les numéros de registres mentionnés plus haut. Les numéros de registre sont extraits des instructions par l'unité de contrôle, qui envoie les numéros de registre sur l'entrée des multiplexeurs/démultiplexeurs.
[[File:Intérieur d'une mémoire RAM.png|centre|vignette|upright=2|Intérieur d'une RAM fabriquée avec des registres et des multiplexeurs.]]
Autre problème : les registres ne serviraient pas à grand-chose si on ne pouvait pas échanger des données entre registres et mémoire RAM. Pour cela, un processeur incorpore souvent des instructions pour copier des données provenant de la mémoire RAM dans un registre, et des instructions qui font l'inverse (d'un registre vers la mémoire). Les instructions en question sont appelées LOAD (copie RAM vers registre) et STORE (copie registre vers RAM). Les échanges de données entre RAM et registres sont fréquents, les instructions LOAD et STORE sont tout aussi importantes que les instructions de calcul.
Les instructions arithmétiques accèdent aux registres, elles peuvent aussi accéder à la mémoire RAM, mais nous omettons cette possibilité pour le moment. Par contre, les instructions LOAD et STORE ne font qu'accéder à la mémoire, ce qui demande de préciser l'adresse à lire/écrire. Encore une fois, on peut se demander d'où viennent les adresses ? Et cette fois-ci, il y a deux possibilités, une de plus que pour les architectures à accumulateur, qui s'appellent des '''modes d'adressage'''.
* Avec l''''adressage direct''', où l'adresse est une constante intégrée dans l’instruction LOAD/STORE elle-même. Il était déjà présent sur les architectures à accumulateur, je ne reviendrais pas dessus.
* Avec l''''adressage indirect''', l'adresse est déterminée lors de l'exécution du programme et est ensuite placée dans un registre général. L'adressage indirect permet d'envoyer ce registre sur le bus d'adresse.
Pour résumer, soit l'adresse est constante et est intégrée dans l'instruction, soit elle est variable et est une donnée comme une autre. Dans le second cas, elle se retrouve dans un registre général, ou est calculée à partir d'opérandes dans les registres, les deux cas sont très similaires. Et cela explique pourquoi on parle de registres généraux : ils servent aussi bien pour les opérandes que pour les adresses mémoire.
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=L'architecture de base d'un ordinateur
| prevText=L'architecture de base d'un ordinateur
| next=La performance d'un ordinateur
| nextText=La performance d'un ordinateur
}}
</noinclude>
9sc94cdcus43xpm6ifanhfr6y44amuf
Wikilivres:GUS2Wiki
4
78643
762719
762199
2026-04-01T12:27:59Z
Alexis Jazz
81580
Updating gadget usage statistics from [[Special:GadgetUsage]] ([[phab:T121049]])
762719
wikitext
text/x-wiki
{{#ifexist:Project:GUS2Wiki/top|{{/top}}|This page provides a historical record of [[Special:GadgetUsage]] through its page history. To get the data in CSV format, see wikitext. To customize this message or add categories, create [[/top]].}}
Les données suivantes sont en cache et ont été mises à jour pour la dernière fois le 2026-04-01T08:33:43Z. {{PLURAL:5000|1=Un seul résultat|5000 résultats}} au maximum {{PLURAL:5000|est disponible|sont disponibles}} dans le cache.
{| class="sortable wikitable"
! Gadget !! data-sort-type="number" | Nombre d’utilisateurs !! data-sort-type="number" | Utilisateurs actifs
|-
|AncreTitres || 33 || 0
|-
|ArchiveLinks || 12 || 0
|-
|Barre de luxe || 35 || 2
|-
|BoutonsLiens || 41 || 0
|-
|CategoryAboveAll || 19 || 1
|-
|CategorySeparator || 22 || 0
|-
|CoinsArrondis || 99 || 1
|-
|CollapseSidebox || 35 || 1
|-
|CouleurContributions || 33 || 1
|-
|CouleursLiens || 25 || 1
|-
|DeluxeAdmin || 5 || 1
|-
|DeluxeEdit || 36 || 1
|-
|DeluxeHistory || 46 || 2
|-
|DeluxeImport || 19 || 1
|-
|DeluxeRename || 16 || 1
|-
|DeluxeSummary || 36 || 2
|-
|DevTools || 17 || 1
|-
|DirectPageLink || 25 || 1
|-
|Emoticons || 43 || 1
|-
|EmoticonsToolbar || 45 || 1
|-
|FastRevert || 36 || 2
|-
|FixArrayAltLines || 22 || 1
|-
|FlecheHaut || 66 || 1
|-
|GoogleTrans || 28 || 1
|-
|HotCats || 81 || 5
|-
|JournalDebug || 21 || 1
|-
|JournalEnTable || 2 || 1
|-
|LeftPaneSwitch || 5 || 1
|-
|ListeABordure || 30 || 1
|-
|LiveRC || 30 || 0
|-
|LocalLiveClock || 27 || 1
|-
|Logo || 42 || 0
|-
|MobileView || 18 || 2
|-
|NavigAdmin || 38 || 0
|-
|OngletEditCount || 44 || 2
|-
|OngletEditZeroth || 66 || 1
|-
|OngletGoogle || 28 || 1
|-
|OngletPurge || 54 || 2
|-
|OptimizedSuivi || 18 || 0
|-
|Popups || 61 || 0
|-
|RenommageCategorie || 6 || 2
|-
|RestaurationDeluxe || 12 || 1
|-
|RevertDiff || 35 || 4
|-
|ScriptAutoVersion || 16 || 1
|-
|ScriptSidebox || 31 || 0
|-
|ScriptToolbar || 42 || 1
|-
|SisterProjects || 16 || 1
|-
|SkinPreview || 4 || 1
|-
|Smart patrol || 2 || 1
|-
|SourceLanguage || 24 || 1
|-
|SousPages || 57 || 3
|-
|SpaceToolbar || 29 || 0
|-
|TableUnicode || 55 || 0
|-
|Tableau || 66 || 1
|-
|TitreDeluxe || 56 || 1
|-
|TitreHierarchique || 17 || 0
|-
|UTCLiveClock || 26 || 0
|-
|UnicodeEditRendering || 29 || 1
|-
|WikEd || 29 || 0
|-
|autonum || 2 || 0
|-
|massblock || 3 || 1
|-
|monBrouillon || 19 || 2
|-
|perpagecustomization || 16 || 1
|-
|recentchangesbox || 15 || 0
|-
|searchFocus || 18 || 0
|-
|searchbox || 30 || 2
|}
* [[Spécial:GadgetUsage]]
* [[m:Meta:GUS2Wiki/Script|GUS2Wiki]]
<!-- data in CSV format:
AncreTitres,33,0
ArchiveLinks,12,0
Barre de luxe,35,2
BoutonsLiens,41,0
CategoryAboveAll,19,1
CategorySeparator,22,0
CoinsArrondis,99,1
CollapseSidebox,35,1
CouleurContributions,33,1
CouleursLiens,25,1
DeluxeAdmin,5,1
DeluxeEdit,36,1
DeluxeHistory,46,2
DeluxeImport,19,1
DeluxeRename,16,1
DeluxeSummary,36,2
DevTools,17,1
DirectPageLink,25,1
Emoticons,43,1
EmoticonsToolbar,45,1
FastRevert,36,2
FixArrayAltLines,22,1
FlecheHaut,66,1
GoogleTrans,28,1
HotCats,81,5
JournalDebug,21,1
JournalEnTable,2,1
LeftPaneSwitch,5,1
ListeABordure,30,1
LiveRC,30,0
LocalLiveClock,27,1
Logo,42,0
MobileView,18,2
NavigAdmin,38,0
OngletEditCount,44,2
OngletEditZeroth,66,1
OngletGoogle,28,1
OngletPurge,54,2
OptimizedSuivi,18,0
Popups,61,0
RenommageCategorie,6,2
RestaurationDeluxe,12,1
RevertDiff,35,4
ScriptAutoVersion,16,1
ScriptSidebox,31,0
ScriptToolbar,42,1
SisterProjects,16,1
SkinPreview,4,1
Smart patrol,2,1
SourceLanguage,24,1
SousPages,57,3
SpaceToolbar,29,0
TableUnicode,55,0
Tableau,66,1
TitreDeluxe,56,1
TitreHierarchique,17,0
UTCLiveClock,26,0
UnicodeEditRendering,29,1
WikEd,29,0
autonum,2,0
massblock,3,1
monBrouillon,19,2
perpagecustomization,16,1
recentchangesbox,15,0
searchFocus,18,0
searchbox,30,2
-->
tgbfrofurh65sec4g6eujwzn15swdd2
Fonctionnement d'un ordinateur/L'espace d'adressage du processeur
0
79337
762741
762699
2026-04-01T16:07:40Z
Mewtow
31375
/* Un seul espace d'adressage, partagé entre plusieurs programmes */
762741
wikitext
text/x-wiki
L''''espace d'adressage''' du processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées. De plus, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, comme nous le verrons plus bas. Nous verrons aussi qu'un processeur peut avoir plusieurs espaces d'adressages séparés.
==L'adressage de la RAM et de la ROM==
Avoir plusieurs espaces d'adressage spécialisés est quelque chose que nous avons déjà rencontré dans les chapitres précédents, mais sans le dire ouvertement. Aussi, nous allons faire quelques rappels sur les cas déjà rencontrés. En premier lieu, nous allons rappeler la différence entre architectures Von Neumann et Hardvard. La différence entre les deux tient dans l'adressage des mémoires RAM et ROM : est-ce qu'elles sont dans un seul espace d'adressage, ou dans des espaces d'adressage séparés.
L''''architecture Von Neumann''' a un seul espace d'adressage, découpé entre la mémoire RAM d'un côté et la mémoire ROM de l'autre. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM est placée dans les adresses hautes, les plus élevées, alors que la RAM est placée dans les adresses basses en commençant par l'adresse 0. C'est une convention qui n'est pas toujours respectée, aussi mieux vaut éviter de la tenir pour acquise.
[[File:Vision de la mémoire par un processeur sur une architecture Von Neumann.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Von Neumann.]]
L''''architecture Harvard''' utilise des espaces d'adressage séparés pour la RAM et la ROM. Une même adresse peut correspondre soit à la ROM, soit à la RAM. Le processeur voit bien deux mémoires séparées, chacune dans son propre espace d'adressage. Les deux espaces d'adressage n'ont pas forcément la même taille. Il est possible d'avoir un plus gros espace d'adressage pour la RAM que pour la ROM. Cela implique que les adresses des instructions et des données soient de taille différentes. C'est peu pratique et c'est rarement implémenté, ce qui fait que le cas le plus courant est celui où les deux espaces d'adressages ont la même taille.
[[File:Vision de la mémoire par un processeur sur une architecture Harvard.png|centre|vignette|upright=2|Vision de la mémoire par un processeur sur une architecture Harvard.]]
Sur une '''architecture Harvard modifiée''', le programme est placé dans un espace d'adressage à part du reste. Le problème, c'est que cet espace d'adressage ne contient pas que le code machine à exécuter. Il contient aussi des constantes, à savoir des données qui gardent la même valeur lors de l'exécution du programme. Elles peuvent être lues, mais pas modifiées durant l'exécution du programme. L'accès à ces constantes demande d'aller lire celles-ci dans l'autre espace d'adressage, pour les copier dans les registres généraux. Le processeur doit pour cela avoir des instructions de lecture dédiées. En clair, il y a une instruction LOAD pour lire dans la mémoire ROM, une autre pour lire dans la RAM.
[[File:Espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=3|Espaces d'adressage sur une archi harvard modifiée]]
Une autre solution utilise des instructions de copie, qui copient les constantes en mémoire RAM, donc d'un espace d'adressage à l'autre.
[[File:Organisation des espaces d'adressage sur une archi harvard modifiée.png|centre|vignette|upright=3|Organisation des espaces d'adressage sur une archi harvard modifiée]]
==L'adressage des périphériques==
Passons maintenant à l'adressage des périphériques. La communication avec les périphériques se fait par l'intermédiaire de registres d’interfaçage. Et ces registres peuvent soit avoir un espace d'adressage séparé, soit être inclus dans l'espace d'adressage des mémoires. Dans ce qui suit, nous allons supposer que l'architecture des de type Von Neumann pour simplifier les explications.
===Les entrées-sorties mappées en mémoire===
Une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques. Le périphérique se retrouve inclus dans l'ensemble des adresses utilisées pour manipuler la mémoire : on dit qu'il est mappé en mémoire. Les adresses mémoires associées à un périphérique sont redirigées automatiquement vers les registres du périphérique en question, voire vers sa mémoire intégrée. On parle alors d''''entrées-sorties mappées en mémoire'''.
[[File:IO mappées en mémoire.png|centre|vignette|upright=2.0|IO mappées en mémoire]]
On remarque un défaut inhérent à cette technique : les adresses utilisées pour les périphériques ne sont plus disponibles pour la RAM. On ne peut plus adresser autant de RAM qu'avant. La perte dépend des périphériques installés et de leur gourmandise en adresses mémoires. C'est ce qui causait un problème assez connu sur les ordinateurs 32 bits, capables d'adresser 4 gibioctets de mémoire. Certaines personnes installaient 4 gigaoctets de mémoire sur leur ordinateur 32 bits et se retrouvaient avec « seulement » 3,5 à 3,8 gigaoctets de mémoire, les périphériques prenant le reste.
Il est possible que la RAM d'un périphérique soit mappée en RAM. Un exemple classique est celui des cartes graphiques qui incorporent une mémoire RAM appelée la mémoire vidéo. La mémoire vidéo est mappée en mémoire, ce qui permet au processeur d'écrire directement dedans. Toute lecture ou écriture dans les adresses associées est redirigée vers le bus PCI/AGP/PCI-Express. Nous verrons plus bas des exemples d'ordinateurs où la mémoire vidéo est mappée en mémoire, que ce soit totalement ou partiellement.
Si je dis totalement ou partiellement, c'est parce que les cartes graphiques modernes disposent de tellement de mémoire qu'on ne peut pas la mapper totalement dans l'espace d'adressage. Sur les systèmes d'avant 2008, seuls 256 mégaoctets de mémoire vidéo sont mappés en mémoire RAM. Le reste de la mémoire vidéo est invisible du point de vue du processeur, mais manipulable par le GPU à sa guise. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''Resizable Bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
===L'espace d'adressage séparé pour les entrées-sorties===
Les entrées-sorties et périphériques peuvent avoir leur propre espace d'adressage dédié, séparé de celui utilisé pour les mémoires RAM et ROM.
[[File:Espaces_d'adressages_séparés_entre_mémoire_et_périphérique.png|centre|vignette|upright=3|Bit IO.]]
Une même adresse peut donc adresser soit une entrée-sortie, soit une case mémoire. Et pour faire la différence, le processeur doit avoir des instructions séparées pour adresser les périphériques et 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. Cela élimine aussi les problèmes avec les caches : les accès à l'espace d'adressage de la RAM passent par l'intermédiaire de la mémoire cache, alors les accès dans l'espace d'adressage des périphériques le contournent totalement.
Là encore, les deux espaces d'adressage n'ont pas forcément la même taille. Il arrive que les deux espaces d'adressage aient la même taille, le plus souvent sur des ordinateurs complexes avec beaucoup de périphériques. Mais les systèmes embarqués ont souvent des espaces d'adressage plus petits pour les périphériques que pour la ou les mémoires. L'implémentation varie grandement suivant le cas, la première méthode imposant d'avoir deux bus séparés pour les mémoires et les périphériques, l'autre permettant un certain partage du bus d'adresse. Nous reviendrons dessus plus en détail dans le chapitre sur l'adressage des périphériques.
==La ''memory map'' d'un ordinateur==
Les deux sections précédentes nous ont appris que l'on peut utiliser un espace d'adressage séparé pour la ROM et un autre pour les périphériques. En tout, cela donne quatre possibilités distinctes.
{|class="wikitable"
|-
!
! IO mappées en mémoire
! IO séparées
|-
! ROM mappée en mémoire (architecture Von Neumann)
| Un seul espace d'adressage
| Deux espaces d'adressage :
* un pour les mémoires RAM/ROM ;
* un pour les IO.
|-
! ROM séparée (architecture Harvard)
| Deux espaces d'adressage :
* un pour la RAM et les IO ;
* un pour la ROM.
| Trois espaces d'adressages :
* un pour la RAM ;
* un pour la ROM ;
* un pour les IO.
|}
Les quatre solutions ont des avantages et inconvénients divers, mais il est intéressant de contraster un espace d'adressage unique avec plusieurs espaces d'adressages.
===L'espace d'adressage unique===
Avec un espace d'adressage unique, la ROM est au sommet de l'espace d'adressage, les périphériques sont juste en-dessous, la RAM commence à l'adresse 0 et prend les adresses basses. Faire simplifie grandement l'implémentation matérielle de l'adressage. Notons que d'autres composants que les périphériques ou les mémoires peuvent se trouver dans l'espace d'adressage. On peut y trouver les horloges temps réels, des timers, des senseurs de température, ou d'autres composants placés sur la carte mère. Un exemple un peu original est le suivant : la console de jeu Nintendo DS incorporait une unité de calcul spécialisée dans les divisions et racines carrées, séparée du processeur, qui était justement mappée en mémoire !
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
L'espace d'adressage unique est plus simple pour les programmeurs, malgré un désavantage dont il faut parler. Le problème est que des adresses censées être disponibles pour la RAM sont détournées vers la ROM ou les périphériques, ce qui limite la quantité de RAM qui peut être réellement adressée en pratique. C'est un défaut qui se manifeste seulement pour les petits espaces d'adressages, de 8 à 16 bits, qui ne permettent pas d'adresser beaucoup de RAM. Avec des adresses codées sur 16 bits, un espace d'adressage de 64 kibioctets de RAM est grignoté par des entrées-sorties assez rapidement. Par contre, pour des adresses de 32 à 64 bits, une bonne partie de l'espace d'adressage est inutilisé, car il n'y a pas assez de RAM. L'espace d'adressage unique n'a donc pas de désavantages.
Les vielles consoles de jeux et certains vieux ordinateurs (Commodores et Amiga), utilisaient un espace d'adressage unique. Elles n'avaient pas une variété de cartes graphiques ou de cartes sons différentes, comme sur les PCs modernes. Au contraire, elles avaient la même configuration matérielle, le matériel ne pouvait pas être changé ni upgradé. Le système d'exploitation était rudimentaire et ne contrôlait pas vraiment l'accès au matériel. Les programmeurs avaient donc totalement accès au matériel et mapper les entrées/sorties en mémoire rendait la programmation des périphériques très simple.
<gallery widths=200px heights=500px>
N5200mk2 memory map.svg|Adressage mémoire (carte mémoire) du N5200mk2.
PC-9801VM memory map.svg|Adressage mémoire (carte mémoire) du PC-9801VM.
</gallery>
===La commutation de banques (''bank switching'')===
Le '''''bank switching''''', aussi appelé '''commutation de banque''', permet d'utiliser plusieurs espaces d'adressage sur un même processeur, sans attribuer chaque espace d'adressage pour une raison précise. L'espace d'adressage est présent en plusieurs exemplaires appelés des '''banques'''. Les banques sont numérotées, chaque numéro de banque permettant de l'identifier et de le sélectionner.
Le but de cette technique est d'augmenter la mémoire disponible pour l'ordinateur. Par exemple, supposons que j'ai besoin d'adresser une mémoire ROM de 4 kibioctets, une RAM de 8 kibioctets, et divers périphériques. Le processeur a un bus d'adresse de 12 bits, ce qui limite l'espace d'adressage à 4 kibioctets. Dans ce cas, je peux réserver 4 banques : une pour la ROM, une pour les périphériques, et deux banques qui contiennent chacune la moitié de la RAM. La simplicité et l'efficacité de cette technique font qu'elle est beaucoup utilisée dans l'informatique embarquée.
[[File:PC-8801MemoryMap.gif|centre|vignette|upright=2|exemple de Bank switching.]]
Cette technique demande d'utiliser un bus d'adresse plus grand que les adresses du processeur. L'adresse réelle se calcule en concaténant le numéro de banque avec l'adresse accédée. Le numéro de la banque actuellement en cours d'utilisation est mémorisé dans un registre appelé le '''registre de banque'''. On peut changer de banque en changeant le contenu de ce registre. Le processeur dispose souvent d'instructions spécialisées qui en sont capables.
{| class="wikitable flexible"
|[[File:Banque mémoire.png|Banque mémoire.]]
|[[File:Registre de banque.png|Registre de banque.]]
|}
==Le placement des programmes dans l'espace d'adressage==
Les ordinateurs modernes sont des architectures Von Neumann, avec un seul espace d'adressage, qui est partagé suivant les besoins. Et un point important est que le système d'exploitation et les programmes sont copiés en mémoire RAM avant d'être exécutés. Ils ne sont pas exécutés depuis une mémoire ROM, cela est réservé aux systèmes embarqués simples. Et cela a une influence sur l'espace d'adressage. Les programmes et le système d'exploitation doivent se partager l'espace d'adressage. Voyons voir comment ce partage se fait.
Dans ce chapitre, nous allons volontairement mettre de côté les ordinateurs qui supportent la mémoire virtuelle. Nous en parlerons dans le prochain chapitre. Le principe est de voir comment un processeur avec un seul espace d'adressage gèrent la présence d'un ou de plusieurs programmes.
===Un seul espace d'adressage, non-partagé===
Le cas le plus simple est celui où il n'y a pas de système d'exploitation et où un seul programme s'exécute sur l'ordinateur. Le programme a alors accès à tout l'espace d'adressage, sauf pour ce qui est réservé aux périphériques et à la mémoire ROM. Le programme organise la mémoire en plusieurs sections, dans lesquelles le programme range des données différentes. Typiquement, on trouve quatre blocs de mémoire, appelés des segments, chacun étant spécialisé pour les données, le code, la pile, etc. Voici ces trois sections :
* Le segment '''''text''''' contient le code machine du programme, de taille fixe.
* Le segment '''''data''''' contient des données de taille fixe qui occupent de la mémoire de façon permanente.
* Le segment pour la '''pile''', de taille variable.
* le reste est appelé le '''tas''', de taille variable.
[[File:Organisation d'un espace d'adressage unique utilisé par un programme unique.png|centre|vignette|upright=2|Organisation d'un espace d'adressage unique utilisé par un programme unique]]
[[File:Typical computer data memory arrangement.png|vignette|upright=0.5|Typical computer data memory arrangement]]
La pile et le tas sont de taille variable, ce qui veut dire qu'ils peuvent grandir ou diminuer à volonté, contrairement au reste. Entre le tas et la pile, on trouve un espace de mémoire inutilisée, qui peut être réquisitionné selon les besoins. La pile commence généralement à l'adresse la plus haute et grandit en descendant, alors que le tas grandit en remontant vers les adresses hautes. Il s'agit là d'une convention, rien de plus. Il est possible d'inverser la pile et le tas sans problème, c'est juste que cette organisation est rentrée dans les usages.
Avant de poursuivre, précisons qu'il est possible de regrouper plusieurs programmes distincts dans un seul, afin qu'ils partagent le même morceau de mémoire. Les programmes portent alors le nom de '''threads'''. Les ''threads'' d'un même processus partagent le même espace d'adressage. Ils partagent généralement certains segments : ils se partagent le code, le tas et les données statiques. Par contre, chaque thread dispose de sa propre pile d'appel.
[[File:Single vs multithreaded processes.jpg|centre|vignette|upright=2.0|Distinction entre processus mono et multi-thread.]]
Il va de soi que cette vision de l'espace d'adressage ne tient pas compte des périphériques. C'est-à-dire que les schémas précédents partent du principe qu'on a un espace d'adressage séparé pour les périphériques. Dans le cas où les entrées-sorties sont mappées en mémoire, l'organisation est plus compliquée. Généralement, les adresses associées aux périphériques sont placées juste au-dessus de la pile, dans les adresses hautes.
===Un seul espace d'adressage, partagé avec le système d'exploitation===
[[File:Gestion de la mémoire sur les OS monoprogrammés.png|vignette|upright=1.0|Gestion de la mémoire sur les OS monoprogrammés.]]
Maintenant, étudions le cas où le programme partage la mémoire avec le système d'exploitation. Sur les systèmes d'exploitation les plus simples, on ne peut lancer qu'un seul programme à la fois. Le système d'exploitation réserve une portion de taille fixe réservée au système d'exploitation, alors que le reste de la mémoire est utilisé pour le programme à exécuter. Le programme est placé à un endroit en RAM qui est toujours le même.
Le système d'exploitation peut être soit placé dans une ROM, soit copié en mémoire RAM depuis une mémoire de masse, comme le programme à lancer. Si le système d'exploitation est copié en mémoire RAM, il est généralement placé dans les premières adresses, les adresses basses. A l'inverse, un OS en mémoire ROM est généralement placé à la fin de la mémoire, dans les adresses hautes. Mais tout cela n'est qu'une convention, et les exceptions sont monnaie courante.
[[File:Méthodes d'allocation de la mémoire avec un espace d'adressage unique.png|centre|vignette|upright=2.0|Méthodes d'allocation de la mémoire avec un espace d'adressage unique]]
Sur de tels systèmes, il faut protéger l'OS contre une erreur ou malveillance d'un programme utilisateur. Notons qu'il s'agit d'une protection en écriture, pas en lecture. Le programme peut parfaitement lire les données de l'OS sans problèmes, au moins en partie. Dans ce qui suit, on part du principe que l'OS est dans les adresses basses.
La solution la plus courante interdit au programme d'écrire au-delà d'une limite au-delà de laquelle se trouve le système d’exploitation. Pour cela, le processeur incorpore un '''registre limite''', qui contient l'adresse limite au-delà de laquelle un programme peut pas écrire. Pour toute écriture en espace utilisateur, l'adresse écrite est comparée au registre limite. Si l'adresse est inférieure au registre limite, le programme cherche écrire dans la mémoire réservée à l'OS. L’accès mémoire est interdit, une exception matérielle est levée et l'OS affiche un message d'erreur.
[[File:Circuit total.png|centre|vignette|upright=2.0|Protection mémoire avec un registre limite.]]
===Un seul espace d'adressage, partagé entre plusieurs programmes===
Les systèmes d’exploitation modernes implémentent la '''multiprogrammation''', le fait de pouvoir lancer plusieurs logiciels en même temps. Et ce même si un seul processeur est présent dans l'ordinateur : les logiciels sont alors exécutés à tour de rôle. Et il faut alors résoudre un problème : le partage de la RAM entre les différents programmes. Les différents programmes et leurs données sont placés en mémoire RAM, et il faut trouver un moyen pour répartir les différents programmes en RAM.
[[File:Partitions mémoire.png|vignette|upright=1|Partitions mémoire]]
Il y a plusieurs solutions pour cela, mais l'une d'entre elle est l'usage de segments mémoire. Avec elle, chaque programme se voit attribuer un ou plusieurs blocs de mémoire. Ils sont appelés des '''partitions mémoire''', ou encore des '''segments'''. Dans ce qui va suivre, nous partons du principe qu'un programme est égal à un segment, pour simplifier les explications. Mais sachez qu'un programme peut être éclaté en plusieurs segments dispersés dans la mémoire, et même être conçu pour ! Nous en reparlerons dans le chapitre sur le mémoire virtuelle.
Le système d'exploitation mémorise une liste des segments importants en mémoire RAM, appelée la ''table des segments''. Il s'agit d'un tableau dont chaque entrée mémorise les informations pour un segment. Une entrée de ce tableau est appelée un '''descripteur de segment''' et contient son adresse de base, sa taille, et des autorisations liées à la protection mémoire. Précisément, l'entrée numéro N mémorise les informations du segment numéro N. A partir de l'adresse de base de la table des segments et du numéro de segment, on peut lire ou écrire un descripteur de segment.
[[File:Global Descriptor table.png|centre|vignette|upright=2|Global Descriptor table]]
Toutefois, l'usage de segments amène un paquet de problèmes qu'il faut résoudre au mieux. Le premier problème est tout simplement de placer les segments dans l'espace d'adressage, mais c'est quelque chose qui est du ressort du système d'exploitation. Par contre, cela implique qu'un segment peut être placé n'importe où en RAM et sa position en RAM change à chaque exécution. En conséquence, les adresses des branchements et des données ne sont jamais les mêmes d'une exécution à l'autre. Pour résoudre ce problème, le compilateur considère que le segment commence à l'adresse zéro, puis les adresses sont corrigées avant ou pendant l'exécution du programme. Cette correction est en général réalisée par l'OS lors de la copie du programme en mémoire, mais il existe aussi des techniques matérielles, que nous verrons dans le chapitre suivant.
Il faut aussi prendre en compte le phénomène de l''''allocation mémoire'''. Derrière ce nom barbare, se cache quelque chose de simple : les programmes peuvent réclamer de la mémoire au système d'exploitation, pour y placer des données. Les langages de programmation bas niveau supportent des fonctions comme malloc(), qui permettent de demander un bloc de mémoire de N octets à l'OS, qui doit alors accommoder la demande. S'il n'y a pas assez de mémoire, l'appel échoue et le programme doit gérer la situation. De même, un programme peut libérer de la mémoire qu'il n'utilise plus avec des fonctions comme free(). Avec des segments, cela revient à changer la taille d'un segment, plus précisément à la fin du segment. Et tout cela est géré par le système d'exploitation, aussi on laisse cela pour le prochain chapitre.
Enfin, sans protection particulière, les programmes peuvent techniquement lire ou écrire les données des autres. Pour éviter cela, il suffit de vérifier qu'un programme accède bien à son segment et pas ailleurs. Il suffit de vérifier si l'adresse lue/écrite est dans le bon intervalle. Il suffit alors d'utiliser deux registres limites, rien de plus.
Mais au-delà de cette simple vérification, si un programme pouvait modifier les données d'un autre programme, on se retrouverait rapidement avec une situation non prévue par le programmeur, avec des conséquences qui vont d'un joli plantage à des failles de sécurité dangereuses. Il faut donc introduire des mécanismes de protection mémoire, pour isoler les programmes les uns des autres, et éviter toute modification problématique. La protection mémoire regroupe plusieurs techniques assez variées, qui ont des objectifs différents. Elles ont pour point commun de faire intervenir à des niveaux divers le système d'exploitation et le processeur.
==La ''memory map'' des PC IBM x86==
Dans ce qui suit, nous allons étudier l'espace d'adressage des processeurs x86. L'organisation de leur espace d'adressage a évolué dans le temps et l'espace d'adressage s'est adapté. Mais il s'est adapté sans modifier l'existant, pour des raisons de compatibilité. Aussi, les processeurs x86 modernes peuvent fonctionner dans plusieurs modes, appelés mode réel, protégé, virtuel 8086, long, ''system management mode'', et compatibilité 32 bits.
[[File:AMD64StateDiagram.svg|centre|vignette|upright=2|AMD64StateDiagram]]
Le ''system management mode'' a déjà été abordé dans le chapitre sur les interruptions. Pour simplifier, il ne s'agit pas d'un véritable mode au sens "adressage". Dans ce mode, le système d'exploitation est mis en pause et le BIOS ou un autre firmware s'exécute sans restriction. On y rentre grâce à une interruption dédiée, lancée par le noyau de l'OS. Le système d'exploitation exécute cette interruption afin de laisser la main au BIOS, pour lui déléguer certaines tâches. Par contre, les autres modes sont bien plus intéressant, car ils ont chacun un espace d'adressage différent. Voyons-les dans le détail.
===Le mode réel : l'adressage sur 20 bits===
Le tout premier mode était le '''mode réel''', qui utilisait des adresses de 20 bits, ce qui fait 1 mébioctet de mémoire adressable. Il était utilisé sur des processeurs 16 bits, qui géraient donc des adresses de 16 bits capables d'adresser 64 kibioctets de mémoire. Pour contourner cette limitation, la mémoire en mode réel était composée de 16 blocs de 64 kibioctets. Pour générer une adresse de 20 bits, le processeur contient un registre de 4 bits qui précise quel bloc de 64 kibioctet est couramment adressé. En somme, une sorte de commutation de banque intégrée au processeur.
: La réalité est plus complexe, comme on le verra dans le prochain chapitre, mais cette explication simpliste suffira pour le moment.
Le processeur démarre systématiquement en mode réel, y compris sur les ordinateurs modernes. Le BIOS s'exécute dans ce mode, avant de passer en mode protégé et de laisser la main à l'UEFI et au système d'exploitation. Autrefois, le système d'exploitation s'exécutait aussi en mode réel, c'est le cas du DOS.
En mode réel, l'espace d'adressage est peuplé par de la RAM, la ROM du BIOS et des périphériques. La RAM prenait les adresses basses, la ROM était au sommet de l'espace d'adressage, et les périphériques entre les deux. Les premiers 640 kibioctets sont réservés à la RAM et sont appelés la mémoire conventionnelle. Les octets restants forment la '''mémoire haute''', réservée aux ROM et aux périphériques. Elle est sectionnée en deux portions. Le sommet de la mémoire haute est réservé au BIOS, alors que le bas de la mémoire haute est réservé aux périphériques. Dans cette dernière, on trouve les BIOS des périphériques (dont celui de la carte vidéo, s'il existe), qui sont nécessaires pour les initialiser et pour communiquer avec eux. De plus, on y trouve la mémoire de la carte vidéo et éventuellement la mémoire d'autres périphériques comme la carte son.
{| class="wikitable" style="text-align:center;"
|+ Espace d'adressage en mode réel
|-
! Numéro du bloc !! Contenu du bloc
|-
| 1024 - 960 Kio || class="f_jaune" | BIOS principal (ROM)
|-
| 960 Kio - 640 Kio
| class="f_vert" | ROM d'extension des périphériques (XT, EGA, 3270 PC) </br> Mémoire vidéo des cartes EGA, MDA ou CGA
|-
| 640 Kio - 0 || class="f_rouge" | Mémoire RAM, mémoire conventionnelle
|}
Pour détailler un peu plus, il faut tenir compte du découpage de l'espace d'adressage en blocs de 64 kibioctets. Le découpage en blocs de 64 kibioctets est particulièrement important pour la mémoire haute. Des blocs sont attribués à un périphérique spécifique. Par exemple, le 16ème bloc est réservé au BIOS, le 12ème aux ROM des périphériques, le 10ème et le 11ème à la mémoire vidéo, etc.
{| class="wikitable" style="text-align:center;"
|+ Espace d'adressage en mode réel
|-
! Numéro du bloc !! Contenu du bloc
|-
| 0 || rowspan="10" class="f_rouge" | Mémoire RAM, mémoire conventionnelle
|-
| 1
|-
| 2
|-
| 3
|-
| 4
|-
| 5
|-
| 6
|-
| 7
|-
| 8
|-
| 9
|-
| 10 || class="f_vert" | Mémoire vidéo des cartes EGA
|-
| 11 || class="f_vert" | Mémoire vidéo des cartes MDA ou CGA
|-
| 12 || class="f_vert" | ROM d'extension des périphériques (XT, EGA, 3270 PC)
|-
| 13 || class="f_gris" | Autre, non-réservé
|-
| 14 || class="f_gris" | Autre, non-réservé
|-
| 15 || class="f_jaune" | ROM du BIOS
|}
Vous remarquerez que les blocs 13 et 14 sont non-réservés. Ils peuvent être utilisés pour mapper des périphériques en mémoire. Mais si aucun périphérique n'est mappé dedans, les blocs sont laissés libres. Les OS n'hésitaient pas à les utiliser pour adresser de la RAM. Par exemple, si l'ordinateur n'a pas de carte vidéo EGA, le bloc qui leur était réservé était réutilisé comme mémoire RAM. La mémoire conventionnelle passait alors de 640 à 704 kibioctets de RAM disponibles.
Les deux premiers kibioctets de la mémoire conventionnelle sont initialisés au démarrage de l'ordinateur. Ils sont utilisés pour stocker le vecteur d'interruption (on expliquera cela dans quelques chapitres) et servent aussi au BIOS. La portion réservée au BIOS, la ''BIOS Data Area'', mémorise des informations en RAM. Elle commence à l'adresse 0040:0000h, a une taille de 255 octets, et est initialisée lors du démarrage de l'ordinateur. Le reste de la mémoire conventionnelle est réservée au le système d'exploitation (MS-DOS, avant sa version 5.0) et au programme en cours d’exécution.
===Interlude : les technologies d'expanded memory===
Déjà à l'époque, 1 mébioctet était une limite assez faible, même si cela n'a pas empêché à un grand dirigeant de l'industrie informatique de dire que "640K ought to be enough for anybody". Aussi, diverses solutions matérielles ont vu le jour. Elles étaient peu utilisées et ont concrètement servi à des applications spécifiques. La principale est l''''''expanded memory''''' (EMS), une solution utilisant une carte d'extension avec plusieurs modules de RAM installés dessus. Les modules étaient accédés via la technique de la commutation de banque.
[[File:Expanded memory.svg|centre|vignette|upright=2|L'espace d'adressage avec ''Expanded memory''. La carte d'extension et le matériel requis ne sont pas représentés.]]
Le terme ''expanded memory'' regroupe plusieurs technologies propriétaires semblables sur le principe mais différentes dans l'exécution. Les premières utilisaient des banques de 64 kibioctets, qui étaient mappées dans un bloc de 64 kibioctets libre en mémoire haute. L'usage de banques de 64 kibioctets collait bien avec l'adressage particulier du mode réel, où la mémoire était gérée par blocs de 64 kibioctets. Les technologies ultérieures utilisaient 2 à 4 pages de 16 kibioctets, qui pouvaient être placée n'importe où en mémoire conventionnelle.
[[File:EmulexPersyst 4M ISA.jpeg|centre|vignette|upright=2|Carte d'extension ''Expanded memory'' de marque Emulex Persyst, de 4 mébioctets.]]
L'''expanded memory'' demandait que les programmes soient codés pour utiliser cette fonctionnalité. Pour cela, ils devaient utiliser une technique de programmation nommée ''Overlay programming''. L'idée est de découper le programme en plusieurs blocs séparés, appelés des '''''overlays'''''. Certains blocs sont en permanence en RAM, mais d'autres sont soit chargés en RAM, soit stockés ailleurs. Le ailleurs est souvent le disque dur, ou dans la RAM ''expanded memory'' si elle est disponible. Le va-et-vient des ''overlays'' entre RAM et disque dur était réalisé en logiciel, par le programme lui-même.
[[File:Overlay Programming.svg|centre|vignette|upright=1.5|''Overlay Programming''.]]
L'utilisation de l'''expanded memory'' utilisait l'interruption logicielle 67h, une interruption peu utilisée à l'époque, qui était libre. La carte d'extension était utilisée à travers un pilote de périphérique dédié, qui était appelé via l'interruption 67h.
===Le mode protégé : l'adressage sur 24 et 32 bits===
Par la suite, le mode réel a été remplacé par le '''mode protégé'''. Il utilise la mémoire virtuelle, ce qui fait qu'on devrait le détailler dans le chapitre suivant. Il permettait aussi de dépasser la limite du mébioctet de mémoire. L'espace d'adressage en mode protégé est passé de 24 bits sur le CPU 286, à 32 bits sur le 386 et les CPU suivants.
Les programmes conçus pour le mode réel ne pouvaient pas s'exécuter en mode protégé. Pour corriger cela, le 286 a introduit le '''mode virtuel 8086''', aussi appelé mode V86. Il s'agit d'une technique de virtualisation, ce qui fait qu'on en parlera en détail dans le chapitre sur la virtualisation assistée en matériel. Tout ce que l'on peut dire ici est que le mode V86 a été détourné pour que les applications DOS utilisent la mémoire au-delà du mébioctet, appelée la '''mémoire étendue'''. Les logiciels DOS accédaient à la mémoire étendue à travers un driver DOS dédié (HIMEM.SYS). Les logiciels DOS déplaçaient des données dans la mémoire étendue, puis les rapatriaient en mémoire conventionnelle quand ils en avaient besoin.
Il ne faut pas confondre mémoire étendue et ''expanded memory''. La technique de ''expanded memory'' repose sur de la commutation de banque, demande une carte d'extension dédiée, fonctionne sans mode V86. A l'inverse, la mémoire étendue ne gère pas de commutation de banque, ne demande pas de carte d'extension, mais utilise le mode V86. Par contre, il est possible d'émuler l'''expanded memory'' sans carte d'extension, avec la mémoire étendue. Quelques cartes mères intégraient des techniques pour, mais une émulation logicielle était aussi possible en réécrivant l'interruption 67h.
===Le mode long : l'adressage 64 bits===
Par la suite, les processeurs ont introduit le '''mode long''', dans lequel les adresses font 64 bits. Le CPU en mode long a aussi un jeu d'instruction totalement différent, des registres en plus et d'autres fonctionnalités actives uniquement dans ce mode. Les programmes compilés pour le 64 bits s'exécutent nativement dans ce mode, alors que les programmes 32 et 16 bits s'exécutent dans un mode de compatibilité dédié.
Sur les systèmes 64 bits, le bus d'adresse fait seulement 48 bits afin d'économiser des interconnexions. Avec 48 bits, il manque 64 - 48 = 16 bits d'adresses, qui ne peuvent pas être utilisés pour adresser quoi que ce soit. La règle est que ces 16 bits doivent être tous égaux : soit ils valent tous 0, soient ils sont tous à 1. Les adresses qui respectent cette contrainte sont appelées des '''adresses canoniques'''.
Le résultat est que l'espace d'adressage est coupé en trois sections, comme illustré ci-dessous.
* Les '''adresses canoniques basses''' ont leurs 16 bits de poids fort à 0 et sont situées en bas de l'espace d'adressage, dans les premières adresses.
* Les '''adresses canoniques hautes''' ont leurs 16 bits de poids fort à 1 et sont situées au sommet de l'espace d'adressage, dans les dernières adresses.
* Entre les deux, se trouvent des '''adresses non-canoniques''', qui ne sont pas accessibles. Y accéder déclenche la levée d'une exception matérielle.
{|
|[[File:AMD64-canonical--48-bit.png|vignette|Espace d'adressage x86-64 bits, avec des adresses physiques de 48 bits.]]
|[[File:AMD64-canonical--56-bit.png|vignette|Espace d'adressage x86-64 bits, avec des adresses physiques de 57 bits.]]
|}
: Les futurs systèmes x86 devraient passer à des adresses de 57 bits, les trois sections auront donc des frontières différentes.
Les adresses non-canoniques sont censées être inutilisables. Mais les programmeurs aimeraient bien pouvoir les utiliser pour des ''pointeurs tagués'', à savoir des pointeurs/adresses associées à des informations. L'idée serait d'utiliser les 16 bits de poids fort pour stocker des informations liées au pointeur, seuls les 48 bits restant codant l'adresse. Les 16 bits peuvent être utilisés de manières très diverses.
Un exemple est la technique du '''''memory tagging''''', qui crée une somme de contrôle au pointeur. La somme de contrôle est générée par un algorithme cryptographique, à partir de l'adresse du pointeur. Elle est vérifiée à chaque utilisation du pointeur. Si la somme de contrôle ne correspond pas au pointeur, une erreur est levée. Si jamais un virus ou un code malveillant modifie un pointeur, il ne saura pas comment calculer la somme de contrôle, la somme de contrôle a énormément de chances d'être incorrecte.
Quelques fonctionnalités des processeurs visent à autoriser l'utilisation des adresses non-canoniques. L'idée est que les 16 bits de poids fort sont ignorées lors des accès mémoire, ce qui permet d'utiliser les 16 bits de poids fort à volonté. Il s'agit des techniques ''Top Byte Ignore'' d'ARM, ''Upper Address Ignore'' d'AMD, et ''Linear Address Masking'' d'Intel.
<noinclude>
{{NavChapitre | book=Fonctionnement d'un ordinateur
| prev=Les architectures actionnées par déplacement
| prevText=Les architectures actionnées par déplacement
| next=L'abstraction mémoire et la mémoire virtuelle
| nextText=L'abstraction mémoire et la mémoire virtuelle
}}
</noinclude>
92qcl3yxadsmgz0vh9ewkfst719d6ul
Les cartes graphiques/La mémoire unifiée et la mémoire vidéo dédiée
0
80571
762749
758299
2026-04-02T00:24:44Z
Mewtow
31375
/* La mémoire unifiée */
762749
wikitext
text/x-wiki
Pour rappel, il existe deux types de cartes graphiques : les cartes dédiées et les cartes intégrées. Les '''cartes graphiques dédiées''' sont des cartes graphiques branchées sur des connecteurs/ports de la carte mère. A l'opposé, tous les processeurs modernes intègrent une carte graphique, appelée '''carte graphique intégrée''', ou encore '''IGP''' (''Integrated Graphic Processor''). En somme, les cartes dédiées sont opposées à celles intégrées dans les processeurs modernes.
Les cartes graphiques dédiées ont de la mémoire vidéo intégrée à la carte graphique, sauf pour quelques exceptions dont on parlera plus tard. Par contre, les IGP n'ont pas de mémoire vidéo dédiée, vu qu'on ne peut pas intégrer beaucoup de mémoire dans un processeur. Et cela permet de classer les cartes graphiques en deux types :
* Les cartes graphiques à '''mémoire vidéo dédiée''', à savoir que la carte graphique dispose de sa propre mémoire rien qu'à elle, séparée de la mémoire RAM de l'ordinateur. On fait alors la distinction entre ''RAM système'' et ''RAM vidéo''.
* Les cartes graphiques à '''mémoire unifiée''', où la mémoire RAM est partagée entre le processeur et la carte graphique. Le terme "unifiée" sous-entend que l'on a unifié la mémoire vidéo et la mémoire système (la RAM).
[[File:Répartition de la mémoire entre RAM système et carte graphique.png|centre|vignette|upright=2.5|Répartition de la mémoire entre RAM système et carte graphique]]
La distinction "mémoire dédiée versus unifiée" correspond de très près à la distinction "GPU dédié versus IGP". Dans la grosse majorité des cas, les cartes vidéos dédiées ont une mémoire dédiée, alors que les IGP utilisent la mémoire unifiée. Mais il existe de rares exceptions où une carte vidéo dédiée utilise la mémoire unifiée. Par exemple, la toute première carte graphique AGP, l'Intel 740, ne possédait pas de mémoire vidéo proprement dite, juste un simple ''framebuffer''. Tout le reste, texture comme géométrie, était placé en mémoire système ! Les performances étaient ridicules, mais les cartes étaient peu chères du fait de l’absence de VRAM, ce qui explique que l'Intel 740 a eu un petit succès sur les ordinateurs d'entrée de gamme.
Une autre exception est celle des GPU soudés sur la carte mère, utilisées sur certaines consoles de jeu, ainsi que certains PC portables puissants destinés aux ''gamers''. Pour ces dernières, il est possible d'utiliser aussi bien de la mémoire dédiée que de la mémoire unifiée. Si la plupart des consoles récents utilisent de la VRAM dédiées, d'anciennes consoles de jeu avec un GPU soudé utilisaient une mémoire unifiée, comme la Nintendo 64, pour ne citer qu'elle.
{|class="wikitable"
|-
!
! Mémoire unifiée
! Mémoire dédiée
|-
! GPU dédié
| Quelques rares GPU d'entrée de gamme || Tous les GPU, sauf de rares exceptions
|-
! GPU intégré
| Systématique ||
|-
! GPU soudé
| Anciennes consoles de jeu || Ordinateurs portables modernes
|}
==La mémoire vidéo dédiée==
La mémoire dédiée est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de ''Framebuffer'' : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les sommets de l'image à calculer, ainsi que divers résultats temporaires.
: Dans ce qui suit, la mémoire vidéo des cartes graphiques dédiées sera appelée la VRAM.
===Les mémoires GDDR et autres VRAM===
La VRAM ressemble aux barrettes de RAM qu'on trouve dans nos PC, à quelques différences près. Le point le plus important est qu'elle n'est pas présente sous la forme de barrettes de mémoire. À la place, les puces de mémoire sont soudées sur la carte graphique, sur son PCB vert. La conséquence est que l'on ne peut pas upgrader la VRAM d'une carte vidéo. Le fait que la VRAM est soudée simplifie la conception de la carte graphique, mais a aussi des avantages au niveau électrique et donc en termes de performance.
Les cartes graphiques des années 90-2000, utilisaient la même mémoire que celle des barrettes de RAM, à savoir des DRAM de type FPM, EDO, ou SDRAM (''Synchronous DRAM''). De nos jours, les barrettes de RAM utilisent de la mémoire dite DDR (''Double Data Rate''), alors que les VRAM sont des RAM dites GDDR (''Graphic Double Data Rate''). Les deux se ressemblent beaucoup, mais il y a de petites différences techniques qui sont trop complexes pour être expliquées ici.
: Quelques cartes graphiques ont utilisé de la mémoire non-DDR, comme les GPU ''Laguna'' de ''Cirrus Logic'', qui utilisaient de la RDRAM de feu Rambus, une mémoire RAM qui a utilisée comme RAM système sur certains PC et sur la Nintendo 64. Citons aussi les cartes graphiques ''Matrox Millennium'' et ''ATI 3D Rage Pro'', qui utilisaient de la ''Window DRAM'' (WRAM). Idem avec
Niveau performance, la GDDR se distingue de la DDR simple par une bande passante élevée, proche de la centaine de gigaoctets par secondes sur les GPU modernes. Mais il y a une contrepartie : un temps d'accès très long, de plusieurs centaines de cycles d'horloge. Concrètement, si je veux lire une texture, entre le moment où j'envoie une demande de lecture à la mémoire vidéo, et le moment celle-ci me renvoie les premiers texels, il va se passer entre 200 à 1000 cycles d'horloge GPU. Par contre, une fois les premiers texels reçus, les texels suivants sont disponibles au cycle suivant, et ainsi de suite. En clair, les données lues mettent du temps avant d'arriver, mais elles arrivent par gros paquets.
Les GPU récents sont des monstres de bande passante et ce n'est pas qu'à cause de la GDDR. Une puce mémoire de DDR/GDDR peut lire/écrire 64 bits par cycle d'horloge. Mais les GPU connectent la GDDR de manière à additionner la bande passante de plusieurs puces. Cela implique que chaque puce de RAM a sa propre connexion au GPU, ce qui permet d’accéder à plusieurs puces en parallèle, en même temps. Les GPU actuels sont capables de lire/écrire 192, 256, 384, voire 512 bits par cycle d'horloge. Les techniques de ''dual channel'' permettent de faire la même chose avec la RAM système, mais n’atteignent que 128 bits par cycle - 192/256 bits avec des techniques de ''triple/quad channel''. En clair, le bus mémoire de la GDDR permet de lire/écrire plus de données par cycle d'horloge qu'une RAM système, de 2 à 8 fois plus.
[[File:Puces mémories d'un GPU et d'une barrette de mémoire.png|centre|vignette|upright=2|Puces mémoires d'un GPU et d'une barrette de mémoire.]]
La différence entre débit et temps d'accès est primordiale sur les GPU modernes comme anciens. Toute l'architecture de la carte graphique est conçue de manière à prendre en compte ce temps d'attente. Les techniques employées sont multiples, et ne sont pas inconnues à ceux qui ont déjà lu un cours d'architecture des ordinateurs : mémoire caches, hiérarchie de caches, ''multithreading'' matériel au niveau du processeur, optimisations des accès mémoire comme des ''Load-Store Queues'' larges, des ''coalesing write buffers'', etc. Mais toutes ces techniques sont techniquement incorporées dans les processeurs de ''shaders'' et dans les circuits fixes. Aussi nous ne pouvons pas en parler dans ce chapitre. À une exception près : l'usage de caches et de ''local stores''.
===Les transferts ''Direct Memory Access''===
Pour échanger des données entre la RAM et la mémoire vidéo, les GPU utilisent la technologie ''Direct Memory Access'', aussi appelée DMA. Elle permet à un périphérique de lire/écrire un bloc de mémoire RAM, sans intervention du processeur, par l'intermédiaire du bus PCI Express.
Pour cela, le GPU intègre un circuit dédié à la gestion des transferts DMA, appelé le '''contrôleur DMA''', qui lit des données en RAM système pour les copier en RAM vidéo (ou inversement, mais c'est plus rare). Précisément, le contrôleur DMA copie un bloc de mémoire, de données consécutives en mémoire, par exemple un bloc de 128 mégaoctets, un bloc de 64 kiloctets, ou autre. Le processeur configure le contrôleur DMA en lui indiquant l'adresse de départ du bloc de mémoire, sa taille, et quelques informations annexes. Le contrôleur DMA lit alors les données une par une, et les écrit dans la mémoire vidéo.
===La mémoire vidéo est mappée dans l'espace d'adressage du CPU===
Les GPU doivent souvent échanger des données avec le processeur. Des données doivent être copiées de la mémoire RAM vers la VRAM. De plus, le CPU peut aussi adresser directement la VRAM. Pour cela, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, grâce à la technique des '''entrées-sorties mappées en mémoire'''. Et c'est ce qui est fait pour le GPU : une partie des adresses est détournée vers le GPU. Typiquement un bloc d'adresse de la même taille que la mémoire vidéo est détournée : elles n'adressent plus de la RAM, mais la directement la mémoire vidéo de la carte graphique. En clair, le processeur voit la mémoire vidéo et peut lire ou écrire dedans directement.
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
Intuitivement, on se dit que toute la mémoire vidéo est visible par le CPU, mais le bus PCI, AGP ou PCI Express ont leur mot à dire. Le bus PCI permettait au CPU d'adresser une fenêtre de 256 mégaoctets de VRAM maximum, en raison d’une sombre histoire de configuration des ''Base Address Registers'' (BARs). Les registres BAR étaient utilisés pour gérer les transferts DMA, mais aussi pour l'adressage direct.
Le PCI Express était aussi dans ce cas avant 2008. La gestion de la mémoire vidéo était alors difficile, mais on pouvait adresser plus de 256 mégaoctets, en déplaçant la fenêtre de 256 mégaoctets dans la mémoire vidéo. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''resizable bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
==La mémoire unifiée==
Avec la mémoire unifiée, une partie de la RAM système est détournée pour servir de mémoire vidéo. La quantité d'adresses détournées est généralement réglable avec un réglage dans le BIOS. On peut ainsi choisir d'allouer 64, 128 ou 256 mégaoctets de mémoire système pour la carte vidéo, sur un ordinateur avec 4 gigaoctets de RAM. Les GPU modernes sont plus souples et fournissent deux réglages : une quantité de RAM vidéo minimale et une quantité de RAM maximale que le GPU ne peut pas dépasser. Par exemple, il est possible de régler le GPU de manière à ce qu'il ait 64 mégaoctets rien que pour lui, mais qu'il puisse avoir accès à maximum 1 gigaoctet s'il en a besoin. Cela fait au total 960 mégaoctets (1024-64) qui peut être alloués au choix à la carte graphique ou au reste des programmes en cours d’exécution, selon les besoins.
[[File:Partage de la mémoire unifiée entre CPU et GPU.png|centre|vignette|upright=2|Répartition de la mémoire entre RAM système et carte graphique]]
===Les GPU dédiés avec mémoire unifiée===
Il existe des cartes dédiées qui utilisent pourtant la mémoire unifiée, par exemple l'Intel 740. Pour lire en mémoire RAM, elles doivent passer par l'intermédiaire du bus AGP, PCI ou PCI-Express. Et ce bus est très lent, bien plus que ne le serait une mémoire vidéo normale. Aussi, les performances sont exécrables. J'insiste sur le fait que l'on parle des cartes graphiques dédiées, mais pas des cartes graphiques soudées des consoles de jeu.
D'ailleurs, de telles cartes dédiées incorporent un ''framebuffer'' directement dans la carte graphique. Il n'y a pas le choix, le VDC de la carte graphique doit accéder à une mémoire suffisamment rapide pour alimenter l'écran. Ils ne peuvent pas prendre le risque d'aller lire la RAM, dont le temps de latence est élevé, et qui peut potentiellement être réservée par le processeur pendant l’affichage d'une image à l'écran.
===Les GPU intégrés===
Les GPU intégrés ou soudés passent par le bus AGP ou PCI Express pour lire des données en RAM système. Mais leur accès à la RAM passe par les mêmes voies que le CPU. Les GPU et le processeur sont reliés à la RAM par un bus dédié appelé le '''bus mémoire'''. Il existe même sans GPU intégré : tous les processeurs sont reliés à la RAM par un tel bus. Si le CPU intègre un IGPU, il greffe l'IGPU sur ce bus mémoire existant.
Un défaut de cette approche est que le débit du bus système est partagé entre le GPU et le processeur. En clair, si le bus mémoire peut transférer 20 gigas de données par secondes, il faudra partager ces 20 gigas/seconde entre CPU et GPU. Par exemple, le CPU aura droit à 15 gigas par secondes, le GPU seulement 5 gigas. Divers circuits d'arbitrage s'occupent de répartir équitablement le bus système, selon les besoins, mais ça reste un compromis imparfait.
[[File:Echanges de données entre CPU et GPU avec une mémoire unifiée.png|centre|vignette|upright=2|Connexion du bus mémoire au CPU et à un GPU soudé sur la carte mère.]]
N'allez cependant pas croire que les GPU intégrés n'ont que des désavantages. Ils disposent d'un avantage bien spécifique : la '''''zero-overhead copy''''', terme barbare mais qui cache une réalité très simple. Avec une mémoire dédiée, le processeur doit copier des données de la RAM système dans la RAM vidéo. Les copies en question se font souvent avant de démarrer le rendu 3D, par exemple lors du chargement d'un niveau dans un jeu vidéo. Elles peuvent aussi se faire lors du rendu, bien que ce soit plus rare. Et ces copies ont un cout en performance. Par contre, avec la mémoire unifié, pas besoin de faire de copie d'une mémoire à l'autre. Le processeur envoie juste une commande du GPU, qui indique l'adresse des données en RAM, leur position dans la RAM.
Le processeur et le GPU intègrent des mémoires caches, afin de réduire l'usage du bus mémoire. Et l'intégration des caches avec un GPU intégré est assez intéressante. Le CPU et l'IGPU peuvent partager certains caches. Par exemple, les processeurs Skylake et Sandy Bridge d'Intel, le CPU et GPU avaient leurs propres caches L2 et L1, mais ils partageaient le cache L3. En général, le partage ne touche que le cache de dernier niveau, le cache le plus gros et le plus proche de la mémoire, à savoir le cache L3 ou L4.
Sur les processeurs modernes, le CPU et le GPU ont leur propre cache L3/L4, afin avoir des caches plus spécialisés. Les caches L3/L4 sont plus gros pour le processeur que pour le GPU, ils vont à des fréquences différentes, sont alimentés par des tensions différentes, etc. De plus, le cache du CPU est optimisé pour un temps d'accès faible, alors que celui du GPU est optimisé pour un fort débit mémoire. Utiliser des caches séparés entraine des problèmes de cohérence des caches, qui ont été vus dans le chapitre sur les caches des processeurs de shaders.
[[File:Caches sur un iGPU.png|centre|vignette|upright=2.5|Caches sur un iGPU]]
===Les GPU des consoles===
Les consoles de jeu utilisent souvent la mémoire unifiée, même les consoles récentes. Pour les consoles de salon, les consoles Nintendo ont été les pionnières de la mémoire unifiée, XBOX l'a adopté dès le début, et les Playstation ont été les dernières à l'utiliser.
* Pour les consoles de 5ème génération, Nintendo 64 utilisait déjà la mémoire unifiée, alors que les autres consoles de l'époque faisaient avec une mémoire vidéo dédiée.
* Pour la 6ème génération, la Gamecube et la Xbox utilisaient la mémoire unifiée, pas la Playstation 2. A partir de la génération suivante, la mémoire unifiée est devenue la solution dominante.
Pour la 7ème génération, seule la Playstation 3 n'utilisait pas la mémoire unifiée, mais XBOX et la Wii le faisait.
* A partir de la 8ème génération, toutes les consoles utilisent la mémoire unifiée.
Il faut noter que la mémoire utilisée sur ces consoles est une mémoire GDDR, soit le type de mémoire utilisé pour les mémoires vidéo dédiées ! Ce ne sont pas des mémoires DDR normales, optimisées pour fonctionner avec des CPU.
Il faut noter que les GPU des consoles doivent s'adapter à cette mémoire unfiiée, histoire de conserver de bonnes performances. Les limitations de bande passante se manifestent les GPU des consoles sont adaptés pour limiter la casse. Aussi, les GPU des consoles ne sont pas exactement les mêmes que ceux des PC, et qu'il existe des toutes petites différences. Par exemple, le GPU de la XBOX est une Geforce 3 légèrement modifiée, en partie pour s'adapter à la mémoire unifiée.
Une première adaptation possible est simplement d'ajouter des mémoires caches, ou d'agrandir les mémoires caches existantes. Par exemple, il est possible de doubler le cache de textures ou le cache de sommets.
==La mémoire virtuelle des GPUs==
Pour commencer, parlons d'un point important, à savoir l'espace d'adressage du GPU. L''''espace d'adressage''' d'un processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées.
L'espace d'adressage du CPU est quelque peu particulier. Depuis les années 80-90, les logiciels n'adressent pas la mémoire RAM directement. Tous les processeurs gèrent un système de mémoire virtuelle, qui donne l'illusion aux programmes d'avoir accès à toute la mémoire adressable, tout l'espace d'adressage. Par exemple, sur les systèmes 32 bits, chaque programme a accès à tout l'espace d'adressage de 4 gigaoctets, et il ne voit pas les autres programmes dedans. C'est une illusion qui a de nombreux avantages : les programmes sont isolés les uns des autres, un programme ne peut pas lire dans la mémoire d'un autre, les programmes n'ont pas à se soucier de la quantité de RAM installée dans l'ordinateur, etc.
Par contre, cela implique que les adresses manipulées par les programmes sont des adresses fictives, qui doivent être traduites en adresses physiques. Les données situées à une adresse dans l'espace d'adressage ne sont pas à la même adresse en RAM. On fait ainsi la distinction entre adresse physique et logique : les adresses logiques sont les fausses adresses, les adresses physiques sont les vraies adresses en RAM.
Rien de tout cela ne devrait vous surprendre si vous avez déjà lu un cours d'architecture des ordinateurs. Maintenant, passons à quelque chose auquel vous n'avez peut-être pas pensé : qu'en est-il du GPU ? La réponse est que non seulement cela dépend de si le GPU est dédié ou intégré, mais que cela dépend aussi de si le GPU est ancien ou non. Les anciens GPU ne géraient pas la mémoire virtuelle, les nouveaux ont leur propre système de mémoire virtuelle séparé du CPU !
===L'abstraction mémoire des GPU===
Cependant, cela pose un léger problème : la communication avec les programmes et les API graphiques est perturbée. Le pilote de périphérique reçoit des adresses virtuelles de la part des applications, mais il doit gérer la mémoire vidéo en utilisant des adresses physiques. Et cela posait de nombreux problèmes pour les pilotes de GPU.
Le cas le plus facile à expliquer est celui des GPU dédiés. Le pilote de GPU alimente la mémoire vidéo avec des transferts DMA et le contrôleur DMA doit être configuré avec des adresses physiques pour faire son travail. Or, les API 3D leur donnaient des adresses virtuelles, pour localiser les textures, ''mesh'', shaders compilés et autres. Et c'est à eux et au système d'exploitation de traduire ces adresses en adresses physiques. Des cas similaires apparaissent sur des GPU intégrés.
Sous Windows, du temps de l'ancien ''Windows Display Driver Model'' (WDDM), c'était le système d’exploitation qui gérait cela. Le WDDM déportait une partie de la gestion du GPU dans le noyau de l'OS, dont la gestion de la mémoire vidéo, vu que seul lui pouvait faire la traduction d'adresse (il a accès au tables des pages). Le pilote de GPU envoyait les commandes matérielles au noyau de l'OS, qui les patchait, en remplaçant les adresses virtuelles par des adresses physiques. Le pilote envoyait alors les commandes traduites au GPU.
Avec le WDDM 2.0, les GPU supportent maintenant la mémoire virtuelle. Cependant, il faut noter que les GPU utilisent une mémoire virtuelle séparée de celle du CPU. Le processeur et le GPU ont deux espaces d'adressage différents. Concrètement, une adresse virtuelle n'adresse pas la même adresse physique selon qu'elle est utilisée par le GPU. De même, la même adresse physique correspondra à des adresses virtuelles différentes entre CPU et GPU. Aussi, on parle de '''mémoire virtuelle GPU''' pour la distinguer de la mémoire virtuelle du processeur.
[[File:Desktop computer bus bandwidths.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle du CPU et du GPU.]]
Même si la mémoire virtuelle du GPU n'est pas celle du CPU, cela simplifie grandement la gestion de la mémoire vidéo. Le pilote de GPU peut travailler directement avec des adresses virtuelles du GPU, et gérer la mémoire vidéo de lui-même, dans avoir à déléguer une partie du travail au noyau de l'OS. Plus besoin de traduire les adresses en adresses physiques, c'est le GPU qui s'en charge de lui-même ! D'ailleurs, cet avantage fait que la mémoire virtuelle GPU est aussi utilisée avec des GPU intégré, qui n'ont pas besoin de faire de copies entre RAM système et RAM vidéo.
[[File:Integrated graphics with distinct memory allocation.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle CPU et GPU, avec un GPU intégré.]]
Pour gérer la mémoire virtuelle, les GPU intègrent un circuit appelé la '''''Graphics address remapping table''''', abrévié en GART. La GART est techniquement une une ''Memory Management Unit'' (MMU), à savoir un circuit spécialisé qui s'occupe de traduire les adresses virtuelles en adresses physiques, elle prend en charge la mémoire virtuelle. La dite MMU étant intégrée dans un périphérique d'entrée-sortie (IO), ici la carte graphique, elle est appelée une IO-MMU (''Input Output-MMU''). Toutes les cartes graphiques utilisant les bus AGP ou PCI-Express intégrent une GART/IO-MMU.
La GART est configurée par le pilote de GPU, afin de gérer la mémoire virtuelle au mieux. Et cela explique que la mémoire virtuelle du GPU et du CPU soient séparées. Le pilote de GPU coopére avec le système d'exploitation pour configurer la GART, mais cette coopération ne peut pas être parfaite. On ne peut pas permettre au pilote de GPU d'avoir accès à la table des pages ou d'autres structures impliquées dans la traduction d'adresse : le risque de sécurité est trop grand. Avoir deux mémoires virtuelles séparées aide grandement le travail du pilote de GPU.
Cependant, quelques technologies permette au CPU et au GPU d'utiliser le même espace d'adressage, de fusionner la mémoire virtuelle du CPU et du GPU. Par exemple, la technologie ''Heterogeneous System Architecture'' permet cela, entre autres fonctionnalités. Elles permettent de synchroniser la MMU du processeur et l'IO-MMU du GPU.
{|
|[[File:HSA-enabled virtual memory with distinct graphics card.svg|vignette|upright=2|HSA-enabled virtual memory with distinct graphics card]]
|[[File:HSA-enabled integrated graphics.svg|vignette|upright=2|HSA-enabled integrated graphics]]
|}
===La mémoire virtuelle des GPU dédiés===
Pour rappel, la mémoire virtuelle permet à un CPU d'utiliser plus de RAM qu'il n'y en a d'installée dans l'ordinateur. Par exemple, elle permet au CPU de gérer 4 gigas de RAM sur un ordinateur qui n'en contient que trois, le gigaoctet de trop étant en réalité simulé par un fichier sur le disque dur. La technique est utilisée par tous les processeurs modernes.
La mémoire virtuelle des GPUs dédiés fait la même chose, sauf que le surplus d'adresses n'est pas stockés sur le disque dur dans un fichier pagefile, mais est dans la RAM système. Pour le dire autrement, ces cartes dédiées peuvent utiliser la mémoire système si jamais la mémoire vidéo est pleine. Cela permet au GPU d'adresser plus de RAM qu'en a la mémoire vidéo. Par exemple, si la carte vidéo a 2 giga-octets de RAM, la carte graphique peut être capable d'en adresser 8 : 2 gigas en RAM vidéo, et 6 autres gigas en RAM système. Le GPU peut lire directement des données en RAM, sans forcément les copier en mémoire vidéo.
[[File:Mémoire virtuelle des cartes graphiques dédiées.png|centre|vignette|upright=2|Mémoire virtuelle des cartes graphiques dédiées]]
La technologie s'est démocratisée avec le bus AGP, dont la fonctionnalité dite d'''AGP texturing'' permettait de lire ou écrire directement dans la mémoire RAM, sans passer par le processeur. D'ailleurs, la carte graphique Intel i740 n'avait pas de mémoire vidéo et se débrouillait uniquement avec la mémoire système. C'est l'AGP qui a introduit le GART, la fameuse IO-MMU mentionnée plus haut.
L'arrivée du bus PCI-Express ne changea pas la donne, si ce n'est que le bus était plus rapide, ce qui améliorait les performances. Au début, seules les cartes graphiques PCI-Express d'entrée de gamme pouvaient accéder à certaines portions de la mémoire RAM grâce à des technologies adaptées, comme le TurboCache de NVIDIA ou l'HyperMemory d'AMD. Mais la technologie s'est aujourd'hui étendue. De nos jours, toutes les cartes vidéos modernes utilisent la RAM système en plus de la mémoire vidéo, mais seulement en dernier recours, soit quand la mémoire vidéo est quasiment pleine, soit pour faciliter les échanges de données avec le processeur. C'est typiquement le pilote de la carte graphique qui décide ce qui va dans la mémoire vidéo et la mémoire système, et il fait au mieux de manière à avoir les performances optimales.
===Les GPU utilisent la pagination===
Le GPU utilise la technique dite de la pagination, à savoir que la RAM système et la RAM du GPU sont découpées en pages de taille fixe, généralement 4 kilo-octets. Un GPU dédié échange des pages entre RAM système et mémoire vidéo. Lors d'un transfert DMA, la page en RAM système est copiée en mémoire vidéo. S'il n'y a pas assez de place en mémoire vidéo, le GPU rapatrie une page de mémoire vidéo vers la RAM système. La page rapatriée en RAM système est choisie par un algorithme spécialisé. Un GPU intégré n'a pas besoin de copie, il lit directement la page voulue en RAM système.
La traduction des adresses virtuelles en adresses physique se fait au niveau de la page. Une adresse est coupée en deux parts : un numéro de page, et la position de la donnée dans la page. La position dans la page ne change pas lors de la traduction d'adresse, mais le numéro de page est lui traduit. Le numéro de page virtuel est remplacé par un numéro de page physique lors de la traduction.
Pour remplacer le numéro de page virtuel en numéro physique, il faut utiliser une table de translation, appelée la '''table des pages''', qui associe un numéro de page logique à un numéro de page physique. Le système d'exploitation dispose de sa table des pages, qui n'est pas accesible au GPU. Par contre, le GPU dispose d'une sorte de mini-table des pages, qui contient les associations page virtuelle-physique utiles pour traiter les commandes GPU, et rien d'autre. En clair, une sorte de sous-ensemble de la table des pages de l'OS, mais spécifique au GPU. La mini-table des pages est gérée par le pilote de périphérique, qui remplit la mini-table des pages. La mini-table des pages est mémorisée dans une mémoire intégrée au GPU, et précisément dans la MMU.
===Le contrôleur DMA et l'IO-MMU des GPU dédiés===
Sur les GPU dédiés, le contrôleur DMA est souvent fusionné avec l'IO-MMU. En effet, il s'occupe de la copie des pages entre mémoire vidéo et RAM système. Le contrôleur DMA reçoit des adresses provenant du pilote de périphérique, qui sont des adresses virtuelles. Mais vu qu'il accède à la RAM système, il doit faire la traduction entre adresses virtuelles qu'il reçoit et adresses physiques qu'il émet, ce qui implique qu'il sert d'IO-MMU.
Même si la mémoire virtuelle GPU a été intégrée dans Windows assez tard, du temps de l'AGP et du PCI-Express, la technologie existait vraisemblablement sur certaines cartes graphiques au format PCI, même la documentation est assez rare. Seule certitude : la carte graphique NV1 de NVIDIA, leur toute première carte graphique, disposait d'un contrôleur DMA avec une IO-MMU intégrée. Le fonctionnement de cette IOMMU est décrite dans le brevet "US5758182A : DMA controller translates virtual I/O device address received directly from application program command to physical i/o device address of I/O device on device bus", des inventeurs David S. H. Rosenthal et Curtis Priem.
[[File:Microarchitecture du GPU NV1 de NVIDIA.png|centre|vignette|upright=2|Microarchitecture du GPU NV1 de NVIDIA]]
{{NavChapitre | book=Les cartes graphiques
| prev=Les caches d'un processeur de shader
| prevText=Les caches d'un processeur de shader
| next=Le rendu d'une scène 3D : l'API graphique
| netxText=Le rendu d'une scène 3D : l'API graphique
}}{{autocat}}
0rbilxz6yuelpfnous1la50dqe7fs3y
762750
762749
2026-04-02T00:42:56Z
Mewtow
31375
/* Les GPU des consoles */
762750
wikitext
text/x-wiki
Pour rappel, il existe deux types de cartes graphiques : les cartes dédiées et les cartes intégrées. Les '''cartes graphiques dédiées''' sont des cartes graphiques branchées sur des connecteurs/ports de la carte mère. A l'opposé, tous les processeurs modernes intègrent une carte graphique, appelée '''carte graphique intégrée''', ou encore '''IGP''' (''Integrated Graphic Processor''). En somme, les cartes dédiées sont opposées à celles intégrées dans les processeurs modernes.
Les cartes graphiques dédiées ont de la mémoire vidéo intégrée à la carte graphique, sauf pour quelques exceptions dont on parlera plus tard. Par contre, les IGP n'ont pas de mémoire vidéo dédiée, vu qu'on ne peut pas intégrer beaucoup de mémoire dans un processeur. Et cela permet de classer les cartes graphiques en deux types :
* Les cartes graphiques à '''mémoire vidéo dédiée''', à savoir que la carte graphique dispose de sa propre mémoire rien qu'à elle, séparée de la mémoire RAM de l'ordinateur. On fait alors la distinction entre ''RAM système'' et ''RAM vidéo''.
* Les cartes graphiques à '''mémoire unifiée''', où la mémoire RAM est partagée entre le processeur et la carte graphique. Le terme "unifiée" sous-entend que l'on a unifié la mémoire vidéo et la mémoire système (la RAM).
[[File:Répartition de la mémoire entre RAM système et carte graphique.png|centre|vignette|upright=2.5|Répartition de la mémoire entre RAM système et carte graphique]]
La distinction "mémoire dédiée versus unifiée" correspond de très près à la distinction "GPU dédié versus IGP". Dans la grosse majorité des cas, les cartes vidéos dédiées ont une mémoire dédiée, alors que les IGP utilisent la mémoire unifiée. Mais il existe de rares exceptions où une carte vidéo dédiée utilise la mémoire unifiée. Par exemple, la toute première carte graphique AGP, l'Intel 740, ne possédait pas de mémoire vidéo proprement dite, juste un simple ''framebuffer''. Tout le reste, texture comme géométrie, était placé en mémoire système ! Les performances étaient ridicules, mais les cartes étaient peu chères du fait de l’absence de VRAM, ce qui explique que l'Intel 740 a eu un petit succès sur les ordinateurs d'entrée de gamme.
Une autre exception est celle des GPU soudés sur la carte mère, utilisées sur certaines consoles de jeu, ainsi que certains PC portables puissants destinés aux ''gamers''. Pour ces dernières, il est possible d'utiliser aussi bien de la mémoire dédiée que de la mémoire unifiée. Si la plupart des consoles récents utilisent de la VRAM dédiées, d'anciennes consoles de jeu avec un GPU soudé utilisaient une mémoire unifiée, comme la Nintendo 64, pour ne citer qu'elle.
{|class="wikitable"
|-
!
! Mémoire unifiée
! Mémoire dédiée
|-
! GPU dédié
| Quelques rares GPU d'entrée de gamme || Tous les GPU, sauf de rares exceptions
|-
! GPU intégré
| Systématique ||
|-
! GPU soudé
| Anciennes consoles de jeu || Ordinateurs portables modernes
|}
==La mémoire vidéo dédiée==
La mémoire dédiée est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de ''Framebuffer'' : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les sommets de l'image à calculer, ainsi que divers résultats temporaires.
: Dans ce qui suit, la mémoire vidéo des cartes graphiques dédiées sera appelée la VRAM.
===Les mémoires GDDR et autres VRAM===
La VRAM ressemble aux barrettes de RAM qu'on trouve dans nos PC, à quelques différences près. Le point le plus important est qu'elle n'est pas présente sous la forme de barrettes de mémoire. À la place, les puces de mémoire sont soudées sur la carte graphique, sur son PCB vert. La conséquence est que l'on ne peut pas upgrader la VRAM d'une carte vidéo. Le fait que la VRAM est soudée simplifie la conception de la carte graphique, mais a aussi des avantages au niveau électrique et donc en termes de performance.
Les cartes graphiques des années 90-2000, utilisaient la même mémoire que celle des barrettes de RAM, à savoir des DRAM de type FPM, EDO, ou SDRAM (''Synchronous DRAM''). De nos jours, les barrettes de RAM utilisent de la mémoire dite DDR (''Double Data Rate''), alors que les VRAM sont des RAM dites GDDR (''Graphic Double Data Rate''). Les deux se ressemblent beaucoup, mais il y a de petites différences techniques qui sont trop complexes pour être expliquées ici.
: Quelques cartes graphiques ont utilisé de la mémoire non-DDR, comme les GPU ''Laguna'' de ''Cirrus Logic'', qui utilisaient de la RDRAM de feu Rambus, une mémoire RAM qui a utilisée comme RAM système sur certains PC et sur la Nintendo 64. Citons aussi les cartes graphiques ''Matrox Millennium'' et ''ATI 3D Rage Pro'', qui utilisaient de la ''Window DRAM'' (WRAM). Idem avec
Niveau performance, la GDDR se distingue de la DDR simple par une bande passante élevée, proche de la centaine de gigaoctets par secondes sur les GPU modernes. Mais il y a une contrepartie : un temps d'accès très long, de plusieurs centaines de cycles d'horloge. Concrètement, si je veux lire une texture, entre le moment où j'envoie une demande de lecture à la mémoire vidéo, et le moment celle-ci me renvoie les premiers texels, il va se passer entre 200 à 1000 cycles d'horloge GPU. Par contre, une fois les premiers texels reçus, les texels suivants sont disponibles au cycle suivant, et ainsi de suite. En clair, les données lues mettent du temps avant d'arriver, mais elles arrivent par gros paquets.
Les GPU récents sont des monstres de bande passante et ce n'est pas qu'à cause de la GDDR. Une puce mémoire de DDR/GDDR peut lire/écrire 64 bits par cycle d'horloge. Mais les GPU connectent la GDDR de manière à additionner la bande passante de plusieurs puces. Cela implique que chaque puce de RAM a sa propre connexion au GPU, ce qui permet d’accéder à plusieurs puces en parallèle, en même temps. Les GPU actuels sont capables de lire/écrire 192, 256, 384, voire 512 bits par cycle d'horloge. Les techniques de ''dual channel'' permettent de faire la même chose avec la RAM système, mais n’atteignent que 128 bits par cycle - 192/256 bits avec des techniques de ''triple/quad channel''. En clair, le bus mémoire de la GDDR permet de lire/écrire plus de données par cycle d'horloge qu'une RAM système, de 2 à 8 fois plus.
[[File:Puces mémories d'un GPU et d'une barrette de mémoire.png|centre|vignette|upright=2|Puces mémoires d'un GPU et d'une barrette de mémoire.]]
La différence entre débit et temps d'accès est primordiale sur les GPU modernes comme anciens. Toute l'architecture de la carte graphique est conçue de manière à prendre en compte ce temps d'attente. Les techniques employées sont multiples, et ne sont pas inconnues à ceux qui ont déjà lu un cours d'architecture des ordinateurs : mémoire caches, hiérarchie de caches, ''multithreading'' matériel au niveau du processeur, optimisations des accès mémoire comme des ''Load-Store Queues'' larges, des ''coalesing write buffers'', etc. Mais toutes ces techniques sont techniquement incorporées dans les processeurs de ''shaders'' et dans les circuits fixes. Aussi nous ne pouvons pas en parler dans ce chapitre. À une exception près : l'usage de caches et de ''local stores''.
===Les transferts ''Direct Memory Access''===
Pour échanger des données entre la RAM et la mémoire vidéo, les GPU utilisent la technologie ''Direct Memory Access'', aussi appelée DMA. Elle permet à un périphérique de lire/écrire un bloc de mémoire RAM, sans intervention du processeur, par l'intermédiaire du bus PCI Express.
Pour cela, le GPU intègre un circuit dédié à la gestion des transferts DMA, appelé le '''contrôleur DMA''', qui lit des données en RAM système pour les copier en RAM vidéo (ou inversement, mais c'est plus rare). Précisément, le contrôleur DMA copie un bloc de mémoire, de données consécutives en mémoire, par exemple un bloc de 128 mégaoctets, un bloc de 64 kiloctets, ou autre. Le processeur configure le contrôleur DMA en lui indiquant l'adresse de départ du bloc de mémoire, sa taille, et quelques informations annexes. Le contrôleur DMA lit alors les données une par une, et les écrit dans la mémoire vidéo.
===La mémoire vidéo est mappée dans l'espace d'adressage du CPU===
Les GPU doivent souvent échanger des données avec le processeur. Des données doivent être copiées de la mémoire RAM vers la VRAM. De plus, le CPU peut aussi adresser directement la VRAM. Pour cela, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, grâce à la technique des '''entrées-sorties mappées en mémoire'''. Et c'est ce qui est fait pour le GPU : une partie des adresses est détournée vers le GPU. Typiquement un bloc d'adresse de la même taille que la mémoire vidéo est détournée : elles n'adressent plus de la RAM, mais la directement la mémoire vidéo de la carte graphique. En clair, le processeur voit la mémoire vidéo et peut lire ou écrire dedans directement.
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
Intuitivement, on se dit que toute la mémoire vidéo est visible par le CPU, mais le bus PCI, AGP ou PCI Express ont leur mot à dire. Le bus PCI permettait au CPU d'adresser une fenêtre de 256 mégaoctets de VRAM maximum, en raison d’une sombre histoire de configuration des ''Base Address Registers'' (BARs). Les registres BAR étaient utilisés pour gérer les transferts DMA, mais aussi pour l'adressage direct.
Le PCI Express était aussi dans ce cas avant 2008. La gestion de la mémoire vidéo était alors difficile, mais on pouvait adresser plus de 256 mégaoctets, en déplaçant la fenêtre de 256 mégaoctets dans la mémoire vidéo. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''resizable bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
==La mémoire unifiée==
Avec la mémoire unifiée, une partie de la RAM système est détournée pour servir de mémoire vidéo. La quantité d'adresses détournées est généralement réglable avec un réglage dans le BIOS. On peut ainsi choisir d'allouer 64, 128 ou 256 mégaoctets de mémoire système pour la carte vidéo, sur un ordinateur avec 4 gigaoctets de RAM. Les GPU modernes sont plus souples et fournissent deux réglages : une quantité de RAM vidéo minimale et une quantité de RAM maximale que le GPU ne peut pas dépasser. Par exemple, il est possible de régler le GPU de manière à ce qu'il ait 64 mégaoctets rien que pour lui, mais qu'il puisse avoir accès à maximum 1 gigaoctet s'il en a besoin. Cela fait au total 960 mégaoctets (1024-64) qui peut être alloués au choix à la carte graphique ou au reste des programmes en cours d’exécution, selon les besoins.
[[File:Partage de la mémoire unifiée entre CPU et GPU.png|centre|vignette|upright=2|Répartition de la mémoire entre RAM système et carte graphique]]
===Les GPU dédiés avec mémoire unifiée===
Il existe des cartes dédiées qui utilisent pourtant la mémoire unifiée, par exemple l'Intel 740. Pour lire en mémoire RAM, elles doivent passer par l'intermédiaire du bus AGP, PCI ou PCI-Express. Et ce bus est très lent, bien plus que ne le serait une mémoire vidéo normale. Aussi, les performances sont exécrables. J'insiste sur le fait que l'on parle des cartes graphiques dédiées, mais pas des cartes graphiques soudées des consoles de jeu.
D'ailleurs, de telles cartes dédiées incorporent un ''framebuffer'' directement dans la carte graphique. Il n'y a pas le choix, le VDC de la carte graphique doit accéder à une mémoire suffisamment rapide pour alimenter l'écran. Ils ne peuvent pas prendre le risque d'aller lire la RAM, dont le temps de latence est élevé, et qui peut potentiellement être réservée par le processeur pendant l’affichage d'une image à l'écran.
===Les GPU intégrés===
Les GPU intégrés ou soudés passent par le bus AGP ou PCI Express pour lire des données en RAM système. Mais leur accès à la RAM passe par les mêmes voies que le CPU. Les GPU et le processeur sont reliés à la RAM par un bus dédié appelé le '''bus mémoire'''. Il existe même sans GPU intégré : tous les processeurs sont reliés à la RAM par un tel bus. Si le CPU intègre un IGPU, il greffe l'IGPU sur ce bus mémoire existant.
Un défaut de cette approche est que le débit du bus système est partagé entre le GPU et le processeur. En clair, si le bus mémoire peut transférer 20 gigas de données par secondes, il faudra partager ces 20 gigas/seconde entre CPU et GPU. Par exemple, le CPU aura droit à 15 gigas par secondes, le GPU seulement 5 gigas. Divers circuits d'arbitrage s'occupent de répartir équitablement le bus système, selon les besoins, mais ça reste un compromis imparfait.
[[File:Echanges de données entre CPU et GPU avec une mémoire unifiée.png|centre|vignette|upright=2|Connexion du bus mémoire au CPU et à un GPU soudé sur la carte mère.]]
N'allez cependant pas croire que les GPU intégrés n'ont que des désavantages. Ils disposent d'un avantage bien spécifique : la '''''zero-overhead copy''''', terme barbare mais qui cache une réalité très simple. Avec une mémoire dédiée, le processeur doit copier des données de la RAM système dans la RAM vidéo. Les copies en question se font souvent avant de démarrer le rendu 3D, par exemple lors du chargement d'un niveau dans un jeu vidéo. Elles peuvent aussi se faire lors du rendu, bien que ce soit plus rare. Et ces copies ont un cout en performance. Par contre, avec la mémoire unifié, pas besoin de faire de copie d'une mémoire à l'autre. Le processeur envoie juste une commande du GPU, qui indique l'adresse des données en RAM, leur position dans la RAM.
Le processeur et le GPU intègrent des mémoires caches, afin de réduire l'usage du bus mémoire. Et l'intégration des caches avec un GPU intégré est assez intéressante. Le CPU et l'IGPU peuvent partager certains caches. Par exemple, les processeurs Skylake et Sandy Bridge d'Intel, le CPU et GPU avaient leurs propres caches L2 et L1, mais ils partageaient le cache L3. En général, le partage ne touche que le cache de dernier niveau, le cache le plus gros et le plus proche de la mémoire, à savoir le cache L3 ou L4.
Sur les processeurs modernes, le CPU et le GPU ont leur propre cache L3/L4, afin avoir des caches plus spécialisés. Les caches L3/L4 sont plus gros pour le processeur que pour le GPU, ils vont à des fréquences différentes, sont alimentés par des tensions différentes, etc. De plus, le cache du CPU est optimisé pour un temps d'accès faible, alors que celui du GPU est optimisé pour un fort débit mémoire. Utiliser des caches séparés entraine des problèmes de cohérence des caches, qui ont été vus dans le chapitre sur les caches des processeurs de shaders.
[[File:Caches sur un iGPU.png|centre|vignette|upright=2.5|Caches sur un iGPU]]
===Les GPU des consoles===
Les consoles de jeu utilisent souvent la mémoire unifiée, même les consoles récentes. Pour les consoles de salon, les consoles Nintendo ont été les pionnières de la mémoire unifiée, XBOX l'a adopté dès le début, et les Playstation ont été les dernières à l'utiliser.
* Pour les consoles de 5ème génération, Nintendo 64 utilisait déjà la mémoire unifiée, alors que les autres consoles de l'époque faisaient avec une mémoire vidéo dédiée.
* Pour la 6ème génération, la Gamecube et la Xbox utilisaient la mémoire unifiée, pas la Playstation 2. A partir de la génération suivante, la mémoire unifiée est devenue la solution dominante.
* Pour la 7ème génération, seule la Playstation 3 n'utilisait pas la mémoire unifiée, mais XBOX et la Wii le faisait.
* A partir de la 8ème génération, toutes les consoles utilisent la mémoire unifiée.
Il faut noter que la mémoire utilisée sur ces consoles est une mémoire GDDR, soit le type de mémoire utilisé pour les mémoires vidéo dédiées ! Ce ne sont pas des mémoires DDR normales, optimisées pour fonctionner avec des CPU. Faire ainsi pose plus de problèmes pour le CPU que le GPU, mais ce n'est pas un problème sur une console. Les jeux vidéos sont plus gourmands pour le GFPU que pour le CPU, ce qui fait qu'il vaut mieux privilégier le GPU niveau performance. Ainsi, il vaut mieux utiliser de la mémoire GDDR, qui a une meilleur bande passante et des latences pas terribles. Le GPU sera donc avec une mémoire adaptée, quitte à détériorer les performances du CPU qui préfère les faibles latences.
Il faut noter que les GPU des consoles doivent s'adapter à cette mémoire unfiiée, histoire de conserver de bonnes performances. Les limitations de bande passante se manifestent les GPU des consoles sont adaptés pour limiter la casse. Aussi, les GPU des consoles ne sont pas exactement les mêmes que ceux des PC, et qu'il existe des toutes petites différences. Par exemple, le GPU de la XBOX est une Geforce 3 légèrement modifiée, en partie pour s'adapter à la mémoire unifiée.
Une première adaptation possible est simplement d'ajouter des mémoires caches, ou d'agrandir les mémoires caches existantes. Par exemple, il est possible de doubler le cache de textures ou le cache de sommets. Les GPU des consoles ne s'en sont pas privé, leurs caches sont généralement plus importants que les GPU dédiés équivalents.
Une seconde adaptation a été utilisée sur la Xbox 360, la Xbox One, la Gamecube, la Wii, la WiiU. L'idée était d'utiliser une mémoire dédiée pour le ''framebuffer'' et le tampon de profondeur (ainsi que le tampon de stencil, que nous n'avons pas encore abordé). Mettre à jour le ''framebuffer'' pendant le rendu est responsable d'une grande quantité d'accès mémoire, et c'est encore pire pour le tampon de profondeur. Si on met les deux dans une mémoire dédiée, on économise beaucoup de bande passante.
: Vous aurez peut-être fait le rapprochement avec les GPU à rendu en ''tile'', qui suivent une logique similaire, sauf qu'ils rendent l'image finale morceau par morceau. Ici, pas de système de ''tile''. Les GPU de ce type ont bien une SRAM, mais elle est plus petite et mémorise juste une ''tile'' de petite taille, qui correspond à un morceau de l'image finale, idem pour le ''frambuffer''.
==La mémoire virtuelle des GPUs==
Pour commencer, parlons d'un point important, à savoir l'espace d'adressage du GPU. L''''espace d'adressage''' d'un processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées.
L'espace d'adressage du CPU est quelque peu particulier. Depuis les années 80-90, les logiciels n'adressent pas la mémoire RAM directement. Tous les processeurs gèrent un système de mémoire virtuelle, qui donne l'illusion aux programmes d'avoir accès à toute la mémoire adressable, tout l'espace d'adressage. Par exemple, sur les systèmes 32 bits, chaque programme a accès à tout l'espace d'adressage de 4 gigaoctets, et il ne voit pas les autres programmes dedans. C'est une illusion qui a de nombreux avantages : les programmes sont isolés les uns des autres, un programme ne peut pas lire dans la mémoire d'un autre, les programmes n'ont pas à se soucier de la quantité de RAM installée dans l'ordinateur, etc.
Par contre, cela implique que les adresses manipulées par les programmes sont des adresses fictives, qui doivent être traduites en adresses physiques. Les données situées à une adresse dans l'espace d'adressage ne sont pas à la même adresse en RAM. On fait ainsi la distinction entre adresse physique et logique : les adresses logiques sont les fausses adresses, les adresses physiques sont les vraies adresses en RAM.
Rien de tout cela ne devrait vous surprendre si vous avez déjà lu un cours d'architecture des ordinateurs. Maintenant, passons à quelque chose auquel vous n'avez peut-être pas pensé : qu'en est-il du GPU ? La réponse est que non seulement cela dépend de si le GPU est dédié ou intégré, mais que cela dépend aussi de si le GPU est ancien ou non. Les anciens GPU ne géraient pas la mémoire virtuelle, les nouveaux ont leur propre système de mémoire virtuelle séparé du CPU !
===L'abstraction mémoire des GPU===
Cependant, cela pose un léger problème : la communication avec les programmes et les API graphiques est perturbée. Le pilote de périphérique reçoit des adresses virtuelles de la part des applications, mais il doit gérer la mémoire vidéo en utilisant des adresses physiques. Et cela posait de nombreux problèmes pour les pilotes de GPU.
Le cas le plus facile à expliquer est celui des GPU dédiés. Le pilote de GPU alimente la mémoire vidéo avec des transferts DMA et le contrôleur DMA doit être configuré avec des adresses physiques pour faire son travail. Or, les API 3D leur donnaient des adresses virtuelles, pour localiser les textures, ''mesh'', shaders compilés et autres. Et c'est à eux et au système d'exploitation de traduire ces adresses en adresses physiques. Des cas similaires apparaissent sur des GPU intégrés.
Sous Windows, du temps de l'ancien ''Windows Display Driver Model'' (WDDM), c'était le système d’exploitation qui gérait cela. Le WDDM déportait une partie de la gestion du GPU dans le noyau de l'OS, dont la gestion de la mémoire vidéo, vu que seul lui pouvait faire la traduction d'adresse (il a accès au tables des pages). Le pilote de GPU envoyait les commandes matérielles au noyau de l'OS, qui les patchait, en remplaçant les adresses virtuelles par des adresses physiques. Le pilote envoyait alors les commandes traduites au GPU.
Avec le WDDM 2.0, les GPU supportent maintenant la mémoire virtuelle. Cependant, il faut noter que les GPU utilisent une mémoire virtuelle séparée de celle du CPU. Le processeur et le GPU ont deux espaces d'adressage différents. Concrètement, une adresse virtuelle n'adresse pas la même adresse physique selon qu'elle est utilisée par le GPU. De même, la même adresse physique correspondra à des adresses virtuelles différentes entre CPU et GPU. Aussi, on parle de '''mémoire virtuelle GPU''' pour la distinguer de la mémoire virtuelle du processeur.
[[File:Desktop computer bus bandwidths.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle du CPU et du GPU.]]
Même si la mémoire virtuelle du GPU n'est pas celle du CPU, cela simplifie grandement la gestion de la mémoire vidéo. Le pilote de GPU peut travailler directement avec des adresses virtuelles du GPU, et gérer la mémoire vidéo de lui-même, dans avoir à déléguer une partie du travail au noyau de l'OS. Plus besoin de traduire les adresses en adresses physiques, c'est le GPU qui s'en charge de lui-même ! D'ailleurs, cet avantage fait que la mémoire virtuelle GPU est aussi utilisée avec des GPU intégré, qui n'ont pas besoin de faire de copies entre RAM système et RAM vidéo.
[[File:Integrated graphics with distinct memory allocation.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle CPU et GPU, avec un GPU intégré.]]
Pour gérer la mémoire virtuelle, les GPU intègrent un circuit appelé la '''''Graphics address remapping table''''', abrévié en GART. La GART est techniquement une une ''Memory Management Unit'' (MMU), à savoir un circuit spécialisé qui s'occupe de traduire les adresses virtuelles en adresses physiques, elle prend en charge la mémoire virtuelle. La dite MMU étant intégrée dans un périphérique d'entrée-sortie (IO), ici la carte graphique, elle est appelée une IO-MMU (''Input Output-MMU''). Toutes les cartes graphiques utilisant les bus AGP ou PCI-Express intégrent une GART/IO-MMU.
La GART est configurée par le pilote de GPU, afin de gérer la mémoire virtuelle au mieux. Et cela explique que la mémoire virtuelle du GPU et du CPU soient séparées. Le pilote de GPU coopére avec le système d'exploitation pour configurer la GART, mais cette coopération ne peut pas être parfaite. On ne peut pas permettre au pilote de GPU d'avoir accès à la table des pages ou d'autres structures impliquées dans la traduction d'adresse : le risque de sécurité est trop grand. Avoir deux mémoires virtuelles séparées aide grandement le travail du pilote de GPU.
Cependant, quelques technologies permette au CPU et au GPU d'utiliser le même espace d'adressage, de fusionner la mémoire virtuelle du CPU et du GPU. Par exemple, la technologie ''Heterogeneous System Architecture'' permet cela, entre autres fonctionnalités. Elles permettent de synchroniser la MMU du processeur et l'IO-MMU du GPU.
{|
|[[File:HSA-enabled virtual memory with distinct graphics card.svg|vignette|upright=2|HSA-enabled virtual memory with distinct graphics card]]
|[[File:HSA-enabled integrated graphics.svg|vignette|upright=2|HSA-enabled integrated graphics]]
|}
===La mémoire virtuelle des GPU dédiés===
Pour rappel, la mémoire virtuelle permet à un CPU d'utiliser plus de RAM qu'il n'y en a d'installée dans l'ordinateur. Par exemple, elle permet au CPU de gérer 4 gigas de RAM sur un ordinateur qui n'en contient que trois, le gigaoctet de trop étant en réalité simulé par un fichier sur le disque dur. La technique est utilisée par tous les processeurs modernes.
La mémoire virtuelle des GPUs dédiés fait la même chose, sauf que le surplus d'adresses n'est pas stockés sur le disque dur dans un fichier pagefile, mais est dans la RAM système. Pour le dire autrement, ces cartes dédiées peuvent utiliser la mémoire système si jamais la mémoire vidéo est pleine. Cela permet au GPU d'adresser plus de RAM qu'en a la mémoire vidéo. Par exemple, si la carte vidéo a 2 giga-octets de RAM, la carte graphique peut être capable d'en adresser 8 : 2 gigas en RAM vidéo, et 6 autres gigas en RAM système. Le GPU peut lire directement des données en RAM, sans forcément les copier en mémoire vidéo.
[[File:Mémoire virtuelle des cartes graphiques dédiées.png|centre|vignette|upright=2|Mémoire virtuelle des cartes graphiques dédiées]]
La technologie s'est démocratisée avec le bus AGP, dont la fonctionnalité dite d'''AGP texturing'' permettait de lire ou écrire directement dans la mémoire RAM, sans passer par le processeur. D'ailleurs, la carte graphique Intel i740 n'avait pas de mémoire vidéo et se débrouillait uniquement avec la mémoire système. C'est l'AGP qui a introduit le GART, la fameuse IO-MMU mentionnée plus haut.
L'arrivée du bus PCI-Express ne changea pas la donne, si ce n'est que le bus était plus rapide, ce qui améliorait les performances. Au début, seules les cartes graphiques PCI-Express d'entrée de gamme pouvaient accéder à certaines portions de la mémoire RAM grâce à des technologies adaptées, comme le TurboCache de NVIDIA ou l'HyperMemory d'AMD. Mais la technologie s'est aujourd'hui étendue. De nos jours, toutes les cartes vidéos modernes utilisent la RAM système en plus de la mémoire vidéo, mais seulement en dernier recours, soit quand la mémoire vidéo est quasiment pleine, soit pour faciliter les échanges de données avec le processeur. C'est typiquement le pilote de la carte graphique qui décide ce qui va dans la mémoire vidéo et la mémoire système, et il fait au mieux de manière à avoir les performances optimales.
===Les GPU utilisent la pagination===
Le GPU utilise la technique dite de la pagination, à savoir que la RAM système et la RAM du GPU sont découpées en pages de taille fixe, généralement 4 kilo-octets. Un GPU dédié échange des pages entre RAM système et mémoire vidéo. Lors d'un transfert DMA, la page en RAM système est copiée en mémoire vidéo. S'il n'y a pas assez de place en mémoire vidéo, le GPU rapatrie une page de mémoire vidéo vers la RAM système. La page rapatriée en RAM système est choisie par un algorithme spécialisé. Un GPU intégré n'a pas besoin de copie, il lit directement la page voulue en RAM système.
La traduction des adresses virtuelles en adresses physique se fait au niveau de la page. Une adresse est coupée en deux parts : un numéro de page, et la position de la donnée dans la page. La position dans la page ne change pas lors de la traduction d'adresse, mais le numéro de page est lui traduit. Le numéro de page virtuel est remplacé par un numéro de page physique lors de la traduction.
Pour remplacer le numéro de page virtuel en numéro physique, il faut utiliser une table de translation, appelée la '''table des pages''', qui associe un numéro de page logique à un numéro de page physique. Le système d'exploitation dispose de sa table des pages, qui n'est pas accesible au GPU. Par contre, le GPU dispose d'une sorte de mini-table des pages, qui contient les associations page virtuelle-physique utiles pour traiter les commandes GPU, et rien d'autre. En clair, une sorte de sous-ensemble de la table des pages de l'OS, mais spécifique au GPU. La mini-table des pages est gérée par le pilote de périphérique, qui remplit la mini-table des pages. La mini-table des pages est mémorisée dans une mémoire intégrée au GPU, et précisément dans la MMU.
===Le contrôleur DMA et l'IO-MMU des GPU dédiés===
Sur les GPU dédiés, le contrôleur DMA est souvent fusionné avec l'IO-MMU. En effet, il s'occupe de la copie des pages entre mémoire vidéo et RAM système. Le contrôleur DMA reçoit des adresses provenant du pilote de périphérique, qui sont des adresses virtuelles. Mais vu qu'il accède à la RAM système, il doit faire la traduction entre adresses virtuelles qu'il reçoit et adresses physiques qu'il émet, ce qui implique qu'il sert d'IO-MMU.
Même si la mémoire virtuelle GPU a été intégrée dans Windows assez tard, du temps de l'AGP et du PCI-Express, la technologie existait vraisemblablement sur certaines cartes graphiques au format PCI, même la documentation est assez rare. Seule certitude : la carte graphique NV1 de NVIDIA, leur toute première carte graphique, disposait d'un contrôleur DMA avec une IO-MMU intégrée. Le fonctionnement de cette IOMMU est décrite dans le brevet "US5758182A : DMA controller translates virtual I/O device address received directly from application program command to physical i/o device address of I/O device on device bus", des inventeurs David S. H. Rosenthal et Curtis Priem.
[[File:Microarchitecture du GPU NV1 de NVIDIA.png|centre|vignette|upright=2|Microarchitecture du GPU NV1 de NVIDIA]]
{{NavChapitre | book=Les cartes graphiques
| prev=Les caches d'un processeur de shader
| prevText=Les caches d'un processeur de shader
| next=Le rendu d'une scène 3D : l'API graphique
| netxText=Le rendu d'une scène 3D : l'API graphique
}}{{autocat}}
rc0ig20yzrj005z5qtu49nxyl62zjsf
762751
762750
2026-04-02T00:45:35Z
Mewtow
31375
/* Les GPU des consoles */
762751
wikitext
text/x-wiki
Pour rappel, il existe deux types de cartes graphiques : les cartes dédiées et les cartes intégrées. Les '''cartes graphiques dédiées''' sont des cartes graphiques branchées sur des connecteurs/ports de la carte mère. A l'opposé, tous les processeurs modernes intègrent une carte graphique, appelée '''carte graphique intégrée''', ou encore '''IGP''' (''Integrated Graphic Processor''). En somme, les cartes dédiées sont opposées à celles intégrées dans les processeurs modernes.
Les cartes graphiques dédiées ont de la mémoire vidéo intégrée à la carte graphique, sauf pour quelques exceptions dont on parlera plus tard. Par contre, les IGP n'ont pas de mémoire vidéo dédiée, vu qu'on ne peut pas intégrer beaucoup de mémoire dans un processeur. Et cela permet de classer les cartes graphiques en deux types :
* Les cartes graphiques à '''mémoire vidéo dédiée''', à savoir que la carte graphique dispose de sa propre mémoire rien qu'à elle, séparée de la mémoire RAM de l'ordinateur. On fait alors la distinction entre ''RAM système'' et ''RAM vidéo''.
* Les cartes graphiques à '''mémoire unifiée''', où la mémoire RAM est partagée entre le processeur et la carte graphique. Le terme "unifiée" sous-entend que l'on a unifié la mémoire vidéo et la mémoire système (la RAM).
[[File:Répartition de la mémoire entre RAM système et carte graphique.png|centre|vignette|upright=2.5|Répartition de la mémoire entre RAM système et carte graphique]]
La distinction "mémoire dédiée versus unifiée" correspond de très près à la distinction "GPU dédié versus IGP". Dans la grosse majorité des cas, les cartes vidéos dédiées ont une mémoire dédiée, alors que les IGP utilisent la mémoire unifiée. Mais il existe de rares exceptions où une carte vidéo dédiée utilise la mémoire unifiée. Par exemple, la toute première carte graphique AGP, l'Intel 740, ne possédait pas de mémoire vidéo proprement dite, juste un simple ''framebuffer''. Tout le reste, texture comme géométrie, était placé en mémoire système ! Les performances étaient ridicules, mais les cartes étaient peu chères du fait de l’absence de VRAM, ce qui explique que l'Intel 740 a eu un petit succès sur les ordinateurs d'entrée de gamme.
Une autre exception est celle des GPU soudés sur la carte mère, utilisées sur certaines consoles de jeu, ainsi que certains PC portables puissants destinés aux ''gamers''. Pour ces dernières, il est possible d'utiliser aussi bien de la mémoire dédiée que de la mémoire unifiée. Si la plupart des consoles récents utilisent de la VRAM dédiées, d'anciennes consoles de jeu avec un GPU soudé utilisaient une mémoire unifiée, comme la Nintendo 64, pour ne citer qu'elle.
{|class="wikitable"
|-
!
! Mémoire unifiée
! Mémoire dédiée
|-
! GPU dédié
| Quelques rares GPU d'entrée de gamme || Tous les GPU, sauf de rares exceptions
|-
! GPU intégré
| Systématique ||
|-
! GPU soudé
| Anciennes consoles de jeu || Ordinateurs portables modernes
|}
==La mémoire vidéo dédiée==
La mémoire dédiée est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de ''Framebuffer'' : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les sommets de l'image à calculer, ainsi que divers résultats temporaires.
: Dans ce qui suit, la mémoire vidéo des cartes graphiques dédiées sera appelée la VRAM.
===Les mémoires GDDR et autres VRAM===
La VRAM ressemble aux barrettes de RAM qu'on trouve dans nos PC, à quelques différences près. Le point le plus important est qu'elle n'est pas présente sous la forme de barrettes de mémoire. À la place, les puces de mémoire sont soudées sur la carte graphique, sur son PCB vert. La conséquence est que l'on ne peut pas upgrader la VRAM d'une carte vidéo. Le fait que la VRAM est soudée simplifie la conception de la carte graphique, mais a aussi des avantages au niveau électrique et donc en termes de performance.
Les cartes graphiques des années 90-2000, utilisaient la même mémoire que celle des barrettes de RAM, à savoir des DRAM de type FPM, EDO, ou SDRAM (''Synchronous DRAM''). De nos jours, les barrettes de RAM utilisent de la mémoire dite DDR (''Double Data Rate''), alors que les VRAM sont des RAM dites GDDR (''Graphic Double Data Rate''). Les deux se ressemblent beaucoup, mais il y a de petites différences techniques qui sont trop complexes pour être expliquées ici.
: Quelques cartes graphiques ont utilisé de la mémoire non-DDR, comme les GPU ''Laguna'' de ''Cirrus Logic'', qui utilisaient de la RDRAM de feu Rambus, une mémoire RAM qui a utilisée comme RAM système sur certains PC et sur la Nintendo 64. Citons aussi les cartes graphiques ''Matrox Millennium'' et ''ATI 3D Rage Pro'', qui utilisaient de la ''Window DRAM'' (WRAM). Idem avec
Niveau performance, la GDDR se distingue de la DDR simple par une bande passante élevée, proche de la centaine de gigaoctets par secondes sur les GPU modernes. Mais il y a une contrepartie : un temps d'accès très long, de plusieurs centaines de cycles d'horloge. Concrètement, si je veux lire une texture, entre le moment où j'envoie une demande de lecture à la mémoire vidéo, et le moment celle-ci me renvoie les premiers texels, il va se passer entre 200 à 1000 cycles d'horloge GPU. Par contre, une fois les premiers texels reçus, les texels suivants sont disponibles au cycle suivant, et ainsi de suite. En clair, les données lues mettent du temps avant d'arriver, mais elles arrivent par gros paquets.
Les GPU récents sont des monstres de bande passante et ce n'est pas qu'à cause de la GDDR. Une puce mémoire de DDR/GDDR peut lire/écrire 64 bits par cycle d'horloge. Mais les GPU connectent la GDDR de manière à additionner la bande passante de plusieurs puces. Cela implique que chaque puce de RAM a sa propre connexion au GPU, ce qui permet d’accéder à plusieurs puces en parallèle, en même temps. Les GPU actuels sont capables de lire/écrire 192, 256, 384, voire 512 bits par cycle d'horloge. Les techniques de ''dual channel'' permettent de faire la même chose avec la RAM système, mais n’atteignent que 128 bits par cycle - 192/256 bits avec des techniques de ''triple/quad channel''. En clair, le bus mémoire de la GDDR permet de lire/écrire plus de données par cycle d'horloge qu'une RAM système, de 2 à 8 fois plus.
[[File:Puces mémories d'un GPU et d'une barrette de mémoire.png|centre|vignette|upright=2|Puces mémoires d'un GPU et d'une barrette de mémoire.]]
La différence entre débit et temps d'accès est primordiale sur les GPU modernes comme anciens. Toute l'architecture de la carte graphique est conçue de manière à prendre en compte ce temps d'attente. Les techniques employées sont multiples, et ne sont pas inconnues à ceux qui ont déjà lu un cours d'architecture des ordinateurs : mémoire caches, hiérarchie de caches, ''multithreading'' matériel au niveau du processeur, optimisations des accès mémoire comme des ''Load-Store Queues'' larges, des ''coalesing write buffers'', etc. Mais toutes ces techniques sont techniquement incorporées dans les processeurs de ''shaders'' et dans les circuits fixes. Aussi nous ne pouvons pas en parler dans ce chapitre. À une exception près : l'usage de caches et de ''local stores''.
===Les transferts ''Direct Memory Access''===
Pour échanger des données entre la RAM et la mémoire vidéo, les GPU utilisent la technologie ''Direct Memory Access'', aussi appelée DMA. Elle permet à un périphérique de lire/écrire un bloc de mémoire RAM, sans intervention du processeur, par l'intermédiaire du bus PCI Express.
Pour cela, le GPU intègre un circuit dédié à la gestion des transferts DMA, appelé le '''contrôleur DMA''', qui lit des données en RAM système pour les copier en RAM vidéo (ou inversement, mais c'est plus rare). Précisément, le contrôleur DMA copie un bloc de mémoire, de données consécutives en mémoire, par exemple un bloc de 128 mégaoctets, un bloc de 64 kiloctets, ou autre. Le processeur configure le contrôleur DMA en lui indiquant l'adresse de départ du bloc de mémoire, sa taille, et quelques informations annexes. Le contrôleur DMA lit alors les données une par une, et les écrit dans la mémoire vidéo.
===La mémoire vidéo est mappée dans l'espace d'adressage du CPU===
Les GPU doivent souvent échanger des données avec le processeur. Des données doivent être copiées de la mémoire RAM vers la VRAM. De plus, le CPU peut aussi adresser directement la VRAM. Pour cela, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, grâce à la technique des '''entrées-sorties mappées en mémoire'''. Et c'est ce qui est fait pour le GPU : une partie des adresses est détournée vers le GPU. Typiquement un bloc d'adresse de la même taille que la mémoire vidéo est détournée : elles n'adressent plus de la RAM, mais la directement la mémoire vidéo de la carte graphique. En clair, le processeur voit la mémoire vidéo et peut lire ou écrire dedans directement.
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
Intuitivement, on se dit que toute la mémoire vidéo est visible par le CPU, mais le bus PCI, AGP ou PCI Express ont leur mot à dire. Le bus PCI permettait au CPU d'adresser une fenêtre de 256 mégaoctets de VRAM maximum, en raison d’une sombre histoire de configuration des ''Base Address Registers'' (BARs). Les registres BAR étaient utilisés pour gérer les transferts DMA, mais aussi pour l'adressage direct.
Le PCI Express était aussi dans ce cas avant 2008. La gestion de la mémoire vidéo était alors difficile, mais on pouvait adresser plus de 256 mégaoctets, en déplaçant la fenêtre de 256 mégaoctets dans la mémoire vidéo. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''resizable bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
==La mémoire unifiée==
Avec la mémoire unifiée, une partie de la RAM système est détournée pour servir de mémoire vidéo. La quantité d'adresses détournées est généralement réglable avec un réglage dans le BIOS. On peut ainsi choisir d'allouer 64, 128 ou 256 mégaoctets de mémoire système pour la carte vidéo, sur un ordinateur avec 4 gigaoctets de RAM. Les GPU modernes sont plus souples et fournissent deux réglages : une quantité de RAM vidéo minimale et une quantité de RAM maximale que le GPU ne peut pas dépasser. Par exemple, il est possible de régler le GPU de manière à ce qu'il ait 64 mégaoctets rien que pour lui, mais qu'il puisse avoir accès à maximum 1 gigaoctet s'il en a besoin. Cela fait au total 960 mégaoctets (1024-64) qui peut être alloués au choix à la carte graphique ou au reste des programmes en cours d’exécution, selon les besoins.
[[File:Partage de la mémoire unifiée entre CPU et GPU.png|centre|vignette|upright=2|Répartition de la mémoire entre RAM système et carte graphique]]
===Les GPU dédiés avec mémoire unifiée===
Il existe des cartes dédiées qui utilisent pourtant la mémoire unifiée, par exemple l'Intel 740. Pour lire en mémoire RAM, elles doivent passer par l'intermédiaire du bus AGP, PCI ou PCI-Express. Et ce bus est très lent, bien plus que ne le serait une mémoire vidéo normale. Aussi, les performances sont exécrables. J'insiste sur le fait que l'on parle des cartes graphiques dédiées, mais pas des cartes graphiques soudées des consoles de jeu.
D'ailleurs, de telles cartes dédiées incorporent un ''framebuffer'' directement dans la carte graphique. Il n'y a pas le choix, le VDC de la carte graphique doit accéder à une mémoire suffisamment rapide pour alimenter l'écran. Ils ne peuvent pas prendre le risque d'aller lire la RAM, dont le temps de latence est élevé, et qui peut potentiellement être réservée par le processeur pendant l’affichage d'une image à l'écran.
===Les GPU intégrés===
Les GPU intégrés ou soudés passent par le bus AGP ou PCI Express pour lire des données en RAM système. Mais leur accès à la RAM passe par les mêmes voies que le CPU. Les GPU et le processeur sont reliés à la RAM par un bus dédié appelé le '''bus mémoire'''. Il existe même sans GPU intégré : tous les processeurs sont reliés à la RAM par un tel bus. Si le CPU intègre un IGPU, il greffe l'IGPU sur ce bus mémoire existant.
Un défaut de cette approche est que le débit du bus système est partagé entre le GPU et le processeur. En clair, si le bus mémoire peut transférer 20 gigas de données par secondes, il faudra partager ces 20 gigas/seconde entre CPU et GPU. Par exemple, le CPU aura droit à 15 gigas par secondes, le GPU seulement 5 gigas. Divers circuits d'arbitrage s'occupent de répartir équitablement le bus système, selon les besoins, mais ça reste un compromis imparfait.
[[File:Echanges de données entre CPU et GPU avec une mémoire unifiée.png|centre|vignette|upright=2|Connexion du bus mémoire au CPU et à un GPU soudé sur la carte mère.]]
N'allez cependant pas croire que les GPU intégrés n'ont que des désavantages. Ils disposent d'un avantage bien spécifique : la '''''zero-overhead copy''''', terme barbare mais qui cache une réalité très simple. Avec une mémoire dédiée, le processeur doit copier des données de la RAM système dans la RAM vidéo. Les copies en question se font souvent avant de démarrer le rendu 3D, par exemple lors du chargement d'un niveau dans un jeu vidéo. Elles peuvent aussi se faire lors du rendu, bien que ce soit plus rare. Et ces copies ont un cout en performance. Par contre, avec la mémoire unifié, pas besoin de faire de copie d'une mémoire à l'autre. Le processeur envoie juste une commande du GPU, qui indique l'adresse des données en RAM, leur position dans la RAM.
Le processeur et le GPU intègrent des mémoires caches, afin de réduire l'usage du bus mémoire. Et l'intégration des caches avec un GPU intégré est assez intéressante. Le CPU et l'IGPU peuvent partager certains caches. Par exemple, les processeurs Skylake et Sandy Bridge d'Intel, le CPU et GPU avaient leurs propres caches L2 et L1, mais ils partageaient le cache L3. En général, le partage ne touche que le cache de dernier niveau, le cache le plus gros et le plus proche de la mémoire, à savoir le cache L3 ou L4.
Sur les processeurs modernes, le CPU et le GPU ont leur propre cache L3/L4, afin avoir des caches plus spécialisés. Les caches L3/L4 sont plus gros pour le processeur que pour le GPU, ils vont à des fréquences différentes, sont alimentés par des tensions différentes, etc. De plus, le cache du CPU est optimisé pour un temps d'accès faible, alors que celui du GPU est optimisé pour un fort débit mémoire. Utiliser des caches séparés entraine des problèmes de cohérence des caches, qui ont été vus dans le chapitre sur les caches des processeurs de shaders.
[[File:Caches sur un iGPU.png|centre|vignette|upright=2.5|Caches sur un iGPU]]
===Les GPU des consoles===
Les consoles de jeu utilisent souvent la mémoire unifiée, même les consoles récentes. Pour les consoles de salon, les consoles Nintendo ont été les pionnières de la mémoire unifiée, XBOX l'a adopté dès le début, et les Playstation ont été les dernières à l'utiliser.
* Pour les consoles de 5ème génération, Nintendo 64 utilisait déjà la mémoire unifiée, alors que les autres consoles de l'époque faisaient avec une mémoire vidéo dédiée.
* Pour la 6ème génération, la Gamecube et la Xbox utilisaient la mémoire unifiée, pas la Playstation 2. A partir de la génération suivante, la mémoire unifiée est devenue la solution dominante.
* Pour la 7ème génération, seule la Playstation 3 n'utilisait pas la mémoire unifiée, mais XBOX et la Wii le faisait.
* A partir de la 8ème génération, toutes les consoles utilisent la mémoire unifiée.
Il faut noter que la mémoire utilisée sur ces consoles est une mémoire GDDR, soit le type de mémoire utilisé pour les mémoires vidéo dédiées ! Ce ne sont pas des mémoires DDR normales, optimisées pour fonctionner avec des CPU. Faire ainsi pose plus de problèmes pour le CPU que le GPU, mais ce n'est pas un problème sur une console. Les jeux vidéos sont plus gourmands pour le GFPU que pour le CPU, ce qui fait qu'il vaut mieux privilégier le GPU niveau performance. Ainsi, il vaut mieux utiliser de la mémoire GDDR, qui a une meilleur bande passante et des latences pas terribles. Le GPU sera donc avec une mémoire adaptée, quitte à détériorer les performances du CPU qui préfère les faibles latences.
Il faut noter que les GPU des consoles doivent s'adapter à cette mémoire unfiiée, histoire de conserver de bonnes performances. Les limitations de bande passante se manifestent les GPU des consoles sont adaptés pour limiter la casse. Aussi, les GPU des consoles ne sont pas exactement les mêmes que ceux des PC, et qu'il existe des toutes petites différences. Par exemple, le GPU de la XBOX est une Geforce 3 légèrement modifiée, en partie pour s'adapter à la mémoire unifiée.
Une première adaptation possible est simplement d'ajouter des mémoires caches, ou d'agrandir les mémoires caches existantes. Par exemple, il est possible de doubler le cache de textures ou le cache de sommets. Les GPU des consoles ne s'en sont pas privé, leurs caches sont généralement plus importants que les GPU dédiés équivalents.
Une seconde adaptation a été utilisée sur la Xbox 360, la Xbox One, la Gamecube, la Wii, la WiiU. L'idée était d'utiliser une mémoire dédiée pour le ''framebuffer'' et le tampon de profondeur (ainsi que le tampon de stencil, que nous n'avons pas encore abordé). Mettre à jour le ''framebuffer'' pendant le rendu est responsable d'une grande quantité d'accès mémoire, et c'est encore pire pour le tampon de profondeur. Si on met les deux dans une mémoire dédiée, on économise beaucoup de bande passante. La Xbox 360 utilisait une mémoire EDRAM de 10 Mégaoctets, la Xbox One utilisait 32 mégaocttes de mémoire ESRAM. La Gamecube et la Wii utilisaient 3 mégaoctes de mémoire EDRAM, la WiiU utilisait 32 mégaoctets d'EDRAM.
: Vous aurez peut-être fait le rapprochement avec les GPU à rendu en ''tile'', qui suivent une logique similaire, sauf qu'ils rendent l'image finale morceau par morceau. Ici, pas de système de ''tile''. Les GPU de ce type ont bien une SRAM, mais elle est plus petite et mémorise juste une ''tile'' de petite taille, qui correspond à un morceau de l'image finale, idem pour le ''frambuffer''.
==La mémoire virtuelle des GPUs==
Pour commencer, parlons d'un point important, à savoir l'espace d'adressage du GPU. L''''espace d'adressage''' d'un processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées.
L'espace d'adressage du CPU est quelque peu particulier. Depuis les années 80-90, les logiciels n'adressent pas la mémoire RAM directement. Tous les processeurs gèrent un système de mémoire virtuelle, qui donne l'illusion aux programmes d'avoir accès à toute la mémoire adressable, tout l'espace d'adressage. Par exemple, sur les systèmes 32 bits, chaque programme a accès à tout l'espace d'adressage de 4 gigaoctets, et il ne voit pas les autres programmes dedans. C'est une illusion qui a de nombreux avantages : les programmes sont isolés les uns des autres, un programme ne peut pas lire dans la mémoire d'un autre, les programmes n'ont pas à se soucier de la quantité de RAM installée dans l'ordinateur, etc.
Par contre, cela implique que les adresses manipulées par les programmes sont des adresses fictives, qui doivent être traduites en adresses physiques. Les données situées à une adresse dans l'espace d'adressage ne sont pas à la même adresse en RAM. On fait ainsi la distinction entre adresse physique et logique : les adresses logiques sont les fausses adresses, les adresses physiques sont les vraies adresses en RAM.
Rien de tout cela ne devrait vous surprendre si vous avez déjà lu un cours d'architecture des ordinateurs. Maintenant, passons à quelque chose auquel vous n'avez peut-être pas pensé : qu'en est-il du GPU ? La réponse est que non seulement cela dépend de si le GPU est dédié ou intégré, mais que cela dépend aussi de si le GPU est ancien ou non. Les anciens GPU ne géraient pas la mémoire virtuelle, les nouveaux ont leur propre système de mémoire virtuelle séparé du CPU !
===L'abstraction mémoire des GPU===
Cependant, cela pose un léger problème : la communication avec les programmes et les API graphiques est perturbée. Le pilote de périphérique reçoit des adresses virtuelles de la part des applications, mais il doit gérer la mémoire vidéo en utilisant des adresses physiques. Et cela posait de nombreux problèmes pour les pilotes de GPU.
Le cas le plus facile à expliquer est celui des GPU dédiés. Le pilote de GPU alimente la mémoire vidéo avec des transferts DMA et le contrôleur DMA doit être configuré avec des adresses physiques pour faire son travail. Or, les API 3D leur donnaient des adresses virtuelles, pour localiser les textures, ''mesh'', shaders compilés et autres. Et c'est à eux et au système d'exploitation de traduire ces adresses en adresses physiques. Des cas similaires apparaissent sur des GPU intégrés.
Sous Windows, du temps de l'ancien ''Windows Display Driver Model'' (WDDM), c'était le système d’exploitation qui gérait cela. Le WDDM déportait une partie de la gestion du GPU dans le noyau de l'OS, dont la gestion de la mémoire vidéo, vu que seul lui pouvait faire la traduction d'adresse (il a accès au tables des pages). Le pilote de GPU envoyait les commandes matérielles au noyau de l'OS, qui les patchait, en remplaçant les adresses virtuelles par des adresses physiques. Le pilote envoyait alors les commandes traduites au GPU.
Avec le WDDM 2.0, les GPU supportent maintenant la mémoire virtuelle. Cependant, il faut noter que les GPU utilisent une mémoire virtuelle séparée de celle du CPU. Le processeur et le GPU ont deux espaces d'adressage différents. Concrètement, une adresse virtuelle n'adresse pas la même adresse physique selon qu'elle est utilisée par le GPU. De même, la même adresse physique correspondra à des adresses virtuelles différentes entre CPU et GPU. Aussi, on parle de '''mémoire virtuelle GPU''' pour la distinguer de la mémoire virtuelle du processeur.
[[File:Desktop computer bus bandwidths.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle du CPU et du GPU.]]
Même si la mémoire virtuelle du GPU n'est pas celle du CPU, cela simplifie grandement la gestion de la mémoire vidéo. Le pilote de GPU peut travailler directement avec des adresses virtuelles du GPU, et gérer la mémoire vidéo de lui-même, dans avoir à déléguer une partie du travail au noyau de l'OS. Plus besoin de traduire les adresses en adresses physiques, c'est le GPU qui s'en charge de lui-même ! D'ailleurs, cet avantage fait que la mémoire virtuelle GPU est aussi utilisée avec des GPU intégré, qui n'ont pas besoin de faire de copies entre RAM système et RAM vidéo.
[[File:Integrated graphics with distinct memory allocation.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle CPU et GPU, avec un GPU intégré.]]
Pour gérer la mémoire virtuelle, les GPU intègrent un circuit appelé la '''''Graphics address remapping table''''', abrévié en GART. La GART est techniquement une une ''Memory Management Unit'' (MMU), à savoir un circuit spécialisé qui s'occupe de traduire les adresses virtuelles en adresses physiques, elle prend en charge la mémoire virtuelle. La dite MMU étant intégrée dans un périphérique d'entrée-sortie (IO), ici la carte graphique, elle est appelée une IO-MMU (''Input Output-MMU''). Toutes les cartes graphiques utilisant les bus AGP ou PCI-Express intégrent une GART/IO-MMU.
La GART est configurée par le pilote de GPU, afin de gérer la mémoire virtuelle au mieux. Et cela explique que la mémoire virtuelle du GPU et du CPU soient séparées. Le pilote de GPU coopére avec le système d'exploitation pour configurer la GART, mais cette coopération ne peut pas être parfaite. On ne peut pas permettre au pilote de GPU d'avoir accès à la table des pages ou d'autres structures impliquées dans la traduction d'adresse : le risque de sécurité est trop grand. Avoir deux mémoires virtuelles séparées aide grandement le travail du pilote de GPU.
Cependant, quelques technologies permette au CPU et au GPU d'utiliser le même espace d'adressage, de fusionner la mémoire virtuelle du CPU et du GPU. Par exemple, la technologie ''Heterogeneous System Architecture'' permet cela, entre autres fonctionnalités. Elles permettent de synchroniser la MMU du processeur et l'IO-MMU du GPU.
{|
|[[File:HSA-enabled virtual memory with distinct graphics card.svg|vignette|upright=2|HSA-enabled virtual memory with distinct graphics card]]
|[[File:HSA-enabled integrated graphics.svg|vignette|upright=2|HSA-enabled integrated graphics]]
|}
===La mémoire virtuelle des GPU dédiés===
Pour rappel, la mémoire virtuelle permet à un CPU d'utiliser plus de RAM qu'il n'y en a d'installée dans l'ordinateur. Par exemple, elle permet au CPU de gérer 4 gigas de RAM sur un ordinateur qui n'en contient que trois, le gigaoctet de trop étant en réalité simulé par un fichier sur le disque dur. La technique est utilisée par tous les processeurs modernes.
La mémoire virtuelle des GPUs dédiés fait la même chose, sauf que le surplus d'adresses n'est pas stockés sur le disque dur dans un fichier pagefile, mais est dans la RAM système. Pour le dire autrement, ces cartes dédiées peuvent utiliser la mémoire système si jamais la mémoire vidéo est pleine. Cela permet au GPU d'adresser plus de RAM qu'en a la mémoire vidéo. Par exemple, si la carte vidéo a 2 giga-octets de RAM, la carte graphique peut être capable d'en adresser 8 : 2 gigas en RAM vidéo, et 6 autres gigas en RAM système. Le GPU peut lire directement des données en RAM, sans forcément les copier en mémoire vidéo.
[[File:Mémoire virtuelle des cartes graphiques dédiées.png|centre|vignette|upright=2|Mémoire virtuelle des cartes graphiques dédiées]]
La technologie s'est démocratisée avec le bus AGP, dont la fonctionnalité dite d'''AGP texturing'' permettait de lire ou écrire directement dans la mémoire RAM, sans passer par le processeur. D'ailleurs, la carte graphique Intel i740 n'avait pas de mémoire vidéo et se débrouillait uniquement avec la mémoire système. C'est l'AGP qui a introduit le GART, la fameuse IO-MMU mentionnée plus haut.
L'arrivée du bus PCI-Express ne changea pas la donne, si ce n'est que le bus était plus rapide, ce qui améliorait les performances. Au début, seules les cartes graphiques PCI-Express d'entrée de gamme pouvaient accéder à certaines portions de la mémoire RAM grâce à des technologies adaptées, comme le TurboCache de NVIDIA ou l'HyperMemory d'AMD. Mais la technologie s'est aujourd'hui étendue. De nos jours, toutes les cartes vidéos modernes utilisent la RAM système en plus de la mémoire vidéo, mais seulement en dernier recours, soit quand la mémoire vidéo est quasiment pleine, soit pour faciliter les échanges de données avec le processeur. C'est typiquement le pilote de la carte graphique qui décide ce qui va dans la mémoire vidéo et la mémoire système, et il fait au mieux de manière à avoir les performances optimales.
===Les GPU utilisent la pagination===
Le GPU utilise la technique dite de la pagination, à savoir que la RAM système et la RAM du GPU sont découpées en pages de taille fixe, généralement 4 kilo-octets. Un GPU dédié échange des pages entre RAM système et mémoire vidéo. Lors d'un transfert DMA, la page en RAM système est copiée en mémoire vidéo. S'il n'y a pas assez de place en mémoire vidéo, le GPU rapatrie une page de mémoire vidéo vers la RAM système. La page rapatriée en RAM système est choisie par un algorithme spécialisé. Un GPU intégré n'a pas besoin de copie, il lit directement la page voulue en RAM système.
La traduction des adresses virtuelles en adresses physique se fait au niveau de la page. Une adresse est coupée en deux parts : un numéro de page, et la position de la donnée dans la page. La position dans la page ne change pas lors de la traduction d'adresse, mais le numéro de page est lui traduit. Le numéro de page virtuel est remplacé par un numéro de page physique lors de la traduction.
Pour remplacer le numéro de page virtuel en numéro physique, il faut utiliser une table de translation, appelée la '''table des pages''', qui associe un numéro de page logique à un numéro de page physique. Le système d'exploitation dispose de sa table des pages, qui n'est pas accesible au GPU. Par contre, le GPU dispose d'une sorte de mini-table des pages, qui contient les associations page virtuelle-physique utiles pour traiter les commandes GPU, et rien d'autre. En clair, une sorte de sous-ensemble de la table des pages de l'OS, mais spécifique au GPU. La mini-table des pages est gérée par le pilote de périphérique, qui remplit la mini-table des pages. La mini-table des pages est mémorisée dans une mémoire intégrée au GPU, et précisément dans la MMU.
===Le contrôleur DMA et l'IO-MMU des GPU dédiés===
Sur les GPU dédiés, le contrôleur DMA est souvent fusionné avec l'IO-MMU. En effet, il s'occupe de la copie des pages entre mémoire vidéo et RAM système. Le contrôleur DMA reçoit des adresses provenant du pilote de périphérique, qui sont des adresses virtuelles. Mais vu qu'il accède à la RAM système, il doit faire la traduction entre adresses virtuelles qu'il reçoit et adresses physiques qu'il émet, ce qui implique qu'il sert d'IO-MMU.
Même si la mémoire virtuelle GPU a été intégrée dans Windows assez tard, du temps de l'AGP et du PCI-Express, la technologie existait vraisemblablement sur certaines cartes graphiques au format PCI, même la documentation est assez rare. Seule certitude : la carte graphique NV1 de NVIDIA, leur toute première carte graphique, disposait d'un contrôleur DMA avec une IO-MMU intégrée. Le fonctionnement de cette IOMMU est décrite dans le brevet "US5758182A : DMA controller translates virtual I/O device address received directly from application program command to physical i/o device address of I/O device on device bus", des inventeurs David S. H. Rosenthal et Curtis Priem.
[[File:Microarchitecture du GPU NV1 de NVIDIA.png|centre|vignette|upright=2|Microarchitecture du GPU NV1 de NVIDIA]]
{{NavChapitre | book=Les cartes graphiques
| prev=Les caches d'un processeur de shader
| prevText=Les caches d'un processeur de shader
| next=Le rendu d'une scène 3D : l'API graphique
| netxText=Le rendu d'une scène 3D : l'API graphique
}}{{autocat}}
59nv5yjnkkj7taf2cukkfigs7cqc6f7
762752
762751
2026-04-02T00:50:56Z
Mewtow
31375
/* Les GPU des consoles */
762752
wikitext
text/x-wiki
Pour rappel, il existe deux types de cartes graphiques : les cartes dédiées et les cartes intégrées. Les '''cartes graphiques dédiées''' sont des cartes graphiques branchées sur des connecteurs/ports de la carte mère. A l'opposé, tous les processeurs modernes intègrent une carte graphique, appelée '''carte graphique intégrée''', ou encore '''IGP''' (''Integrated Graphic Processor''). En somme, les cartes dédiées sont opposées à celles intégrées dans les processeurs modernes.
Les cartes graphiques dédiées ont de la mémoire vidéo intégrée à la carte graphique, sauf pour quelques exceptions dont on parlera plus tard. Par contre, les IGP n'ont pas de mémoire vidéo dédiée, vu qu'on ne peut pas intégrer beaucoup de mémoire dans un processeur. Et cela permet de classer les cartes graphiques en deux types :
* Les cartes graphiques à '''mémoire vidéo dédiée''', à savoir que la carte graphique dispose de sa propre mémoire rien qu'à elle, séparée de la mémoire RAM de l'ordinateur. On fait alors la distinction entre ''RAM système'' et ''RAM vidéo''.
* Les cartes graphiques à '''mémoire unifiée''', où la mémoire RAM est partagée entre le processeur et la carte graphique. Le terme "unifiée" sous-entend que l'on a unifié la mémoire vidéo et la mémoire système (la RAM).
[[File:Répartition de la mémoire entre RAM système et carte graphique.png|centre|vignette|upright=2.5|Répartition de la mémoire entre RAM système et carte graphique]]
La distinction "mémoire dédiée versus unifiée" correspond de très près à la distinction "GPU dédié versus IGP". Dans la grosse majorité des cas, les cartes vidéos dédiées ont une mémoire dédiée, alors que les IGP utilisent la mémoire unifiée. Mais il existe de rares exceptions où une carte vidéo dédiée utilise la mémoire unifiée. Par exemple, la toute première carte graphique AGP, l'Intel 740, ne possédait pas de mémoire vidéo proprement dite, juste un simple ''framebuffer''. Tout le reste, texture comme géométrie, était placé en mémoire système ! Les performances étaient ridicules, mais les cartes étaient peu chères du fait de l’absence de VRAM, ce qui explique que l'Intel 740 a eu un petit succès sur les ordinateurs d'entrée de gamme.
Une autre exception est celle des GPU soudés sur la carte mère, utilisées sur certaines consoles de jeu, ainsi que certains PC portables puissants destinés aux ''gamers''. Pour ces dernières, il est possible d'utiliser aussi bien de la mémoire dédiée que de la mémoire unifiée. Si la plupart des consoles récents utilisent de la VRAM dédiées, d'anciennes consoles de jeu avec un GPU soudé utilisaient une mémoire unifiée, comme la Nintendo 64, pour ne citer qu'elle.
{|class="wikitable"
|-
!
! Mémoire unifiée
! Mémoire dédiée
|-
! GPU dédié
| Quelques rares GPU d'entrée de gamme || Tous les GPU, sauf de rares exceptions
|-
! GPU intégré
| Systématique ||
|-
! GPU soudé
| Anciennes consoles de jeu || Ordinateurs portables modernes
|}
==La mémoire vidéo dédiée==
La mémoire dédiée est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de ''Framebuffer'' : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les sommets de l'image à calculer, ainsi que divers résultats temporaires.
: Dans ce qui suit, la mémoire vidéo des cartes graphiques dédiées sera appelée la VRAM.
===Les mémoires GDDR et autres VRAM===
La VRAM ressemble aux barrettes de RAM qu'on trouve dans nos PC, à quelques différences près. Le point le plus important est qu'elle n'est pas présente sous la forme de barrettes de mémoire. À la place, les puces de mémoire sont soudées sur la carte graphique, sur son PCB vert. La conséquence est que l'on ne peut pas upgrader la VRAM d'une carte vidéo. Le fait que la VRAM est soudée simplifie la conception de la carte graphique, mais a aussi des avantages au niveau électrique et donc en termes de performance.
Les cartes graphiques des années 90-2000, utilisaient la même mémoire que celle des barrettes de RAM, à savoir des DRAM de type FPM, EDO, ou SDRAM (''Synchronous DRAM''). De nos jours, les barrettes de RAM utilisent de la mémoire dite DDR (''Double Data Rate''), alors que les VRAM sont des RAM dites GDDR (''Graphic Double Data Rate''). Les deux se ressemblent beaucoup, mais il y a de petites différences techniques qui sont trop complexes pour être expliquées ici.
: Quelques cartes graphiques ont utilisé de la mémoire non-DDR, comme les GPU ''Laguna'' de ''Cirrus Logic'', qui utilisaient de la RDRAM de feu Rambus, une mémoire RAM qui a utilisée comme RAM système sur certains PC et sur la Nintendo 64. Citons aussi les cartes graphiques ''Matrox Millennium'' et ''ATI 3D Rage Pro'', qui utilisaient de la ''Window DRAM'' (WRAM). Idem avec
Niveau performance, la GDDR se distingue de la DDR simple par une bande passante élevée, proche de la centaine de gigaoctets par secondes sur les GPU modernes. Mais il y a une contrepartie : un temps d'accès très long, de plusieurs centaines de cycles d'horloge. Concrètement, si je veux lire une texture, entre le moment où j'envoie une demande de lecture à la mémoire vidéo, et le moment celle-ci me renvoie les premiers texels, il va se passer entre 200 à 1000 cycles d'horloge GPU. Par contre, une fois les premiers texels reçus, les texels suivants sont disponibles au cycle suivant, et ainsi de suite. En clair, les données lues mettent du temps avant d'arriver, mais elles arrivent par gros paquets.
Les GPU récents sont des monstres de bande passante et ce n'est pas qu'à cause de la GDDR. Une puce mémoire de DDR/GDDR peut lire/écrire 64 bits par cycle d'horloge. Mais les GPU connectent la GDDR de manière à additionner la bande passante de plusieurs puces. Cela implique que chaque puce de RAM a sa propre connexion au GPU, ce qui permet d’accéder à plusieurs puces en parallèle, en même temps. Les GPU actuels sont capables de lire/écrire 192, 256, 384, voire 512 bits par cycle d'horloge. Les techniques de ''dual channel'' permettent de faire la même chose avec la RAM système, mais n’atteignent que 128 bits par cycle - 192/256 bits avec des techniques de ''triple/quad channel''. En clair, le bus mémoire de la GDDR permet de lire/écrire plus de données par cycle d'horloge qu'une RAM système, de 2 à 8 fois plus.
[[File:Puces mémories d'un GPU et d'une barrette de mémoire.png|centre|vignette|upright=2|Puces mémoires d'un GPU et d'une barrette de mémoire.]]
La différence entre débit et temps d'accès est primordiale sur les GPU modernes comme anciens. Toute l'architecture de la carte graphique est conçue de manière à prendre en compte ce temps d'attente. Les techniques employées sont multiples, et ne sont pas inconnues à ceux qui ont déjà lu un cours d'architecture des ordinateurs : mémoire caches, hiérarchie de caches, ''multithreading'' matériel au niveau du processeur, optimisations des accès mémoire comme des ''Load-Store Queues'' larges, des ''coalesing write buffers'', etc. Mais toutes ces techniques sont techniquement incorporées dans les processeurs de ''shaders'' et dans les circuits fixes. Aussi nous ne pouvons pas en parler dans ce chapitre. À une exception près : l'usage de caches et de ''local stores''.
===Les transferts ''Direct Memory Access''===
Pour échanger des données entre la RAM et la mémoire vidéo, les GPU utilisent la technologie ''Direct Memory Access'', aussi appelée DMA. Elle permet à un périphérique de lire/écrire un bloc de mémoire RAM, sans intervention du processeur, par l'intermédiaire du bus PCI Express.
Pour cela, le GPU intègre un circuit dédié à la gestion des transferts DMA, appelé le '''contrôleur DMA''', qui lit des données en RAM système pour les copier en RAM vidéo (ou inversement, mais c'est plus rare). Précisément, le contrôleur DMA copie un bloc de mémoire, de données consécutives en mémoire, par exemple un bloc de 128 mégaoctets, un bloc de 64 kiloctets, ou autre. Le processeur configure le contrôleur DMA en lui indiquant l'adresse de départ du bloc de mémoire, sa taille, et quelques informations annexes. Le contrôleur DMA lit alors les données une par une, et les écrit dans la mémoire vidéo.
===La mémoire vidéo est mappée dans l'espace d'adressage du CPU===
Les GPU doivent souvent échanger des données avec le processeur. Des données doivent être copiées de la mémoire RAM vers la VRAM. De plus, le CPU peut aussi adresser directement la VRAM. Pour cela, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, grâce à la technique des '''entrées-sorties mappées en mémoire'''. Et c'est ce qui est fait pour le GPU : une partie des adresses est détournée vers le GPU. Typiquement un bloc d'adresse de la même taille que la mémoire vidéo est détournée : elles n'adressent plus de la RAM, mais la directement la mémoire vidéo de la carte graphique. En clair, le processeur voit la mémoire vidéo et peut lire ou écrire dedans directement.
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
Intuitivement, on se dit que toute la mémoire vidéo est visible par le CPU, mais le bus PCI, AGP ou PCI Express ont leur mot à dire. Le bus PCI permettait au CPU d'adresser une fenêtre de 256 mégaoctets de VRAM maximum, en raison d’une sombre histoire de configuration des ''Base Address Registers'' (BARs). Les registres BAR étaient utilisés pour gérer les transferts DMA, mais aussi pour l'adressage direct.
Le PCI Express était aussi dans ce cas avant 2008. La gestion de la mémoire vidéo était alors difficile, mais on pouvait adresser plus de 256 mégaoctets, en déplaçant la fenêtre de 256 mégaoctets dans la mémoire vidéo. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''resizable bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
==La mémoire unifiée==
Avec la mémoire unifiée, une partie de la RAM système est détournée pour servir de mémoire vidéo. La quantité d'adresses détournées est généralement réglable avec un réglage dans le BIOS. On peut ainsi choisir d'allouer 64, 128 ou 256 mégaoctets de mémoire système pour la carte vidéo, sur un ordinateur avec 4 gigaoctets de RAM. Les GPU modernes sont plus souples et fournissent deux réglages : une quantité de RAM vidéo minimale et une quantité de RAM maximale que le GPU ne peut pas dépasser. Par exemple, il est possible de régler le GPU de manière à ce qu'il ait 64 mégaoctets rien que pour lui, mais qu'il puisse avoir accès à maximum 1 gigaoctet s'il en a besoin. Cela fait au total 960 mégaoctets (1024-64) qui peut être alloués au choix à la carte graphique ou au reste des programmes en cours d’exécution, selon les besoins.
[[File:Partage de la mémoire unifiée entre CPU et GPU.png|centre|vignette|upright=2|Répartition de la mémoire entre RAM système et carte graphique]]
===Les GPU dédiés avec mémoire unifiée===
Il existe des cartes dédiées qui utilisent pourtant la mémoire unifiée, par exemple l'Intel 740. Pour lire en mémoire RAM, elles doivent passer par l'intermédiaire du bus AGP, PCI ou PCI-Express. Et ce bus est très lent, bien plus que ne le serait une mémoire vidéo normale. Aussi, les performances sont exécrables. J'insiste sur le fait que l'on parle des cartes graphiques dédiées, mais pas des cartes graphiques soudées des consoles de jeu.
D'ailleurs, de telles cartes dédiées incorporent un ''framebuffer'' directement dans la carte graphique. Il n'y a pas le choix, le VDC de la carte graphique doit accéder à une mémoire suffisamment rapide pour alimenter l'écran. Ils ne peuvent pas prendre le risque d'aller lire la RAM, dont le temps de latence est élevé, et qui peut potentiellement être réservée par le processeur pendant l’affichage d'une image à l'écran.
===Les GPU intégrés===
Les GPU intégrés ou soudés passent par le bus AGP ou PCI Express pour lire des données en RAM système. Mais leur accès à la RAM passe par les mêmes voies que le CPU. Les GPU et le processeur sont reliés à la RAM par un bus dédié appelé le '''bus mémoire'''. Il existe même sans GPU intégré : tous les processeurs sont reliés à la RAM par un tel bus. Si le CPU intègre un IGPU, il greffe l'IGPU sur ce bus mémoire existant.
Un défaut de cette approche est que le débit du bus système est partagé entre le GPU et le processeur. En clair, si le bus mémoire peut transférer 20 gigas de données par secondes, il faudra partager ces 20 gigas/seconde entre CPU et GPU. Par exemple, le CPU aura droit à 15 gigas par secondes, le GPU seulement 5 gigas. Divers circuits d'arbitrage s'occupent de répartir équitablement le bus système, selon les besoins, mais ça reste un compromis imparfait.
[[File:Echanges de données entre CPU et GPU avec une mémoire unifiée.png|centre|vignette|upright=2|Connexion du bus mémoire au CPU et à un GPU soudé sur la carte mère.]]
N'allez cependant pas croire que les GPU intégrés n'ont que des désavantages. Ils disposent d'un avantage bien spécifique : la '''''zero-overhead copy''''', terme barbare mais qui cache une réalité très simple. Avec une mémoire dédiée, le processeur doit copier des données de la RAM système dans la RAM vidéo. Les copies en question se font souvent avant de démarrer le rendu 3D, par exemple lors du chargement d'un niveau dans un jeu vidéo. Elles peuvent aussi se faire lors du rendu, bien que ce soit plus rare. Et ces copies ont un cout en performance. Par contre, avec la mémoire unifié, pas besoin de faire de copie d'une mémoire à l'autre. Le processeur envoie juste une commande du GPU, qui indique l'adresse des données en RAM, leur position dans la RAM.
Le processeur et le GPU intègrent des mémoires caches, afin de réduire l'usage du bus mémoire. Et l'intégration des caches avec un GPU intégré est assez intéressante. Le CPU et l'IGPU peuvent partager certains caches. Par exemple, les processeurs Skylake et Sandy Bridge d'Intel, le CPU et GPU avaient leurs propres caches L2 et L1, mais ils partageaient le cache L3. En général, le partage ne touche que le cache de dernier niveau, le cache le plus gros et le plus proche de la mémoire, à savoir le cache L3 ou L4.
Sur les processeurs modernes, le CPU et le GPU ont leur propre cache L3/L4, afin avoir des caches plus spécialisés. Les caches L3/L4 sont plus gros pour le processeur que pour le GPU, ils vont à des fréquences différentes, sont alimentés par des tensions différentes, etc. De plus, le cache du CPU est optimisé pour un temps d'accès faible, alors que celui du GPU est optimisé pour un fort débit mémoire. Utiliser des caches séparés entraine des problèmes de cohérence des caches, qui ont été vus dans le chapitre sur les caches des processeurs de shaders.
[[File:Caches sur un iGPU.png|centre|vignette|upright=2.5|Caches sur un iGPU]]
===Les GPU des consoles===
Les consoles de jeu utilisent souvent la mémoire unifiée, même les consoles récentes. Pour les consoles de salon, les consoles Nintendo ont été les pionnières de la mémoire unifiée, XBOX l'a adopté dès le début, et les Playstation ont été les dernières à l'utiliser.
* Pour les consoles de 5ème génération, Nintendo 64 utilisait déjà la mémoire unifiée, alors que les autres consoles de l'époque faisaient avec une mémoire vidéo dédiée.
* Pour la 6ème génération, la Gamecube et la Xbox utilisaient la mémoire unifiée, pas la Playstation 2. A partir de la génération suivante, la mémoire unifiée est devenue la solution dominante.
* Pour la 7ème génération, seule la Playstation 3 n'utilisait pas la mémoire unifiée, mais XBOX et la Wii le faisait.
* A partir de la 8ème génération, toutes les consoles utilisent la mémoire unifiée.
Il faut noter que la mémoire utilisée sur ces consoles est une mémoire GDDR, soit le type de mémoire utilisé pour les mémoires vidéo dédiées ! Ce ne sont pas des mémoires DDR normales, optimisées pour fonctionner avec des CPU. Faire ainsi pose plus de problèmes pour le CPU que le GPU, mais ce n'est pas un problème sur une console. Les jeux vidéos sont plus gourmands pour le GFPU que pour le CPU, ce qui fait qu'il vaut mieux privilégier le GPU niveau performance. Ainsi, il vaut mieux utiliser de la mémoire GDDR, qui a une meilleur bande passante et des latences pas terribles. Le GPU sera donc avec une mémoire adaptée, quitte à détériorer les performances du CPU qui préfère les faibles latences.
Il faut noter que les GPU des consoles doivent s'adapter à cette mémoire unfiiée, histoire de conserver de bonnes performances. Les limitations de bande passante se manifestent les GPU des consoles sont adaptés pour limiter la casse. Aussi, les GPU des consoles ne sont pas exactement les mêmes que ceux des PC, et qu'il existe des toutes petites différences. Par exemple, le GPU de la XBOX est une Geforce 3 légèrement modifiée, en partie pour s'adapter à la mémoire unifiée.
Une première adaptation possible est simplement d'ajouter des mémoires caches, ou d'agrandir les mémoires caches existantes. Par exemple, il est possible de doubler le cache de textures ou le cache de sommets. Les GPU des consoles ne s'en sont pas privé, leurs caches sont généralement plus importants que les GPU dédiés équivalents.
Une seconde adaptation a été utilisée sur la Xbox 360, la Xbox One, la Gamecube, la Wii, la WiiU. L'idée était d'utiliser une mémoire dédiée pour le ''framebuffer'' et le tampon de profondeur (ainsi que le tampon de stencil, que nous n'avons pas encore abordé). Mettre à jour le ''framebuffer'' pendant le rendu est responsable d'une grande quantité d'accès mémoire, et c'est encore pire pour le tampon de profondeur. Si on met les deux dans une mémoire dédiée, on économise beaucoup de bande passante.
La Xbox 360 utilisait une mémoire EDRAM de 10 Mégaoctets, la Xbox One utilisait 32 mégaoctets de mémoire ESRAM. La Gamecube et la Wii utilisaient 3 mégaoctes de mémoire EDRAM, la WiiU utilisait 32 mégaoctets d'EDRAM. Et mine de rien, ce n'est pas beaucoup. Une image en résolution 1920 par 1080 utilise déjà 8 mégaoctets, ce qui rentre tout juste dans l'EDRAM de la Xbox 360, à condition de ne pas utiliser d'antialiasing. Pour des résolutions usuelles à l'époque, comme le 1280 par 720, ca ne rentre pas si on utilise de l'antialiasing.
: Vous aurez peut-être fait le rapprochement avec les GPU à rendu en ''tile'', qui suivent une logique similaire, sauf qu'ils rendent l'image finale morceau par morceau. Ici, pas de système de ''tile''. Les GPU de ce type ont bien une SRAM, mais elle est plus petite et mémorise juste une ''tile'' de petite taille, qui correspond à un morceau de l'image finale, idem pour le ''frambuffer''.
==La mémoire virtuelle des GPUs==
Pour commencer, parlons d'un point important, à savoir l'espace d'adressage du GPU. L''''espace d'adressage''' d'un processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées.
L'espace d'adressage du CPU est quelque peu particulier. Depuis les années 80-90, les logiciels n'adressent pas la mémoire RAM directement. Tous les processeurs gèrent un système de mémoire virtuelle, qui donne l'illusion aux programmes d'avoir accès à toute la mémoire adressable, tout l'espace d'adressage. Par exemple, sur les systèmes 32 bits, chaque programme a accès à tout l'espace d'adressage de 4 gigaoctets, et il ne voit pas les autres programmes dedans. C'est une illusion qui a de nombreux avantages : les programmes sont isolés les uns des autres, un programme ne peut pas lire dans la mémoire d'un autre, les programmes n'ont pas à se soucier de la quantité de RAM installée dans l'ordinateur, etc.
Par contre, cela implique que les adresses manipulées par les programmes sont des adresses fictives, qui doivent être traduites en adresses physiques. Les données situées à une adresse dans l'espace d'adressage ne sont pas à la même adresse en RAM. On fait ainsi la distinction entre adresse physique et logique : les adresses logiques sont les fausses adresses, les adresses physiques sont les vraies adresses en RAM.
Rien de tout cela ne devrait vous surprendre si vous avez déjà lu un cours d'architecture des ordinateurs. Maintenant, passons à quelque chose auquel vous n'avez peut-être pas pensé : qu'en est-il du GPU ? La réponse est que non seulement cela dépend de si le GPU est dédié ou intégré, mais que cela dépend aussi de si le GPU est ancien ou non. Les anciens GPU ne géraient pas la mémoire virtuelle, les nouveaux ont leur propre système de mémoire virtuelle séparé du CPU !
===L'abstraction mémoire des GPU===
Cependant, cela pose un léger problème : la communication avec les programmes et les API graphiques est perturbée. Le pilote de périphérique reçoit des adresses virtuelles de la part des applications, mais il doit gérer la mémoire vidéo en utilisant des adresses physiques. Et cela posait de nombreux problèmes pour les pilotes de GPU.
Le cas le plus facile à expliquer est celui des GPU dédiés. Le pilote de GPU alimente la mémoire vidéo avec des transferts DMA et le contrôleur DMA doit être configuré avec des adresses physiques pour faire son travail. Or, les API 3D leur donnaient des adresses virtuelles, pour localiser les textures, ''mesh'', shaders compilés et autres. Et c'est à eux et au système d'exploitation de traduire ces adresses en adresses physiques. Des cas similaires apparaissent sur des GPU intégrés.
Sous Windows, du temps de l'ancien ''Windows Display Driver Model'' (WDDM), c'était le système d’exploitation qui gérait cela. Le WDDM déportait une partie de la gestion du GPU dans le noyau de l'OS, dont la gestion de la mémoire vidéo, vu que seul lui pouvait faire la traduction d'adresse (il a accès au tables des pages). Le pilote de GPU envoyait les commandes matérielles au noyau de l'OS, qui les patchait, en remplaçant les adresses virtuelles par des adresses physiques. Le pilote envoyait alors les commandes traduites au GPU.
Avec le WDDM 2.0, les GPU supportent maintenant la mémoire virtuelle. Cependant, il faut noter que les GPU utilisent une mémoire virtuelle séparée de celle du CPU. Le processeur et le GPU ont deux espaces d'adressage différents. Concrètement, une adresse virtuelle n'adresse pas la même adresse physique selon qu'elle est utilisée par le GPU. De même, la même adresse physique correspondra à des adresses virtuelles différentes entre CPU et GPU. Aussi, on parle de '''mémoire virtuelle GPU''' pour la distinguer de la mémoire virtuelle du processeur.
[[File:Desktop computer bus bandwidths.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle du CPU et du GPU.]]
Même si la mémoire virtuelle du GPU n'est pas celle du CPU, cela simplifie grandement la gestion de la mémoire vidéo. Le pilote de GPU peut travailler directement avec des adresses virtuelles du GPU, et gérer la mémoire vidéo de lui-même, dans avoir à déléguer une partie du travail au noyau de l'OS. Plus besoin de traduire les adresses en adresses physiques, c'est le GPU qui s'en charge de lui-même ! D'ailleurs, cet avantage fait que la mémoire virtuelle GPU est aussi utilisée avec des GPU intégré, qui n'ont pas besoin de faire de copies entre RAM système et RAM vidéo.
[[File:Integrated graphics with distinct memory allocation.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle CPU et GPU, avec un GPU intégré.]]
Pour gérer la mémoire virtuelle, les GPU intègrent un circuit appelé la '''''Graphics address remapping table''''', abrévié en GART. La GART est techniquement une une ''Memory Management Unit'' (MMU), à savoir un circuit spécialisé qui s'occupe de traduire les adresses virtuelles en adresses physiques, elle prend en charge la mémoire virtuelle. La dite MMU étant intégrée dans un périphérique d'entrée-sortie (IO), ici la carte graphique, elle est appelée une IO-MMU (''Input Output-MMU''). Toutes les cartes graphiques utilisant les bus AGP ou PCI-Express intégrent une GART/IO-MMU.
La GART est configurée par le pilote de GPU, afin de gérer la mémoire virtuelle au mieux. Et cela explique que la mémoire virtuelle du GPU et du CPU soient séparées. Le pilote de GPU coopére avec le système d'exploitation pour configurer la GART, mais cette coopération ne peut pas être parfaite. On ne peut pas permettre au pilote de GPU d'avoir accès à la table des pages ou d'autres structures impliquées dans la traduction d'adresse : le risque de sécurité est trop grand. Avoir deux mémoires virtuelles séparées aide grandement le travail du pilote de GPU.
Cependant, quelques technologies permette au CPU et au GPU d'utiliser le même espace d'adressage, de fusionner la mémoire virtuelle du CPU et du GPU. Par exemple, la technologie ''Heterogeneous System Architecture'' permet cela, entre autres fonctionnalités. Elles permettent de synchroniser la MMU du processeur et l'IO-MMU du GPU.
{|
|[[File:HSA-enabled virtual memory with distinct graphics card.svg|vignette|upright=2|HSA-enabled virtual memory with distinct graphics card]]
|[[File:HSA-enabled integrated graphics.svg|vignette|upright=2|HSA-enabled integrated graphics]]
|}
===La mémoire virtuelle des GPU dédiés===
Pour rappel, la mémoire virtuelle permet à un CPU d'utiliser plus de RAM qu'il n'y en a d'installée dans l'ordinateur. Par exemple, elle permet au CPU de gérer 4 gigas de RAM sur un ordinateur qui n'en contient que trois, le gigaoctet de trop étant en réalité simulé par un fichier sur le disque dur. La technique est utilisée par tous les processeurs modernes.
La mémoire virtuelle des GPUs dédiés fait la même chose, sauf que le surplus d'adresses n'est pas stockés sur le disque dur dans un fichier pagefile, mais est dans la RAM système. Pour le dire autrement, ces cartes dédiées peuvent utiliser la mémoire système si jamais la mémoire vidéo est pleine. Cela permet au GPU d'adresser plus de RAM qu'en a la mémoire vidéo. Par exemple, si la carte vidéo a 2 giga-octets de RAM, la carte graphique peut être capable d'en adresser 8 : 2 gigas en RAM vidéo, et 6 autres gigas en RAM système. Le GPU peut lire directement des données en RAM, sans forcément les copier en mémoire vidéo.
[[File:Mémoire virtuelle des cartes graphiques dédiées.png|centre|vignette|upright=2|Mémoire virtuelle des cartes graphiques dédiées]]
La technologie s'est démocratisée avec le bus AGP, dont la fonctionnalité dite d'''AGP texturing'' permettait de lire ou écrire directement dans la mémoire RAM, sans passer par le processeur. D'ailleurs, la carte graphique Intel i740 n'avait pas de mémoire vidéo et se débrouillait uniquement avec la mémoire système. C'est l'AGP qui a introduit le GART, la fameuse IO-MMU mentionnée plus haut.
L'arrivée du bus PCI-Express ne changea pas la donne, si ce n'est que le bus était plus rapide, ce qui améliorait les performances. Au début, seules les cartes graphiques PCI-Express d'entrée de gamme pouvaient accéder à certaines portions de la mémoire RAM grâce à des technologies adaptées, comme le TurboCache de NVIDIA ou l'HyperMemory d'AMD. Mais la technologie s'est aujourd'hui étendue. De nos jours, toutes les cartes vidéos modernes utilisent la RAM système en plus de la mémoire vidéo, mais seulement en dernier recours, soit quand la mémoire vidéo est quasiment pleine, soit pour faciliter les échanges de données avec le processeur. C'est typiquement le pilote de la carte graphique qui décide ce qui va dans la mémoire vidéo et la mémoire système, et il fait au mieux de manière à avoir les performances optimales.
===Les GPU utilisent la pagination===
Le GPU utilise la technique dite de la pagination, à savoir que la RAM système et la RAM du GPU sont découpées en pages de taille fixe, généralement 4 kilo-octets. Un GPU dédié échange des pages entre RAM système et mémoire vidéo. Lors d'un transfert DMA, la page en RAM système est copiée en mémoire vidéo. S'il n'y a pas assez de place en mémoire vidéo, le GPU rapatrie une page de mémoire vidéo vers la RAM système. La page rapatriée en RAM système est choisie par un algorithme spécialisé. Un GPU intégré n'a pas besoin de copie, il lit directement la page voulue en RAM système.
La traduction des adresses virtuelles en adresses physique se fait au niveau de la page. Une adresse est coupée en deux parts : un numéro de page, et la position de la donnée dans la page. La position dans la page ne change pas lors de la traduction d'adresse, mais le numéro de page est lui traduit. Le numéro de page virtuel est remplacé par un numéro de page physique lors de la traduction.
Pour remplacer le numéro de page virtuel en numéro physique, il faut utiliser une table de translation, appelée la '''table des pages''', qui associe un numéro de page logique à un numéro de page physique. Le système d'exploitation dispose de sa table des pages, qui n'est pas accesible au GPU. Par contre, le GPU dispose d'une sorte de mini-table des pages, qui contient les associations page virtuelle-physique utiles pour traiter les commandes GPU, et rien d'autre. En clair, une sorte de sous-ensemble de la table des pages de l'OS, mais spécifique au GPU. La mini-table des pages est gérée par le pilote de périphérique, qui remplit la mini-table des pages. La mini-table des pages est mémorisée dans une mémoire intégrée au GPU, et précisément dans la MMU.
===Le contrôleur DMA et l'IO-MMU des GPU dédiés===
Sur les GPU dédiés, le contrôleur DMA est souvent fusionné avec l'IO-MMU. En effet, il s'occupe de la copie des pages entre mémoire vidéo et RAM système. Le contrôleur DMA reçoit des adresses provenant du pilote de périphérique, qui sont des adresses virtuelles. Mais vu qu'il accède à la RAM système, il doit faire la traduction entre adresses virtuelles qu'il reçoit et adresses physiques qu'il émet, ce qui implique qu'il sert d'IO-MMU.
Même si la mémoire virtuelle GPU a été intégrée dans Windows assez tard, du temps de l'AGP et du PCI-Express, la technologie existait vraisemblablement sur certaines cartes graphiques au format PCI, même la documentation est assez rare. Seule certitude : la carte graphique NV1 de NVIDIA, leur toute première carte graphique, disposait d'un contrôleur DMA avec une IO-MMU intégrée. Le fonctionnement de cette IOMMU est décrite dans le brevet "US5758182A : DMA controller translates virtual I/O device address received directly from application program command to physical i/o device address of I/O device on device bus", des inventeurs David S. H. Rosenthal et Curtis Priem.
[[File:Microarchitecture du GPU NV1 de NVIDIA.png|centre|vignette|upright=2|Microarchitecture du GPU NV1 de NVIDIA]]
{{NavChapitre | book=Les cartes graphiques
| prev=Les caches d'un processeur de shader
| prevText=Les caches d'un processeur de shader
| next=Le rendu d'une scène 3D : l'API graphique
| netxText=Le rendu d'une scène 3D : l'API graphique
}}{{autocat}}
pl6rwtl6m021glec1ur2gt9ksr2lndu
762753
762752
2026-04-02T00:54:58Z
Mewtow
31375
/* Les GPU des consoles */
762753
wikitext
text/x-wiki
Pour rappel, il existe deux types de cartes graphiques : les cartes dédiées et les cartes intégrées. Les '''cartes graphiques dédiées''' sont des cartes graphiques branchées sur des connecteurs/ports de la carte mère. A l'opposé, tous les processeurs modernes intègrent une carte graphique, appelée '''carte graphique intégrée''', ou encore '''IGP''' (''Integrated Graphic Processor''). En somme, les cartes dédiées sont opposées à celles intégrées dans les processeurs modernes.
Les cartes graphiques dédiées ont de la mémoire vidéo intégrée à la carte graphique, sauf pour quelques exceptions dont on parlera plus tard. Par contre, les IGP n'ont pas de mémoire vidéo dédiée, vu qu'on ne peut pas intégrer beaucoup de mémoire dans un processeur. Et cela permet de classer les cartes graphiques en deux types :
* Les cartes graphiques à '''mémoire vidéo dédiée''', à savoir que la carte graphique dispose de sa propre mémoire rien qu'à elle, séparée de la mémoire RAM de l'ordinateur. On fait alors la distinction entre ''RAM système'' et ''RAM vidéo''.
* Les cartes graphiques à '''mémoire unifiée''', où la mémoire RAM est partagée entre le processeur et la carte graphique. Le terme "unifiée" sous-entend que l'on a unifié la mémoire vidéo et la mémoire système (la RAM).
[[File:Répartition de la mémoire entre RAM système et carte graphique.png|centre|vignette|upright=2.5|Répartition de la mémoire entre RAM système et carte graphique]]
La distinction "mémoire dédiée versus unifiée" correspond de très près à la distinction "GPU dédié versus IGP". Dans la grosse majorité des cas, les cartes vidéos dédiées ont une mémoire dédiée, alors que les IGP utilisent la mémoire unifiée. Mais il existe de rares exceptions où une carte vidéo dédiée utilise la mémoire unifiée. Par exemple, la toute première carte graphique AGP, l'Intel 740, ne possédait pas de mémoire vidéo proprement dite, juste un simple ''framebuffer''. Tout le reste, texture comme géométrie, était placé en mémoire système ! Les performances étaient ridicules, mais les cartes étaient peu chères du fait de l’absence de VRAM, ce qui explique que l'Intel 740 a eu un petit succès sur les ordinateurs d'entrée de gamme.
Une autre exception est celle des GPU soudés sur la carte mère, utilisées sur certaines consoles de jeu, ainsi que certains PC portables puissants destinés aux ''gamers''. Pour ces dernières, il est possible d'utiliser aussi bien de la mémoire dédiée que de la mémoire unifiée. Si la plupart des consoles récents utilisent de la VRAM dédiées, d'anciennes consoles de jeu avec un GPU soudé utilisaient une mémoire unifiée, comme la Nintendo 64, pour ne citer qu'elle.
{|class="wikitable"
|-
!
! Mémoire unifiée
! Mémoire dédiée
|-
! GPU dédié
| Quelques rares GPU d'entrée de gamme || Tous les GPU, sauf de rares exceptions
|-
! GPU intégré
| Systématique ||
|-
! GPU soudé
| Anciennes consoles de jeu || Ordinateurs portables modernes
|}
==La mémoire vidéo dédiée==
La mémoire dédiée est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de ''Framebuffer'' : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les sommets de l'image à calculer, ainsi que divers résultats temporaires.
: Dans ce qui suit, la mémoire vidéo des cartes graphiques dédiées sera appelée la VRAM.
===Les mémoires GDDR et autres VRAM===
La VRAM ressemble aux barrettes de RAM qu'on trouve dans nos PC, à quelques différences près. Le point le plus important est qu'elle n'est pas présente sous la forme de barrettes de mémoire. À la place, les puces de mémoire sont soudées sur la carte graphique, sur son PCB vert. La conséquence est que l'on ne peut pas upgrader la VRAM d'une carte vidéo. Le fait que la VRAM est soudée simplifie la conception de la carte graphique, mais a aussi des avantages au niveau électrique et donc en termes de performance.
Les cartes graphiques des années 90-2000, utilisaient la même mémoire que celle des barrettes de RAM, à savoir des DRAM de type FPM, EDO, ou SDRAM (''Synchronous DRAM''). De nos jours, les barrettes de RAM utilisent de la mémoire dite DDR (''Double Data Rate''), alors que les VRAM sont des RAM dites GDDR (''Graphic Double Data Rate''). Les deux se ressemblent beaucoup, mais il y a de petites différences techniques qui sont trop complexes pour être expliquées ici.
: Quelques cartes graphiques ont utilisé de la mémoire non-DDR, comme les GPU ''Laguna'' de ''Cirrus Logic'', qui utilisaient de la RDRAM de feu Rambus, une mémoire RAM qui a utilisée comme RAM système sur certains PC et sur la Nintendo 64. Citons aussi les cartes graphiques ''Matrox Millennium'' et ''ATI 3D Rage Pro'', qui utilisaient de la ''Window DRAM'' (WRAM). Idem avec
Niveau performance, la GDDR se distingue de la DDR simple par une bande passante élevée, proche de la centaine de gigaoctets par secondes sur les GPU modernes. Mais il y a une contrepartie : un temps d'accès très long, de plusieurs centaines de cycles d'horloge. Concrètement, si je veux lire une texture, entre le moment où j'envoie une demande de lecture à la mémoire vidéo, et le moment celle-ci me renvoie les premiers texels, il va se passer entre 200 à 1000 cycles d'horloge GPU. Par contre, une fois les premiers texels reçus, les texels suivants sont disponibles au cycle suivant, et ainsi de suite. En clair, les données lues mettent du temps avant d'arriver, mais elles arrivent par gros paquets.
Les GPU récents sont des monstres de bande passante et ce n'est pas qu'à cause de la GDDR. Une puce mémoire de DDR/GDDR peut lire/écrire 64 bits par cycle d'horloge. Mais les GPU connectent la GDDR de manière à additionner la bande passante de plusieurs puces. Cela implique que chaque puce de RAM a sa propre connexion au GPU, ce qui permet d’accéder à plusieurs puces en parallèle, en même temps. Les GPU actuels sont capables de lire/écrire 192, 256, 384, voire 512 bits par cycle d'horloge. Les techniques de ''dual channel'' permettent de faire la même chose avec la RAM système, mais n’atteignent que 128 bits par cycle - 192/256 bits avec des techniques de ''triple/quad channel''. En clair, le bus mémoire de la GDDR permet de lire/écrire plus de données par cycle d'horloge qu'une RAM système, de 2 à 8 fois plus.
[[File:Puces mémories d'un GPU et d'une barrette de mémoire.png|centre|vignette|upright=2|Puces mémoires d'un GPU et d'une barrette de mémoire.]]
La différence entre débit et temps d'accès est primordiale sur les GPU modernes comme anciens. Toute l'architecture de la carte graphique est conçue de manière à prendre en compte ce temps d'attente. Les techniques employées sont multiples, et ne sont pas inconnues à ceux qui ont déjà lu un cours d'architecture des ordinateurs : mémoire caches, hiérarchie de caches, ''multithreading'' matériel au niveau du processeur, optimisations des accès mémoire comme des ''Load-Store Queues'' larges, des ''coalesing write buffers'', etc. Mais toutes ces techniques sont techniquement incorporées dans les processeurs de ''shaders'' et dans les circuits fixes. Aussi nous ne pouvons pas en parler dans ce chapitre. À une exception près : l'usage de caches et de ''local stores''.
===Les transferts ''Direct Memory Access''===
Pour échanger des données entre la RAM et la mémoire vidéo, les GPU utilisent la technologie ''Direct Memory Access'', aussi appelée DMA. Elle permet à un périphérique de lire/écrire un bloc de mémoire RAM, sans intervention du processeur, par l'intermédiaire du bus PCI Express.
Pour cela, le GPU intègre un circuit dédié à la gestion des transferts DMA, appelé le '''contrôleur DMA''', qui lit des données en RAM système pour les copier en RAM vidéo (ou inversement, mais c'est plus rare). Précisément, le contrôleur DMA copie un bloc de mémoire, de données consécutives en mémoire, par exemple un bloc de 128 mégaoctets, un bloc de 64 kiloctets, ou autre. Le processeur configure le contrôleur DMA en lui indiquant l'adresse de départ du bloc de mémoire, sa taille, et quelques informations annexes. Le contrôleur DMA lit alors les données une par une, et les écrit dans la mémoire vidéo.
===La mémoire vidéo est mappée dans l'espace d'adressage du CPU===
Les GPU doivent souvent échanger des données avec le processeur. Des données doivent être copiées de la mémoire RAM vers la VRAM. De plus, le CPU peut aussi adresser directement la VRAM. Pour cela, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, grâce à la technique des '''entrées-sorties mappées en mémoire'''. Et c'est ce qui est fait pour le GPU : une partie des adresses est détournée vers le GPU. Typiquement un bloc d'adresse de la même taille que la mémoire vidéo est détournée : elles n'adressent plus de la RAM, mais la directement la mémoire vidéo de la carte graphique. En clair, le processeur voit la mémoire vidéo et peut lire ou écrire dedans directement.
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
Intuitivement, on se dit que toute la mémoire vidéo est visible par le CPU, mais le bus PCI, AGP ou PCI Express ont leur mot à dire. Le bus PCI permettait au CPU d'adresser une fenêtre de 256 mégaoctets de VRAM maximum, en raison d’une sombre histoire de configuration des ''Base Address Registers'' (BARs). Les registres BAR étaient utilisés pour gérer les transferts DMA, mais aussi pour l'adressage direct.
Le PCI Express était aussi dans ce cas avant 2008. La gestion de la mémoire vidéo était alors difficile, mais on pouvait adresser plus de 256 mégaoctets, en déplaçant la fenêtre de 256 mégaoctets dans la mémoire vidéo. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''resizable bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
==La mémoire unifiée==
Avec la mémoire unifiée, une partie de la RAM système est détournée pour servir de mémoire vidéo. La quantité d'adresses détournées est généralement réglable avec un réglage dans le BIOS. On peut ainsi choisir d'allouer 64, 128 ou 256 mégaoctets de mémoire système pour la carte vidéo, sur un ordinateur avec 4 gigaoctets de RAM. Les GPU modernes sont plus souples et fournissent deux réglages : une quantité de RAM vidéo minimale et une quantité de RAM maximale que le GPU ne peut pas dépasser. Par exemple, il est possible de régler le GPU de manière à ce qu'il ait 64 mégaoctets rien que pour lui, mais qu'il puisse avoir accès à maximum 1 gigaoctet s'il en a besoin. Cela fait au total 960 mégaoctets (1024-64) qui peut être alloués au choix à la carte graphique ou au reste des programmes en cours d’exécution, selon les besoins.
[[File:Partage de la mémoire unifiée entre CPU et GPU.png|centre|vignette|upright=2|Répartition de la mémoire entre RAM système et carte graphique]]
===Les GPU dédiés avec mémoire unifiée===
Il existe des cartes dédiées qui utilisent pourtant la mémoire unifiée, par exemple l'Intel 740. Pour lire en mémoire RAM, elles doivent passer par l'intermédiaire du bus AGP, PCI ou PCI-Express. Et ce bus est très lent, bien plus que ne le serait une mémoire vidéo normale. Aussi, les performances sont exécrables. J'insiste sur le fait que l'on parle des cartes graphiques dédiées, mais pas des cartes graphiques soudées des consoles de jeu.
D'ailleurs, de telles cartes dédiées incorporent un ''framebuffer'' directement dans la carte graphique. Il n'y a pas le choix, le VDC de la carte graphique doit accéder à une mémoire suffisamment rapide pour alimenter l'écran. Ils ne peuvent pas prendre le risque d'aller lire la RAM, dont le temps de latence est élevé, et qui peut potentiellement être réservée par le processeur pendant l’affichage d'une image à l'écran.
===Les GPU intégrés===
Les GPU intégrés ou soudés passent par le bus AGP ou PCI Express pour lire des données en RAM système. Mais leur accès à la RAM passe par les mêmes voies que le CPU. Les GPU et le processeur sont reliés à la RAM par un bus dédié appelé le '''bus mémoire'''. Il existe même sans GPU intégré : tous les processeurs sont reliés à la RAM par un tel bus. Si le CPU intègre un IGPU, il greffe l'IGPU sur ce bus mémoire existant.
Un défaut de cette approche est que le débit du bus système est partagé entre le GPU et le processeur. En clair, si le bus mémoire peut transférer 20 gigas de données par secondes, il faudra partager ces 20 gigas/seconde entre CPU et GPU. Par exemple, le CPU aura droit à 15 gigas par secondes, le GPU seulement 5 gigas. Divers circuits d'arbitrage s'occupent de répartir équitablement le bus système, selon les besoins, mais ça reste un compromis imparfait.
[[File:Echanges de données entre CPU et GPU avec une mémoire unifiée.png|centre|vignette|upright=2|Connexion du bus mémoire au CPU et à un GPU soudé sur la carte mère.]]
N'allez cependant pas croire que les GPU intégrés n'ont que des désavantages. Ils disposent d'un avantage bien spécifique : la '''''zero-overhead copy''''', terme barbare mais qui cache une réalité très simple. Avec une mémoire dédiée, le processeur doit copier des données de la RAM système dans la RAM vidéo. Les copies en question se font souvent avant de démarrer le rendu 3D, par exemple lors du chargement d'un niveau dans un jeu vidéo. Elles peuvent aussi se faire lors du rendu, bien que ce soit plus rare. Et ces copies ont un cout en performance. Par contre, avec la mémoire unifié, pas besoin de faire de copie d'une mémoire à l'autre. Le processeur envoie juste une commande du GPU, qui indique l'adresse des données en RAM, leur position dans la RAM.
Le processeur et le GPU intègrent des mémoires caches, afin de réduire l'usage du bus mémoire. Et l'intégration des caches avec un GPU intégré est assez intéressante. Le CPU et l'IGPU peuvent partager certains caches. Par exemple, les processeurs Skylake et Sandy Bridge d'Intel, le CPU et GPU avaient leurs propres caches L2 et L1, mais ils partageaient le cache L3. En général, le partage ne touche que le cache de dernier niveau, le cache le plus gros et le plus proche de la mémoire, à savoir le cache L3 ou L4.
Sur les processeurs modernes, le CPU et le GPU ont leur propre cache L3/L4, afin avoir des caches plus spécialisés. Les caches L3/L4 sont plus gros pour le processeur que pour le GPU, ils vont à des fréquences différentes, sont alimentés par des tensions différentes, etc. De plus, le cache du CPU est optimisé pour un temps d'accès faible, alors que celui du GPU est optimisé pour un fort débit mémoire. Utiliser des caches séparés entraine des problèmes de cohérence des caches, qui ont été vus dans le chapitre sur les caches des processeurs de shaders.
[[File:Caches sur un iGPU.png|centre|vignette|upright=2.5|Caches sur un iGPU]]
===Les GPU des consoles===
Les consoles de jeu utilisent souvent la mémoire unifiée, même les consoles récentes. Pour les consoles de salon, les consoles Nintendo ont été les pionnières de la mémoire unifiée, XBOX l'a adopté dès le début, et les Playstation ont été les dernières à l'utiliser.
* Pour les consoles de 5ème génération, Nintendo 64 utilisait déjà la mémoire unifiée, alors que les autres consoles de l'époque faisaient avec une mémoire vidéo dédiée.
* Pour la 6ème génération, la Gamecube et la Xbox utilisaient la mémoire unifiée, pas la Playstation 2. A partir de la génération suivante, la mémoire unifiée est devenue la solution dominante.
* Pour la 7ème génération, seule la Playstation 3 n'utilisait pas la mémoire unifiée, mais XBOX et la Wii le faisait.
* A partir de la 8ème génération, toutes les consoles utilisent la mémoire unifiée.
Il faut noter que la mémoire utilisée sur ces consoles est une mémoire GDDR, soit le type de mémoire utilisé pour les mémoires vidéo dédiées ! Ce ne sont pas des mémoires DDR normales, optimisées pour fonctionner avec des CPU. Faire ainsi pose plus de problèmes pour le CPU que le GPU, mais ce n'est pas un problème sur une console. Les jeux vidéos sont plus gourmands pour le GFPU que pour le CPU, ce qui fait qu'il vaut mieux privilégier le GPU niveau performance. Ainsi, il vaut mieux utiliser de la mémoire GDDR, qui a une meilleur bande passante et des latences pas terribles. Le GPU sera donc avec une mémoire adaptée, quitte à détériorer les performances du CPU qui préfère les faibles latences.
Il faut noter que les GPU des consoles doivent s'adapter à cette mémoire unfiiée, histoire de conserver de bonnes performances. Les limitations de bande passante se manifestent les GPU des consoles sont adaptés pour limiter la casse. Aussi, les GPU des consoles ne sont pas exactement les mêmes que ceux des PC, et qu'il existe des toutes petites différences. Par exemple, le GPU de la XBOX est une Geforce 3 légèrement modifiée, en partie pour s'adapter à la mémoire unifiée.
Une première adaptation possible est simplement d'ajouter des mémoires caches, ou d'agrandir les mémoires caches existantes. Par exemple, il est possible de doubler le cache de textures ou le cache de sommets. Les GPU des consoles ne s'en sont pas privé, leurs caches sont généralement plus importants que les GPU dédiés équivalents.
Une seconde adaptation a été utilisée sur la Xbox 360, la Xbox One, la Gamecube, la Wii, la WiiU. L'idée était d'utiliser une mémoire dédiée pour le ''framebuffer'' et le tampon de profondeur (ainsi que le tampon de stencil, que nous n'avons pas encore abordé). Mettre à jour le ''framebuffer'' pendant le rendu est responsable d'une grande quantité d'accès mémoire, et c'est encore pire pour le tampon de profondeur. Si on met les deux dans une mémoire dédiée, on économise beaucoup de bande passante.
: Vous aurez peut-être fait le rapprochement avec les GPU à rendu en ''tile'', qui suivent une logique similaire, sauf qu'ils rendent l'image finale morceau par morceau. Ici, pas de système de ''tile''. Les GPU de ce type ont bien une SRAM, mais elle est plus petite et mémorise juste une ''tile'' de petite taille, qui correspond à un morceau de l'image finale, idem pour le ''frambuffer''.
La Xbox 360 utilisait une mémoire EDRAM de 10 Mégaoctets, la Xbox One utilisait 32 mégaoctets de mémoire ESRAM. La Gamecube et la Wii utilisaient 3 mégaoctes de mémoire EDRAM, la WiiU utilisait 32 mégaoctets d'EDRAM. Et mine de rien, ce n'est pas beaucoup. Une image en résolution 1920 par 1080 utilise déjà 8 mégaoctets, ce qui rentre tout juste dans l'EDRAM de la Xbox 360, à condition de ne pas utiliser d'antialiasing. Pour des résolutions usuelles à l'époque, comme le 1280 par 720, ca ne rentre pas si on utilise de l'antialiasing.
Et c'est sans doute pour cette raison que la technique a été abandonnée par la suite. La mémoire RAM nécessaire pour que la technique fonctionne demanderait une mémoire plus grosse, qui utiliserait plus de transistors. Et ce budget en transistor peut être utilisé pour autre chose, ce qui améliorerait les performances. A quoi bon placer une EDRAM dédiée aux ''render target'', alors qu'on peut avoir du cache en remplacement qui améliorera les performances générales ? Pas étonnant que les GPU modernes préfèrent utiliser des GDDR avec une bande passante énorme, ainsi que des mémoires caches de très grande capacité.
==La mémoire virtuelle des GPUs==
Pour commencer, parlons d'un point important, à savoir l'espace d'adressage du GPU. L''''espace d'adressage''' d'un processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées.
L'espace d'adressage du CPU est quelque peu particulier. Depuis les années 80-90, les logiciels n'adressent pas la mémoire RAM directement. Tous les processeurs gèrent un système de mémoire virtuelle, qui donne l'illusion aux programmes d'avoir accès à toute la mémoire adressable, tout l'espace d'adressage. Par exemple, sur les systèmes 32 bits, chaque programme a accès à tout l'espace d'adressage de 4 gigaoctets, et il ne voit pas les autres programmes dedans. C'est une illusion qui a de nombreux avantages : les programmes sont isolés les uns des autres, un programme ne peut pas lire dans la mémoire d'un autre, les programmes n'ont pas à se soucier de la quantité de RAM installée dans l'ordinateur, etc.
Par contre, cela implique que les adresses manipulées par les programmes sont des adresses fictives, qui doivent être traduites en adresses physiques. Les données situées à une adresse dans l'espace d'adressage ne sont pas à la même adresse en RAM. On fait ainsi la distinction entre adresse physique et logique : les adresses logiques sont les fausses adresses, les adresses physiques sont les vraies adresses en RAM.
Rien de tout cela ne devrait vous surprendre si vous avez déjà lu un cours d'architecture des ordinateurs. Maintenant, passons à quelque chose auquel vous n'avez peut-être pas pensé : qu'en est-il du GPU ? La réponse est que non seulement cela dépend de si le GPU est dédié ou intégré, mais que cela dépend aussi de si le GPU est ancien ou non. Les anciens GPU ne géraient pas la mémoire virtuelle, les nouveaux ont leur propre système de mémoire virtuelle séparé du CPU !
===L'abstraction mémoire des GPU===
Cependant, cela pose un léger problème : la communication avec les programmes et les API graphiques est perturbée. Le pilote de périphérique reçoit des adresses virtuelles de la part des applications, mais il doit gérer la mémoire vidéo en utilisant des adresses physiques. Et cela posait de nombreux problèmes pour les pilotes de GPU.
Le cas le plus facile à expliquer est celui des GPU dédiés. Le pilote de GPU alimente la mémoire vidéo avec des transferts DMA et le contrôleur DMA doit être configuré avec des adresses physiques pour faire son travail. Or, les API 3D leur donnaient des adresses virtuelles, pour localiser les textures, ''mesh'', shaders compilés et autres. Et c'est à eux et au système d'exploitation de traduire ces adresses en adresses physiques. Des cas similaires apparaissent sur des GPU intégrés.
Sous Windows, du temps de l'ancien ''Windows Display Driver Model'' (WDDM), c'était le système d’exploitation qui gérait cela. Le WDDM déportait une partie de la gestion du GPU dans le noyau de l'OS, dont la gestion de la mémoire vidéo, vu que seul lui pouvait faire la traduction d'adresse (il a accès au tables des pages). Le pilote de GPU envoyait les commandes matérielles au noyau de l'OS, qui les patchait, en remplaçant les adresses virtuelles par des adresses physiques. Le pilote envoyait alors les commandes traduites au GPU.
Avec le WDDM 2.0, les GPU supportent maintenant la mémoire virtuelle. Cependant, il faut noter que les GPU utilisent une mémoire virtuelle séparée de celle du CPU. Le processeur et le GPU ont deux espaces d'adressage différents. Concrètement, une adresse virtuelle n'adresse pas la même adresse physique selon qu'elle est utilisée par le GPU. De même, la même adresse physique correspondra à des adresses virtuelles différentes entre CPU et GPU. Aussi, on parle de '''mémoire virtuelle GPU''' pour la distinguer de la mémoire virtuelle du processeur.
[[File:Desktop computer bus bandwidths.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle du CPU et du GPU.]]
Même si la mémoire virtuelle du GPU n'est pas celle du CPU, cela simplifie grandement la gestion de la mémoire vidéo. Le pilote de GPU peut travailler directement avec des adresses virtuelles du GPU, et gérer la mémoire vidéo de lui-même, dans avoir à déléguer une partie du travail au noyau de l'OS. Plus besoin de traduire les adresses en adresses physiques, c'est le GPU qui s'en charge de lui-même ! D'ailleurs, cet avantage fait que la mémoire virtuelle GPU est aussi utilisée avec des GPU intégré, qui n'ont pas besoin de faire de copies entre RAM système et RAM vidéo.
[[File:Integrated graphics with distinct memory allocation.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle CPU et GPU, avec un GPU intégré.]]
Pour gérer la mémoire virtuelle, les GPU intègrent un circuit appelé la '''''Graphics address remapping table''''', abrévié en GART. La GART est techniquement une une ''Memory Management Unit'' (MMU), à savoir un circuit spécialisé qui s'occupe de traduire les adresses virtuelles en adresses physiques, elle prend en charge la mémoire virtuelle. La dite MMU étant intégrée dans un périphérique d'entrée-sortie (IO), ici la carte graphique, elle est appelée une IO-MMU (''Input Output-MMU''). Toutes les cartes graphiques utilisant les bus AGP ou PCI-Express intégrent une GART/IO-MMU.
La GART est configurée par le pilote de GPU, afin de gérer la mémoire virtuelle au mieux. Et cela explique que la mémoire virtuelle du GPU et du CPU soient séparées. Le pilote de GPU coopére avec le système d'exploitation pour configurer la GART, mais cette coopération ne peut pas être parfaite. On ne peut pas permettre au pilote de GPU d'avoir accès à la table des pages ou d'autres structures impliquées dans la traduction d'adresse : le risque de sécurité est trop grand. Avoir deux mémoires virtuelles séparées aide grandement le travail du pilote de GPU.
Cependant, quelques technologies permette au CPU et au GPU d'utiliser le même espace d'adressage, de fusionner la mémoire virtuelle du CPU et du GPU. Par exemple, la technologie ''Heterogeneous System Architecture'' permet cela, entre autres fonctionnalités. Elles permettent de synchroniser la MMU du processeur et l'IO-MMU du GPU.
{|
|[[File:HSA-enabled virtual memory with distinct graphics card.svg|vignette|upright=2|HSA-enabled virtual memory with distinct graphics card]]
|[[File:HSA-enabled integrated graphics.svg|vignette|upright=2|HSA-enabled integrated graphics]]
|}
===La mémoire virtuelle des GPU dédiés===
Pour rappel, la mémoire virtuelle permet à un CPU d'utiliser plus de RAM qu'il n'y en a d'installée dans l'ordinateur. Par exemple, elle permet au CPU de gérer 4 gigas de RAM sur un ordinateur qui n'en contient que trois, le gigaoctet de trop étant en réalité simulé par un fichier sur le disque dur. La technique est utilisée par tous les processeurs modernes.
La mémoire virtuelle des GPUs dédiés fait la même chose, sauf que le surplus d'adresses n'est pas stockés sur le disque dur dans un fichier pagefile, mais est dans la RAM système. Pour le dire autrement, ces cartes dédiées peuvent utiliser la mémoire système si jamais la mémoire vidéo est pleine. Cela permet au GPU d'adresser plus de RAM qu'en a la mémoire vidéo. Par exemple, si la carte vidéo a 2 giga-octets de RAM, la carte graphique peut être capable d'en adresser 8 : 2 gigas en RAM vidéo, et 6 autres gigas en RAM système. Le GPU peut lire directement des données en RAM, sans forcément les copier en mémoire vidéo.
[[File:Mémoire virtuelle des cartes graphiques dédiées.png|centre|vignette|upright=2|Mémoire virtuelle des cartes graphiques dédiées]]
La technologie s'est démocratisée avec le bus AGP, dont la fonctionnalité dite d'''AGP texturing'' permettait de lire ou écrire directement dans la mémoire RAM, sans passer par le processeur. D'ailleurs, la carte graphique Intel i740 n'avait pas de mémoire vidéo et se débrouillait uniquement avec la mémoire système. C'est l'AGP qui a introduit le GART, la fameuse IO-MMU mentionnée plus haut.
L'arrivée du bus PCI-Express ne changea pas la donne, si ce n'est que le bus était plus rapide, ce qui améliorait les performances. Au début, seules les cartes graphiques PCI-Express d'entrée de gamme pouvaient accéder à certaines portions de la mémoire RAM grâce à des technologies adaptées, comme le TurboCache de NVIDIA ou l'HyperMemory d'AMD. Mais la technologie s'est aujourd'hui étendue. De nos jours, toutes les cartes vidéos modernes utilisent la RAM système en plus de la mémoire vidéo, mais seulement en dernier recours, soit quand la mémoire vidéo est quasiment pleine, soit pour faciliter les échanges de données avec le processeur. C'est typiquement le pilote de la carte graphique qui décide ce qui va dans la mémoire vidéo et la mémoire système, et il fait au mieux de manière à avoir les performances optimales.
===Les GPU utilisent la pagination===
Le GPU utilise la technique dite de la pagination, à savoir que la RAM système et la RAM du GPU sont découpées en pages de taille fixe, généralement 4 kilo-octets. Un GPU dédié échange des pages entre RAM système et mémoire vidéo. Lors d'un transfert DMA, la page en RAM système est copiée en mémoire vidéo. S'il n'y a pas assez de place en mémoire vidéo, le GPU rapatrie une page de mémoire vidéo vers la RAM système. La page rapatriée en RAM système est choisie par un algorithme spécialisé. Un GPU intégré n'a pas besoin de copie, il lit directement la page voulue en RAM système.
La traduction des adresses virtuelles en adresses physique se fait au niveau de la page. Une adresse est coupée en deux parts : un numéro de page, et la position de la donnée dans la page. La position dans la page ne change pas lors de la traduction d'adresse, mais le numéro de page est lui traduit. Le numéro de page virtuel est remplacé par un numéro de page physique lors de la traduction.
Pour remplacer le numéro de page virtuel en numéro physique, il faut utiliser une table de translation, appelée la '''table des pages''', qui associe un numéro de page logique à un numéro de page physique. Le système d'exploitation dispose de sa table des pages, qui n'est pas accesible au GPU. Par contre, le GPU dispose d'une sorte de mini-table des pages, qui contient les associations page virtuelle-physique utiles pour traiter les commandes GPU, et rien d'autre. En clair, une sorte de sous-ensemble de la table des pages de l'OS, mais spécifique au GPU. La mini-table des pages est gérée par le pilote de périphérique, qui remplit la mini-table des pages. La mini-table des pages est mémorisée dans une mémoire intégrée au GPU, et précisément dans la MMU.
===Le contrôleur DMA et l'IO-MMU des GPU dédiés===
Sur les GPU dédiés, le contrôleur DMA est souvent fusionné avec l'IO-MMU. En effet, il s'occupe de la copie des pages entre mémoire vidéo et RAM système. Le contrôleur DMA reçoit des adresses provenant du pilote de périphérique, qui sont des adresses virtuelles. Mais vu qu'il accède à la RAM système, il doit faire la traduction entre adresses virtuelles qu'il reçoit et adresses physiques qu'il émet, ce qui implique qu'il sert d'IO-MMU.
Même si la mémoire virtuelle GPU a été intégrée dans Windows assez tard, du temps de l'AGP et du PCI-Express, la technologie existait vraisemblablement sur certaines cartes graphiques au format PCI, même la documentation est assez rare. Seule certitude : la carte graphique NV1 de NVIDIA, leur toute première carte graphique, disposait d'un contrôleur DMA avec une IO-MMU intégrée. Le fonctionnement de cette IOMMU est décrite dans le brevet "US5758182A : DMA controller translates virtual I/O device address received directly from application program command to physical i/o device address of I/O device on device bus", des inventeurs David S. H. Rosenthal et Curtis Priem.
[[File:Microarchitecture du GPU NV1 de NVIDIA.png|centre|vignette|upright=2|Microarchitecture du GPU NV1 de NVIDIA]]
{{NavChapitre | book=Les cartes graphiques
| prev=Les caches d'un processeur de shader
| prevText=Les caches d'un processeur de shader
| next=Le rendu d'une scène 3D : l'API graphique
| netxText=Le rendu d'une scène 3D : l'API graphique
}}{{autocat}}
5xmjtrwgxv4nqq1gqe3meux5v1vjiuz
762754
762753
2026-04-02T00:56:20Z
Mewtow
31375
/* Les GPU des consoles */
762754
wikitext
text/x-wiki
Pour rappel, il existe deux types de cartes graphiques : les cartes dédiées et les cartes intégrées. Les '''cartes graphiques dédiées''' sont des cartes graphiques branchées sur des connecteurs/ports de la carte mère. A l'opposé, tous les processeurs modernes intègrent une carte graphique, appelée '''carte graphique intégrée''', ou encore '''IGP''' (''Integrated Graphic Processor''). En somme, les cartes dédiées sont opposées à celles intégrées dans les processeurs modernes.
Les cartes graphiques dédiées ont de la mémoire vidéo intégrée à la carte graphique, sauf pour quelques exceptions dont on parlera plus tard. Par contre, les IGP n'ont pas de mémoire vidéo dédiée, vu qu'on ne peut pas intégrer beaucoup de mémoire dans un processeur. Et cela permet de classer les cartes graphiques en deux types :
* Les cartes graphiques à '''mémoire vidéo dédiée''', à savoir que la carte graphique dispose de sa propre mémoire rien qu'à elle, séparée de la mémoire RAM de l'ordinateur. On fait alors la distinction entre ''RAM système'' et ''RAM vidéo''.
* Les cartes graphiques à '''mémoire unifiée''', où la mémoire RAM est partagée entre le processeur et la carte graphique. Le terme "unifiée" sous-entend que l'on a unifié la mémoire vidéo et la mémoire système (la RAM).
[[File:Répartition de la mémoire entre RAM système et carte graphique.png|centre|vignette|upright=2.5|Répartition de la mémoire entre RAM système et carte graphique]]
La distinction "mémoire dédiée versus unifiée" correspond de très près à la distinction "GPU dédié versus IGP". Dans la grosse majorité des cas, les cartes vidéos dédiées ont une mémoire dédiée, alors que les IGP utilisent la mémoire unifiée. Mais il existe de rares exceptions où une carte vidéo dédiée utilise la mémoire unifiée. Par exemple, la toute première carte graphique AGP, l'Intel 740, ne possédait pas de mémoire vidéo proprement dite, juste un simple ''framebuffer''. Tout le reste, texture comme géométrie, était placé en mémoire système ! Les performances étaient ridicules, mais les cartes étaient peu chères du fait de l’absence de VRAM, ce qui explique que l'Intel 740 a eu un petit succès sur les ordinateurs d'entrée de gamme.
Une autre exception est celle des GPU soudés sur la carte mère, utilisées sur certaines consoles de jeu, ainsi que certains PC portables puissants destinés aux ''gamers''. Pour ces dernières, il est possible d'utiliser aussi bien de la mémoire dédiée que de la mémoire unifiée. Si la plupart des consoles récents utilisent de la VRAM dédiées, d'anciennes consoles de jeu avec un GPU soudé utilisaient une mémoire unifiée, comme la Nintendo 64, pour ne citer qu'elle.
{|class="wikitable"
|-
!
! Mémoire unifiée
! Mémoire dédiée
|-
! GPU dédié
| Quelques rares GPU d'entrée de gamme || Tous les GPU, sauf de rares exceptions
|-
! GPU intégré
| Systématique ||
|-
! GPU soudé
| Anciennes consoles de jeu || Ordinateurs portables modernes
|}
==La mémoire vidéo dédiée==
La mémoire dédiée est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de ''Framebuffer'' : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les sommets de l'image à calculer, ainsi que divers résultats temporaires.
: Dans ce qui suit, la mémoire vidéo des cartes graphiques dédiées sera appelée la VRAM.
===Les mémoires GDDR et autres VRAM===
La VRAM ressemble aux barrettes de RAM qu'on trouve dans nos PC, à quelques différences près. Le point le plus important est qu'elle n'est pas présente sous la forme de barrettes de mémoire. À la place, les puces de mémoire sont soudées sur la carte graphique, sur son PCB vert. La conséquence est que l'on ne peut pas upgrader la VRAM d'une carte vidéo. Le fait que la VRAM est soudée simplifie la conception de la carte graphique, mais a aussi des avantages au niveau électrique et donc en termes de performance.
Les cartes graphiques des années 90-2000, utilisaient la même mémoire que celle des barrettes de RAM, à savoir des DRAM de type FPM, EDO, ou SDRAM (''Synchronous DRAM''). De nos jours, les barrettes de RAM utilisent de la mémoire dite DDR (''Double Data Rate''), alors que les VRAM sont des RAM dites GDDR (''Graphic Double Data Rate''). Les deux se ressemblent beaucoup, mais il y a de petites différences techniques qui sont trop complexes pour être expliquées ici.
: Quelques cartes graphiques ont utilisé de la mémoire non-DDR, comme les GPU ''Laguna'' de ''Cirrus Logic'', qui utilisaient de la RDRAM de feu Rambus, une mémoire RAM qui a utilisée comme RAM système sur certains PC et sur la Nintendo 64. Citons aussi les cartes graphiques ''Matrox Millennium'' et ''ATI 3D Rage Pro'', qui utilisaient de la ''Window DRAM'' (WRAM). Idem avec
Niveau performance, la GDDR se distingue de la DDR simple par une bande passante élevée, proche de la centaine de gigaoctets par secondes sur les GPU modernes. Mais il y a une contrepartie : un temps d'accès très long, de plusieurs centaines de cycles d'horloge. Concrètement, si je veux lire une texture, entre le moment où j'envoie une demande de lecture à la mémoire vidéo, et le moment celle-ci me renvoie les premiers texels, il va se passer entre 200 à 1000 cycles d'horloge GPU. Par contre, une fois les premiers texels reçus, les texels suivants sont disponibles au cycle suivant, et ainsi de suite. En clair, les données lues mettent du temps avant d'arriver, mais elles arrivent par gros paquets.
Les GPU récents sont des monstres de bande passante et ce n'est pas qu'à cause de la GDDR. Une puce mémoire de DDR/GDDR peut lire/écrire 64 bits par cycle d'horloge. Mais les GPU connectent la GDDR de manière à additionner la bande passante de plusieurs puces. Cela implique que chaque puce de RAM a sa propre connexion au GPU, ce qui permet d’accéder à plusieurs puces en parallèle, en même temps. Les GPU actuels sont capables de lire/écrire 192, 256, 384, voire 512 bits par cycle d'horloge. Les techniques de ''dual channel'' permettent de faire la même chose avec la RAM système, mais n’atteignent que 128 bits par cycle - 192/256 bits avec des techniques de ''triple/quad channel''. En clair, le bus mémoire de la GDDR permet de lire/écrire plus de données par cycle d'horloge qu'une RAM système, de 2 à 8 fois plus.
[[File:Puces mémories d'un GPU et d'une barrette de mémoire.png|centre|vignette|upright=2|Puces mémoires d'un GPU et d'une barrette de mémoire.]]
La différence entre débit et temps d'accès est primordiale sur les GPU modernes comme anciens. Toute l'architecture de la carte graphique est conçue de manière à prendre en compte ce temps d'attente. Les techniques employées sont multiples, et ne sont pas inconnues à ceux qui ont déjà lu un cours d'architecture des ordinateurs : mémoire caches, hiérarchie de caches, ''multithreading'' matériel au niveau du processeur, optimisations des accès mémoire comme des ''Load-Store Queues'' larges, des ''coalesing write buffers'', etc. Mais toutes ces techniques sont techniquement incorporées dans les processeurs de ''shaders'' et dans les circuits fixes. Aussi nous ne pouvons pas en parler dans ce chapitre. À une exception près : l'usage de caches et de ''local stores''.
===Les transferts ''Direct Memory Access''===
Pour échanger des données entre la RAM et la mémoire vidéo, les GPU utilisent la technologie ''Direct Memory Access'', aussi appelée DMA. Elle permet à un périphérique de lire/écrire un bloc de mémoire RAM, sans intervention du processeur, par l'intermédiaire du bus PCI Express.
Pour cela, le GPU intègre un circuit dédié à la gestion des transferts DMA, appelé le '''contrôleur DMA''', qui lit des données en RAM système pour les copier en RAM vidéo (ou inversement, mais c'est plus rare). Précisément, le contrôleur DMA copie un bloc de mémoire, de données consécutives en mémoire, par exemple un bloc de 128 mégaoctets, un bloc de 64 kiloctets, ou autre. Le processeur configure le contrôleur DMA en lui indiquant l'adresse de départ du bloc de mémoire, sa taille, et quelques informations annexes. Le contrôleur DMA lit alors les données une par une, et les écrit dans la mémoire vidéo.
===La mémoire vidéo est mappée dans l'espace d'adressage du CPU===
Les GPU doivent souvent échanger des données avec le processeur. Des données doivent être copiées de la mémoire RAM vers la VRAM. De plus, le CPU peut aussi adresser directement la VRAM. Pour cela, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, grâce à la technique des '''entrées-sorties mappées en mémoire'''. Et c'est ce qui est fait pour le GPU : une partie des adresses est détournée vers le GPU. Typiquement un bloc d'adresse de la même taille que la mémoire vidéo est détournée : elles n'adressent plus de la RAM, mais la directement la mémoire vidéo de la carte graphique. En clair, le processeur voit la mémoire vidéo et peut lire ou écrire dedans directement.
[[File:Espace d'adressage classique avec entrées-sorties mappées en mémoire.png|centre|vignette|upright=2|Espace d'adressage classique avec entrées-sorties mappées en mémoire]]
Intuitivement, on se dit que toute la mémoire vidéo est visible par le CPU, mais le bus PCI, AGP ou PCI Express ont leur mot à dire. Le bus PCI permettait au CPU d'adresser une fenêtre de 256 mégaoctets de VRAM maximum, en raison d’une sombre histoire de configuration des ''Base Address Registers'' (BARs). Les registres BAR étaient utilisés pour gérer les transferts DMA, mais aussi pour l'adressage direct.
Le PCI Express était aussi dans ce cas avant 2008. La gestion de la mémoire vidéo était alors difficile, mais on pouvait adresser plus de 256 mégaoctets, en déplaçant la fenêtre de 256 mégaoctets dans la mémoire vidéo. Après 2008, la spécification du PCI-Express ajouta un support de la technologie ''resizable bar'', qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.
==La mémoire unifiée==
Avec la mémoire unifiée, une partie de la RAM système est détournée pour servir de mémoire vidéo. La quantité d'adresses détournées est généralement réglable avec un réglage dans le BIOS. On peut ainsi choisir d'allouer 64, 128 ou 256 mégaoctets de mémoire système pour la carte vidéo, sur un ordinateur avec 4 gigaoctets de RAM. Les GPU modernes sont plus souples et fournissent deux réglages : une quantité de RAM vidéo minimale et une quantité de RAM maximale que le GPU ne peut pas dépasser. Par exemple, il est possible de régler le GPU de manière à ce qu'il ait 64 mégaoctets rien que pour lui, mais qu'il puisse avoir accès à maximum 1 gigaoctet s'il en a besoin. Cela fait au total 960 mégaoctets (1024-64) qui peut être alloués au choix à la carte graphique ou au reste des programmes en cours d’exécution, selon les besoins.
[[File:Partage de la mémoire unifiée entre CPU et GPU.png|centre|vignette|upright=2|Répartition de la mémoire entre RAM système et carte graphique]]
===Les GPU dédiés avec mémoire unifiée===
Il existe des cartes dédiées qui utilisent pourtant la mémoire unifiée, par exemple l'Intel 740. Pour lire en mémoire RAM, elles doivent passer par l'intermédiaire du bus AGP, PCI ou PCI-Express. Et ce bus est très lent, bien plus que ne le serait une mémoire vidéo normale. Aussi, les performances sont exécrables. J'insiste sur le fait que l'on parle des cartes graphiques dédiées, mais pas des cartes graphiques soudées des consoles de jeu.
D'ailleurs, de telles cartes dédiées incorporent un ''framebuffer'' directement dans la carte graphique. Il n'y a pas le choix, le VDC de la carte graphique doit accéder à une mémoire suffisamment rapide pour alimenter l'écran. Ils ne peuvent pas prendre le risque d'aller lire la RAM, dont le temps de latence est élevé, et qui peut potentiellement être réservée par le processeur pendant l’affichage d'une image à l'écran.
===Les GPU intégrés===
Les GPU intégrés ou soudés passent par le bus AGP ou PCI Express pour lire des données en RAM système. Mais leur accès à la RAM passe par les mêmes voies que le CPU. Les GPU et le processeur sont reliés à la RAM par un bus dédié appelé le '''bus mémoire'''. Il existe même sans GPU intégré : tous les processeurs sont reliés à la RAM par un tel bus. Si le CPU intègre un IGPU, il greffe l'IGPU sur ce bus mémoire existant.
Un défaut de cette approche est que le débit du bus système est partagé entre le GPU et le processeur. En clair, si le bus mémoire peut transférer 20 gigas de données par secondes, il faudra partager ces 20 gigas/seconde entre CPU et GPU. Par exemple, le CPU aura droit à 15 gigas par secondes, le GPU seulement 5 gigas. Divers circuits d'arbitrage s'occupent de répartir équitablement le bus système, selon les besoins, mais ça reste un compromis imparfait.
[[File:Echanges de données entre CPU et GPU avec une mémoire unifiée.png|centre|vignette|upright=2|Connexion du bus mémoire au CPU et à un GPU soudé sur la carte mère.]]
N'allez cependant pas croire que les GPU intégrés n'ont que des désavantages. Ils disposent d'un avantage bien spécifique : la '''''zero-overhead copy''''', terme barbare mais qui cache une réalité très simple. Avec une mémoire dédiée, le processeur doit copier des données de la RAM système dans la RAM vidéo. Les copies en question se font souvent avant de démarrer le rendu 3D, par exemple lors du chargement d'un niveau dans un jeu vidéo. Elles peuvent aussi se faire lors du rendu, bien que ce soit plus rare. Et ces copies ont un cout en performance. Par contre, avec la mémoire unifié, pas besoin de faire de copie d'une mémoire à l'autre. Le processeur envoie juste une commande du GPU, qui indique l'adresse des données en RAM, leur position dans la RAM.
Le processeur et le GPU intègrent des mémoires caches, afin de réduire l'usage du bus mémoire. Et l'intégration des caches avec un GPU intégré est assez intéressante. Le CPU et l'IGPU peuvent partager certains caches. Par exemple, les processeurs Skylake et Sandy Bridge d'Intel, le CPU et GPU avaient leurs propres caches L2 et L1, mais ils partageaient le cache L3. En général, le partage ne touche que le cache de dernier niveau, le cache le plus gros et le plus proche de la mémoire, à savoir le cache L3 ou L4.
Sur les processeurs modernes, le CPU et le GPU ont leur propre cache L3/L4, afin avoir des caches plus spécialisés. Les caches L3/L4 sont plus gros pour le processeur que pour le GPU, ils vont à des fréquences différentes, sont alimentés par des tensions différentes, etc. De plus, le cache du CPU est optimisé pour un temps d'accès faible, alors que celui du GPU est optimisé pour un fort débit mémoire. Utiliser des caches séparés entraine des problèmes de cohérence des caches, qui ont été vus dans le chapitre sur les caches des processeurs de shaders.
[[File:Caches sur un iGPU.png|centre|vignette|upright=2.5|Caches sur un iGPU]]
===Les GPU des consoles===
Les consoles de jeu utilisent souvent la mémoire unifiée, même les consoles récentes. Pour les consoles de salon, les consoles Nintendo ont été les pionnières de la mémoire unifiée, XBOX l'a adopté dès le début, et les Playstation ont été les dernières à l'utiliser.
* Pour les consoles de 5ème génération, Nintendo 64 utilisait déjà la mémoire unifiée, alors que les autres consoles de l'époque faisaient avec une mémoire vidéo dédiée.
* Pour la 6ème génération, la Gamecube et la Xbox utilisaient la mémoire unifiée, pas la Playstation 2. A partir de la génération suivante, la mémoire unifiée est devenue la solution dominante.
* Pour la 7ème génération, seule la Playstation 3 n'utilisait pas la mémoire unifiée, mais XBOX et la Wii le faisait.
* A partir de la 8ème génération, toutes les consoles utilisent la mémoire unifiée.
Il faut noter que la mémoire utilisée sur ces consoles est une mémoire GDDR, soit le type de mémoire utilisé pour les mémoires vidéo dédiées ! Ce ne sont pas des mémoires DDR normales, optimisées pour fonctionner avec des CPU. Faire ainsi pose plus de problèmes pour le CPU que le GPU, mais ce n'est pas un problème sur une console. Les jeux vidéos sont plus gourmands pour le GFPU que pour le CPU, ce qui fait qu'il vaut mieux privilégier le GPU niveau performance. Ainsi, il vaut mieux utiliser de la mémoire GDDR, qui a une meilleure bande passante et des latences pas terribles. Le GPU sera donc avec une mémoire adaptée, quitte à détériorer les performances du CPU qui préfère les faibles latences.
Les GPU des consoles doivent s'adapter à cette mémoire unifiée, histoire de conserver de bonnes performances. Les limitations de bande passante se manifestent les GPU des consoles sont adaptés pour limiter la casse. Aussi, les GPU des consoles ne sont pas exactement les mêmes que ceux des PC, et qu'il existe des toutes petites différences. Par exemple, le GPU de la XBOX est une Geforce 3 légèrement modifiée, en partie pour s'adapter à la mémoire unifiée.
Une adaptation possible est simplement d'ajouter des mémoires caches, ou d'agrandir les mémoires caches existantes. Par exemple, il est possible de doubler le cache de textures ou le cache de sommets. Les GPU des consoles ne s'en sont pas privé, leurs caches sont généralement plus importants que les GPU dédiés équivalents.
Une seconde adaptation a été utilisée sur la Xbox 360, la Xbox One, la Gamecube, la Wii, la WiiU. L'idée était d'utiliser une mémoire dédiée pour le ''framebuffer'' et le tampon de profondeur (ainsi que le tampon de stencil, que nous n'avons pas encore abordé). Mettre à jour le ''framebuffer'' pendant le rendu est responsable d'une grande quantité d'accès mémoire, et c'est encore pire pour le tampon de profondeur. Si on met les deux dans une mémoire dédiée, on économise beaucoup de bande passante.
: Vous aurez peut-être fait le rapprochement avec les GPU à rendu en ''tile'', qui suivent une logique similaire, sauf qu'ils rendent l'image finale morceau par morceau. Ici, pas de système de ''tile''. Les GPU de ce type ont bien une SRAM, mais elle est plus petite et mémorise juste une ''tile'' de petite taille, qui correspond à un morceau de l'image finale, idem pour le ''frambuffer''.
La Xbox 360 utilisait une mémoire EDRAM de 10 Mégaoctets, la Xbox One utilisait 32 mégaoctets de mémoire ESRAM. La Gamecube et la Wii utilisaient 3 mégaoctets de mémoire EDRAM, la WiiU utilisait 32 mégaoctets d'EDRAM. Et mine de rien, ce n'est pas beaucoup. Une image en résolution 1920 par 1080 utilise déjà 8 mégaoctets, ce qui rentre tout juste dans l'EDRAM de la Xbox 360, à condition de ne pas utiliser d'antialiasing. Pour des résolutions usuelles à l'époque, comme le 1280 par 720, ca ne rentre pas si on utilise de l'antialiasing.
Et c'est sans doute pour cette raison que la technique a été abandonnée par la suite. La mémoire RAM nécessaire pour que la technique fonctionne demanderait une mémoire plus grosse, qui utiliserait plus de transistors. Et ce budget en transistor peut être utilisé pour autre chose, ce qui améliorerait les performances. A quoi bon placer une EDRAM dédiée aux ''render target'', alors qu'on peut avoir du cache en remplacement qui améliorera les performances générales ? Pas étonnant que les GPU modernes préfèrent utiliser des GDDR avec une bande passante énorme, ainsi que des mémoires caches de très grande capacité.
==La mémoire virtuelle des GPUs==
Pour commencer, parlons d'un point important, à savoir l'espace d'adressage du GPU. L''''espace d'adressage''' d'un processeur est l'ensemble des adresses utilisables par le processeur. Par exemple, un processeur 16 bits peut adresser 2^16 = 65536 adresses, l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas toujours égal à la mémoire réellement installée. S'il n'y a pas assez de RAM installée, des adresses seront inoccupées.
L'espace d'adressage du CPU est quelque peu particulier. Depuis les années 80-90, les logiciels n'adressent pas la mémoire RAM directement. Tous les processeurs gèrent un système de mémoire virtuelle, qui donne l'illusion aux programmes d'avoir accès à toute la mémoire adressable, tout l'espace d'adressage. Par exemple, sur les systèmes 32 bits, chaque programme a accès à tout l'espace d'adressage de 4 gigaoctets, et il ne voit pas les autres programmes dedans. C'est une illusion qui a de nombreux avantages : les programmes sont isolés les uns des autres, un programme ne peut pas lire dans la mémoire d'un autre, les programmes n'ont pas à se soucier de la quantité de RAM installée dans l'ordinateur, etc.
Par contre, cela implique que les adresses manipulées par les programmes sont des adresses fictives, qui doivent être traduites en adresses physiques. Les données situées à une adresse dans l'espace d'adressage ne sont pas à la même adresse en RAM. On fait ainsi la distinction entre adresse physique et logique : les adresses logiques sont les fausses adresses, les adresses physiques sont les vraies adresses en RAM.
Rien de tout cela ne devrait vous surprendre si vous avez déjà lu un cours d'architecture des ordinateurs. Maintenant, passons à quelque chose auquel vous n'avez peut-être pas pensé : qu'en est-il du GPU ? La réponse est que non seulement cela dépend de si le GPU est dédié ou intégré, mais que cela dépend aussi de si le GPU est ancien ou non. Les anciens GPU ne géraient pas la mémoire virtuelle, les nouveaux ont leur propre système de mémoire virtuelle séparé du CPU !
===L'abstraction mémoire des GPU===
Cependant, cela pose un léger problème : la communication avec les programmes et les API graphiques est perturbée. Le pilote de périphérique reçoit des adresses virtuelles de la part des applications, mais il doit gérer la mémoire vidéo en utilisant des adresses physiques. Et cela posait de nombreux problèmes pour les pilotes de GPU.
Le cas le plus facile à expliquer est celui des GPU dédiés. Le pilote de GPU alimente la mémoire vidéo avec des transferts DMA et le contrôleur DMA doit être configuré avec des adresses physiques pour faire son travail. Or, les API 3D leur donnaient des adresses virtuelles, pour localiser les textures, ''mesh'', shaders compilés et autres. Et c'est à eux et au système d'exploitation de traduire ces adresses en adresses physiques. Des cas similaires apparaissent sur des GPU intégrés.
Sous Windows, du temps de l'ancien ''Windows Display Driver Model'' (WDDM), c'était le système d’exploitation qui gérait cela. Le WDDM déportait une partie de la gestion du GPU dans le noyau de l'OS, dont la gestion de la mémoire vidéo, vu que seul lui pouvait faire la traduction d'adresse (il a accès au tables des pages). Le pilote de GPU envoyait les commandes matérielles au noyau de l'OS, qui les patchait, en remplaçant les adresses virtuelles par des adresses physiques. Le pilote envoyait alors les commandes traduites au GPU.
Avec le WDDM 2.0, les GPU supportent maintenant la mémoire virtuelle. Cependant, il faut noter que les GPU utilisent une mémoire virtuelle séparée de celle du CPU. Le processeur et le GPU ont deux espaces d'adressage différents. Concrètement, une adresse virtuelle n'adresse pas la même adresse physique selon qu'elle est utilisée par le GPU. De même, la même adresse physique correspondra à des adresses virtuelles différentes entre CPU et GPU. Aussi, on parle de '''mémoire virtuelle GPU''' pour la distinguer de la mémoire virtuelle du processeur.
[[File:Desktop computer bus bandwidths.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle du CPU et du GPU.]]
Même si la mémoire virtuelle du GPU n'est pas celle du CPU, cela simplifie grandement la gestion de la mémoire vidéo. Le pilote de GPU peut travailler directement avec des adresses virtuelles du GPU, et gérer la mémoire vidéo de lui-même, dans avoir à déléguer une partie du travail au noyau de l'OS. Plus besoin de traduire les adresses en adresses physiques, c'est le GPU qui s'en charge de lui-même ! D'ailleurs, cet avantage fait que la mémoire virtuelle GPU est aussi utilisée avec des GPU intégré, qui n'ont pas besoin de faire de copies entre RAM système et RAM vidéo.
[[File:Integrated graphics with distinct memory allocation.svg|centre|vignette|upright=2|Séparation de la mémoire virtuelle CPU et GPU, avec un GPU intégré.]]
Pour gérer la mémoire virtuelle, les GPU intègrent un circuit appelé la '''''Graphics address remapping table''''', abrévié en GART. La GART est techniquement une une ''Memory Management Unit'' (MMU), à savoir un circuit spécialisé qui s'occupe de traduire les adresses virtuelles en adresses physiques, elle prend en charge la mémoire virtuelle. La dite MMU étant intégrée dans un périphérique d'entrée-sortie (IO), ici la carte graphique, elle est appelée une IO-MMU (''Input Output-MMU''). Toutes les cartes graphiques utilisant les bus AGP ou PCI-Express intégrent une GART/IO-MMU.
La GART est configurée par le pilote de GPU, afin de gérer la mémoire virtuelle au mieux. Et cela explique que la mémoire virtuelle du GPU et du CPU soient séparées. Le pilote de GPU coopére avec le système d'exploitation pour configurer la GART, mais cette coopération ne peut pas être parfaite. On ne peut pas permettre au pilote de GPU d'avoir accès à la table des pages ou d'autres structures impliquées dans la traduction d'adresse : le risque de sécurité est trop grand. Avoir deux mémoires virtuelles séparées aide grandement le travail du pilote de GPU.
Cependant, quelques technologies permette au CPU et au GPU d'utiliser le même espace d'adressage, de fusionner la mémoire virtuelle du CPU et du GPU. Par exemple, la technologie ''Heterogeneous System Architecture'' permet cela, entre autres fonctionnalités. Elles permettent de synchroniser la MMU du processeur et l'IO-MMU du GPU.
{|
|[[File:HSA-enabled virtual memory with distinct graphics card.svg|vignette|upright=2|HSA-enabled virtual memory with distinct graphics card]]
|[[File:HSA-enabled integrated graphics.svg|vignette|upright=2|HSA-enabled integrated graphics]]
|}
===La mémoire virtuelle des GPU dédiés===
Pour rappel, la mémoire virtuelle permet à un CPU d'utiliser plus de RAM qu'il n'y en a d'installée dans l'ordinateur. Par exemple, elle permet au CPU de gérer 4 gigas de RAM sur un ordinateur qui n'en contient que trois, le gigaoctet de trop étant en réalité simulé par un fichier sur le disque dur. La technique est utilisée par tous les processeurs modernes.
La mémoire virtuelle des GPUs dédiés fait la même chose, sauf que le surplus d'adresses n'est pas stockés sur le disque dur dans un fichier pagefile, mais est dans la RAM système. Pour le dire autrement, ces cartes dédiées peuvent utiliser la mémoire système si jamais la mémoire vidéo est pleine. Cela permet au GPU d'adresser plus de RAM qu'en a la mémoire vidéo. Par exemple, si la carte vidéo a 2 giga-octets de RAM, la carte graphique peut être capable d'en adresser 8 : 2 gigas en RAM vidéo, et 6 autres gigas en RAM système. Le GPU peut lire directement des données en RAM, sans forcément les copier en mémoire vidéo.
[[File:Mémoire virtuelle des cartes graphiques dédiées.png|centre|vignette|upright=2|Mémoire virtuelle des cartes graphiques dédiées]]
La technologie s'est démocratisée avec le bus AGP, dont la fonctionnalité dite d'''AGP texturing'' permettait de lire ou écrire directement dans la mémoire RAM, sans passer par le processeur. D'ailleurs, la carte graphique Intel i740 n'avait pas de mémoire vidéo et se débrouillait uniquement avec la mémoire système. C'est l'AGP qui a introduit le GART, la fameuse IO-MMU mentionnée plus haut.
L'arrivée du bus PCI-Express ne changea pas la donne, si ce n'est que le bus était plus rapide, ce qui améliorait les performances. Au début, seules les cartes graphiques PCI-Express d'entrée de gamme pouvaient accéder à certaines portions de la mémoire RAM grâce à des technologies adaptées, comme le TurboCache de NVIDIA ou l'HyperMemory d'AMD. Mais la technologie s'est aujourd'hui étendue. De nos jours, toutes les cartes vidéos modernes utilisent la RAM système en plus de la mémoire vidéo, mais seulement en dernier recours, soit quand la mémoire vidéo est quasiment pleine, soit pour faciliter les échanges de données avec le processeur. C'est typiquement le pilote de la carte graphique qui décide ce qui va dans la mémoire vidéo et la mémoire système, et il fait au mieux de manière à avoir les performances optimales.
===Les GPU utilisent la pagination===
Le GPU utilise la technique dite de la pagination, à savoir que la RAM système et la RAM du GPU sont découpées en pages de taille fixe, généralement 4 kilo-octets. Un GPU dédié échange des pages entre RAM système et mémoire vidéo. Lors d'un transfert DMA, la page en RAM système est copiée en mémoire vidéo. S'il n'y a pas assez de place en mémoire vidéo, le GPU rapatrie une page de mémoire vidéo vers la RAM système. La page rapatriée en RAM système est choisie par un algorithme spécialisé. Un GPU intégré n'a pas besoin de copie, il lit directement la page voulue en RAM système.
La traduction des adresses virtuelles en adresses physique se fait au niveau de la page. Une adresse est coupée en deux parts : un numéro de page, et la position de la donnée dans la page. La position dans la page ne change pas lors de la traduction d'adresse, mais le numéro de page est lui traduit. Le numéro de page virtuel est remplacé par un numéro de page physique lors de la traduction.
Pour remplacer le numéro de page virtuel en numéro physique, il faut utiliser une table de translation, appelée la '''table des pages''', qui associe un numéro de page logique à un numéro de page physique. Le système d'exploitation dispose de sa table des pages, qui n'est pas accesible au GPU. Par contre, le GPU dispose d'une sorte de mini-table des pages, qui contient les associations page virtuelle-physique utiles pour traiter les commandes GPU, et rien d'autre. En clair, une sorte de sous-ensemble de la table des pages de l'OS, mais spécifique au GPU. La mini-table des pages est gérée par le pilote de périphérique, qui remplit la mini-table des pages. La mini-table des pages est mémorisée dans une mémoire intégrée au GPU, et précisément dans la MMU.
===Le contrôleur DMA et l'IO-MMU des GPU dédiés===
Sur les GPU dédiés, le contrôleur DMA est souvent fusionné avec l'IO-MMU. En effet, il s'occupe de la copie des pages entre mémoire vidéo et RAM système. Le contrôleur DMA reçoit des adresses provenant du pilote de périphérique, qui sont des adresses virtuelles. Mais vu qu'il accède à la RAM système, il doit faire la traduction entre adresses virtuelles qu'il reçoit et adresses physiques qu'il émet, ce qui implique qu'il sert d'IO-MMU.
Même si la mémoire virtuelle GPU a été intégrée dans Windows assez tard, du temps de l'AGP et du PCI-Express, la technologie existait vraisemblablement sur certaines cartes graphiques au format PCI, même la documentation est assez rare. Seule certitude : la carte graphique NV1 de NVIDIA, leur toute première carte graphique, disposait d'un contrôleur DMA avec une IO-MMU intégrée. Le fonctionnement de cette IOMMU est décrite dans le brevet "US5758182A : DMA controller translates virtual I/O device address received directly from application program command to physical i/o device address of I/O device on device bus", des inventeurs David S. H. Rosenthal et Curtis Priem.
[[File:Microarchitecture du GPU NV1 de NVIDIA.png|centre|vignette|upright=2|Microarchitecture du GPU NV1 de NVIDIA]]
{{NavChapitre | book=Les cartes graphiques
| prev=Les caches d'un processeur de shader
| prevText=Les caches d'un processeur de shader
| next=Le rendu d'une scène 3D : l'API graphique
| netxText=Le rendu d'une scène 3D : l'API graphique
}}{{autocat}}
oiiw4cphfergdwfs1zr57ml8juemlow
Utilisateur:Clopeau
2
83770
762759
2026-04-02T07:50:59Z
Clopeau
107841
unua prezentado
762759
wikitext
text/x-wiki
Denis Serge Clopeau né le 6 octobre 1953
médecin retraité
intérêt pour toutes les sciences
aime nature tout est objet de curiosité, mer en bateau à voile, montagne en randonnée et beaucoup de satisfaction à utiliser l'Espéranto langue internationale
auteur d'un WikiLivre Miroir brisé Essai pour un modèle de psychisme objectif
emerita kuracisto
intereso por ĉiuj sciencoj
ŝatas naturon, cîo iinstigas kuriozon, maro per velŝipo, montaro per piedaj ekskursoj kaj granda plezuro uzi Esperanto
verkisto de WikiLibron Rompita Spegulo Eseo por Objekta Psiko
0y59ftbwg1q3sglj3fywewegxi2zm54