• Zack Salloum

Architecture d'un processeur


I. Description



Le processeur (ou CPU de l'anglais Central Processing Unit, « Unité centrale de traitement ») est le composant qui exécute les instructions machine des programmes informatiques. Avec la mémoire notamment, c'est l'un des composants qui existent depuis les premiers ordinateurs et qui sont présents dans tous les ordinateurs. Un processeur construit en un seul circuit intégré est un microprocesseur.

L'invention du transistor en 1948 a ouvert la voie à la miniaturisation des composants électroniques. Car auparavant les ordinateurs prenaient la taille d'une pièce entière.

Les processeurs des débuts étaient conçus spécifiquement pour un ordinateur d'un type donné. Cette méthode coûteuse de conception des processeurs pour une application spécifique a conduit au développement de la production de masse de processeurs qui conviennent pour un ou plusieurs usages. Cette tendance à la standardisation qui débuta dans le domaine des ordinateurs centraux (mainframes à transistors discrets et mini-ordinateurs) a connu une accélération rapide avec l'avènement des circuits intégrés. Les circuits intégrés ont permis la miniaturisation des processeurs. La miniaturisation et la standardisation des processeurs ont conduit à leur diffusion dans la vie moderne bien au-delà des usages des machines programmables dédiées.


Architecture d'un processeur (Ref. Wikipedia)

II. Architecture de base d'un processeur



L'architecture de base fonctionnelle d'un processeur consiste à relier le processeur à la mémoire principale via un bus de communication interne et également à des périphériques via un bus de communication interne et/ou externe.

Certaines architecture consiste à utiliser un seul bus de communication interne pour relier le processeur à la mémoire principale et aux périphériques.

La complexité et la rapidité des bus de communication interne et externe jouent un rôle important sur:

  • La vitesse des opérations de l'architecture.

  • La complexité des instructions du processeur.

  • La complexité du code usagé.

  • Les ressources nécessaires pour l'implémentations de l'architecture.

  • L'adaptabilité de l'architecture avec les périphériques et la complexité du code des pilotes des périphériques.


III. Opération d'un processeur



Le rôle fondamental de la plupart des unités centrales de traitement, indépendamment de la forme physique qu'elles prennent, est d'exécuter une série d'instructions stockées appelées "programme".

L’ensemble des instructions et des données constitue un programme.

Le langage le plus proche du code machine tout en restant lisible par des humains est le langage d’assemblage, aussi appelé langage assembleur (forme francisée du mot anglais « assembler »). Toutefois, l’informatique a développé toute une série de langages, dits de « haut niveau » (comme le Pascal, C, C++, Fortran, Ada, etc), destinés à simplifier l’écriture des programmes.


VI. Programmation d'un processeur



VI.1. L'assembleur



Un assembleur est un programme d'ordinateur qui traduit un programme écrit en langage assembleur : essentiellement, une représentation mnémonique du langage machine en code objet.

En plus de traduire les mnémoniques d'instructions en code binaire, les assembleurs sont capables de gérer des noms symboliques pour les emplacements mémoire (pour stocker des données ou référencer des points du programme) et un langage macro pour effectuer des substitutions textuelles - typiquement utilisé pour coder des séquences courtes d'instructions fréquemment utilisées qui seront insérées dans le code plutôt que d'écrire des procédures.

Historiquement, les assembleurs sont apparus comme le premier outil permettant au programmeur de prendre du recul par rapport au code objet et de se consacrer à la programmation proprement dite. Les programmes assembleurs sont plus simples à écrire que les compilateurs pour les langages de haut-niveau. Ils sont disponibles depuis les années 1950.


VI.2. Le compilateur



Un compilateur est un programme informatique qui transforme un code source écrit dans un langage de programmation (le langage source) en langage assembleur ou cible.

Pour qu'il puisse être exploité par la machine, le compilateur traduit le code source, écrit dans un langage de haut niveau d'abstraction, facilement compréhensible par l'humain, vers un langage de plus bas niveau, un langage d'assemblage ou langage machine. Dans le cas de langage semi-compilé (ou semi-interprété), le code source est traduit en un langage intermédiaire, sous forme binaire (code objet ou bytecode), avant d'être lui-même interprété ou compilé.

Un compilateur effectue les opérations suivantes : analyse lexicale, pré-traitement (préprocesseur), analyse syntaxique (parsing), analyse sémantique, génération de code et optimisation de code.

La compilation est souvent suivie d'une étape d'édition des liens, pour générer un fichier binaire pour être chargé dans la mémoire d'exécution d'un processeur.

La tâche principale d'un compilateur est de produire un code objet correct qui s'exécutera sur un processeur. La plupart des compilateurs permettent d'optimiser le code, c'est-à-dire qu'ils vont chercher à améliorer la vitesse d'exécution, ou réduire l'occupation mémoire du programme.

En général, le langage source est « de plus haut niveau » que le langage cible, c'est-à-dire qu'il présente un niveau d'abstraction supérieur. De plus, le code source du programme est généralement réparti dans plusieurs fichiers.

Un compilateur fonctionne par analyse-synthèse : au lieu de remplacer chaque construction du langage source par une suite équivalente de constructions du langage cible, il commence par analyser le texte source pour en construire une représentation intermédiaire qu'il traduit à son tour en langage cible.

On sépare le compilateur en au moins deux parties : une partie avant (ou frontale), parfois appelée « souche », qui lit le texte source et produit la représentation intermédiaire ; et une partie arrière (ou finale), qui parcourt cette représentation pour produire le texte cible. Dans un compilateur idéal, la partie avant est indépendante du langage cible, tandis que la partie arrière est indépendante du langage source. Certains compilateurs effectuent des traitements substantiels sur la partie intermédiaire, devenant une partie centrale à part entière, indépendante à la fois du langage source et de la machine cible. On peut ainsi écrire des compilateurs pour toute une gamme de langages et d'architectures en partageant la partie centrale, à laquelle on attache une partie avant par langage et une partie arrière par architecture.

Les étapes de la compilation incluent :


VI.2.1. Le prétraitement


Le prétraitement est nécessaire pour certains langages comme C, qui prend en charge la substitution de macro et de la compilation conditionnelle.

Généralement, la phase de prétraitement se produit avant l'analyse syntaxique ou sémantique ; par exemple dans le cas de C, le préprocesseur manipule les symboles lexicaux plutôt que des formes syntaxiques.


VI.2.2. L'analyse lexicale


L'analyse lexicale découpe le code source en petits morceaux appelés jetons (tokens).

Chaque jeton est une unité atomique unique de la langue (unités lexicales ou lexèmes), par exemple un mot-clé, un identifiant ou un symbole. La syntaxe de jeton est généralement un langage régulier, donc reconnaissable par un automate à états finis.

Cette phase est aussi appelée à balayage ou lexing ; le logiciel qui effectue une analyse lexicale est appelé un analyseur lexical ou un scanner. Un analyseur lexical pour un langage régulier peut être généré par un programme informatique, à partir d'une description du langage par des expressions régulières.


VI.2.3. L'analyse syntaxique


L'analyse syntaxique implique l'analyse de la séquence jeton pour identifier la structure syntaxique du programme.

Cette phase s'appuie généralement sur la construction d'un arbre d'analyse ; on remplace la séquence linéaire des jetons par une structure en arbre construite selon la grammaire formelle qui définit la syntaxe du langage. Par exemple, une condition est toujours suivie d'un test logique (égalité, comparaison…). L'arbre d'analyse est souvent modifié et amélioré au fur et à mesure de la compilation.


VI.2.4. L'analyse sémantique


L'analyse sémantique est la phase durant laquelle le compilateur ajoute des informations sémantiques à l'arbre d'analyse et construit la table des symboles.

Cette phase vérifie le type (vérification des erreurs de type), ou l'objet de liaison (associant variables et références de fonction avec leurs définitions), ou une tâche définie (toutes les variables locales doivent être initialisées avant utilisation), peut émettre des avertissements, ou rejeter des programmes incorrects.

L'analyse sémantique nécessite habituellement un arbre d'analyse complet, ce qui signifie que cette phase fait suite à la phase d'analyse syntaxique, et précède logiquement la phase de génération de code ; mais il est possible de replier ces phases en une seule passe.


VI.2.5. La transformation


La transformation est la phase de la transformation du code source en code intermédiaire.


VI.2.6. L'optimisation


L'application de techniques d'optimisation sur le code intermédiaire : c'est-à-dire rendre le programme « meilleur » selon son usage.

VI.2.7. La génération de code


la génération de code avec l'allocation de registres et la traduction du code intermédiaire en code objet, avec éventuellement l'insertion de données de débogage et d'analyse de l'exécution.


VI.2.8. L'édition des liens


La phase d’édition des liens consiste en la construction d'une image mémoire contenant l’ensemble des parties de code compilées séparément (modules, sous-programmes ou bibliothèques de sous-programmes). L'éditeur de liens a pour rôle de lier les fichiers objets (fichiers simplement compilés) avec les fichiers précompilés d'une ou plusieurs bibliothèques.

VI.3. Le programmeur


Le programmeur est formé d'un élément électronique et/ou logiciel utilisé pour charger le code binaire généré par le compilateur dans la mémoire d'exécution du processeur.

Un programme spécial peut être implémenté pour charger automatiquement le code binaire vers la mémoire d'exécution du processeur sans l'aide d'un programmeur est le "bootloader". Néanmoins une programmation manuelle est nécessaire pour le chargement du code du "bootloader".



V. Classification des processeurs



V.1. Architecture



L'architecture définit le fonctionnement interne d'un processeur ainsi que le comportement vu par le programmeur. Deux catégories générales sont définies:

  • Architecture à registre ou modèle de Von Neumann

  • Architecture à pile


V.2. Jeu d'instruction (ISA : Instruction Set Architecture)



Le jeu d'instructions est l'ensemble des instructions machines qu'un processeur peut exécuter. Ces instructions machines permettent d'effectuer des opérations élémentaires (addition, ET logique…) ou plus complexes (division, passage en mode basse consommation…).


V.2.1. Types d'instructions


V.2.1.1. Les opérations de traitement des données et de la mémoire

  • Définir une case mémoire à une valeur constante fixe.

  • Déplacer des données d'un emplacement de mémoire à un autre emplacement mémoire.

  • Stocker le résultat d'un calcul, ou récupérer des données stockées pour effectuer un calcul.

  • Lire et écrire des données à partir des périphériques.


V.2.1.2. Les opérations de calculs logique et arithmétique

  • Additionner, soustraire, multiplier ou diviser les valeurs de deux cases mémoires, en plaçant le résultat dans une case mémoire, la création éventuelle d'un ou plusieurs codes de condition dans un registre d'état.

  • Effectuer des opérations sur les bits, par exemple, en prenant la conjonction et de disjonction de bits correspondants dans une paire de cases mémoires, en prenant la négation de chaque bit dans une case mémoire.

  • Comparer deux valeurs dans deux cases mémoires (par exemple, pour voir si on est moins, ou si elles sont égales).


V.2.1.3. Les opérations de contrôle d'exécution

  • Se brancher à un autre endroit dans le programme et exécuter des instructions là.

  • Se brancher conditionnellement à un autre endroit si une certaine condition est vérifiée.

  • Se brancher inconditionnellement à un autre endroit, ou revenir d'un appel d'une fonction.


V.3. Largeur de données



La largeur de ses registres internes de manipulation de données (4, 8, 16, 32, 64, 128) bits et leur utilisation.


V.4. Type de bus de communication interne et/ou externe



Les spécifications des entrées/sorties, de l'accès à la mémoire,...


V.5. Cadence d'horloge



Un processeur est cadencé par un signal d'horloge (signal oscillant régulier imposant un rythme au circuit). Plus cette fréquence est élevée, plus le microprocesseur peut exécuter à un rythme élevé les instructions de base des programmes.

Plus la fréquence est élevée, plus le processeur consomme d'électricité, et plus il chauffe : cela implique d'avoir une solution de refroidissement du processeur adaptée.

La fréquence est notamment limitée par les temps de commutation des portes logiques : il est nécessaire qu'entre deux « coups d'horloge », les signaux numériques aient eu le temps de parcourir tout le trajet nécessaire à l'exécution de l'instruction attendue.


V.6. Vitesse de traitement



La vitesse de traitement d'un processeur est encore parfois exprimée en MIPS (million d'instructions par seconde) ou en mégaFLOPS (millions de floating-point operations per second) pour la partie virgule flottante, dite FPU (Floating Point Unit).

474 views