Summary

Ce document présente les fondements de l'architecture des ordinateurs, en commençant par une introduction et une revue de l'historique de l'architecture de Von Neumann.

Full Transcript

1 Chapitre 1 : ARCHITECTURE DES SYSTÈMES À MICROPROCESSEUR 1.1 Introduction à l'architecture des ordinateurs L'architecture des ordinateurs est une branche de l'informatique qui traite de la conception, de l'organisation et du fonctionnement des ordinateurs. Elle inclut les concepts liés au matér...

1 Chapitre 1 : ARCHITECTURE DES SYSTÈMES À MICROPROCESSEUR 1.1 Introduction à l'architecture des ordinateurs L'architecture des ordinateurs est une branche de l'informatique qui traite de la conception, de l'organisation et du fonctionnement des ordinateurs. Elle inclut les concepts liés au matériel (hardware) et au logiciel (software), ainsi que l'interaction entre ces deux composantes. 1.1.1 Qu'est-ce que l'architecture des ordinateurs ? L'architecture des ordinateurs désigne la manière dont les composants d'un ordinateur interagissent pour exécuter des programmes. Un ordinateur se compose de plusieurs unités de base telles que : L'unité centrale de traitement (CPU) : le cœur de l'ordinateur qui exécute les instructions. La mémoire : où les instructions et les données sont stockées temporairement pendant l'exécution des programmes. Les unités d'entrée/sortie (E/S) : qui permettent à l'ordinateur de communiquer avec l'extérieur (par exemple, clavier, écran, disque dur). 1.1.2 Évolution historique de l'architecture des ordinateurs L'architecture des ordinateurs a évolué au fil du temps, passant des machines mécaniques comme le Zuse Z3 aux ordinateurs électroniques modernes. Une des architectures les plus influentes dans l'histoire de l'informatique est celle proposée par John von Neumann dans les années 1940, connue sous le nom de modèle de Von Neumann. Figure 1 John von Neumann 1903-1957 2 1.2 Origines de l'Architecture de Von Neumann Avant l'architecture de Von Neumann, les premiers ordinateurs étaient des machines fixes et spécialisées, comme l'ENIAC (Electronic Numerical Integrator and Computer), construites pour effectuer des tâches spécifiques et nécessitant des modifications matérielles pour exécuter de nouveaux programmes. Ces ordinateurs, appelés ordinateurs à programme câblé, étaient rigides, car leur comportement était dicté par la manière dont les composants matériels étaient interconnectés. Cela rendait toute modification complexe et coûteuse, nécessitant souvent de reconfigurer physiquement les circuits pour effectuer des calculs différents. Un exemple concret est l'ENIAC, qui était utilisé pour effectuer des calculs balistiques pour l'armée américaine pendant la Seconde Guerre mondiale. L'architecture de l'ENIAC était une architecture à programme câblé, où les ingénieurs devaient reconfigurer physiquement la machine (en modifiant les connexions et les câbles) pour changer la fonction ou le calcul à effectuer. Cela limitait grandement la flexibilité de la machine, qui ne pouvait pas être facilement reprogrammée pour d'autres tâches sans intervention matérielle. L'avancée majeure qui a conduit à l'architecture de Von Neumann est venue de la reconnaissance du besoin d'un système plus flexible, où les instructions, tout comme les données, pourraient être stockées dans une mémoire centrale et traitées par le même mécanisme de traitement. Le mathématicien John von Neumann, inspiré par des idées théoriques comme la machine de Turing (proposée par Alan Turing en 1936), a formalisé cette idée dans son célèbre rapport sur l'EDVAC (Electronic Discrete Variable Automatic Computer) en 1945. Il a proposé un modèle d'ordinateur dans lequel le programme (instructions) et les données partagent la même mémoire, permettant ainsi de modifier ou de réutiliser les programmes sans reconfigurer l'ordinateur. Ce concept révolutionnaire, souvent appelé le modèle de programme stocké, a permis le développement de machines beaucoup plus flexibles, capables d'exécuter différents programmes sans nécessiter de modifications matérielles. Cela a marqué une étape clé dans l'informatique moderne, permettant la création de systèmes plus polyvalents et efficaces. Ce modèle a jeté les bases des architectures que nous utilisons aujourd'hui dans presque tous les ordinateurs, allant des ordinateurs personnels aux systèmes embarqués. 1.3 Le Modèle de Von Neumann Le modèle de Von Neumann est un modèle d'architecture de système informatique qui a posé les bases des ordinateurs modernes. Proposé par le mathématicien John von Neumann en 1945, ce modèle décrit un ordinateur en tant que machine composée de plusieurs unités interconnectées et qui peut stocker à la fois les données et les instructions dans une même mémoire. 1.3.1 Les Composants du Modèle de Von Neumann Le modèle de Von Neumann se compose de quatre éléments principaux : 1. Unité de traitement centrale (CPU) : 3 o Responsable de l'exécution des instructions. Elle se décompose en deux sous- unités : ▪ L'unité arithmétique et logique (ALU) : qui réalise les calculs et les opérations logiques. ▪ L'unité de contrôle : qui gère le flux d'instructions et orchestre l'exécution des programmes. 2. Mémoire : o C'est l'espace où sont stockées à la fois les instructions du programme et les données à traiter. Dans le modèle de Von Neumann, les programmes et les données partagent la même mémoire (mémoire unifiée), ce qui le distingue de l'architecture Harvard, où les instructions et les données sont stockées dans des mémoires distinctes. 3. Unité d'Entrée/Sortie (E/S) : o Permet à l'ordinateur d'interagir avec l'extérieur en recevant des informations (périphériques d’entrée, comme le clavier ou la souris) et en émettant des résultats (périphériques de sortie, comme l'écran ou l'imprimante). 4. Bus : o C'est un système de communication qui relie le CPU, la mémoire et les périphériques d'E/S. Il existe généralement trois types de bus : ▪ Bus de données : transporte les données entre les différentes unités. ▪ Bus d'adresse : indique l'emplacement en mémoire où les données doivent être lues ou écrites. ▪ Bus de contrôle : transporte les signaux de commande pour synchroniser les opérations. Figure 2 Schéma de l'architecture de von Neumann. 4 1.3.2 Le Cycle de Fonctionnement de Von Neumann Le modèle de Von Neumann repose sur un cycle d'exécution d'instruction simple, appelé le cycle de Fetch-Decode-Execute : 1. Fetch (récupération) : le CPU récupère une instruction dans la mémoire. 2. Decode (décodage) : l'instruction est décodée pour déterminer quelles opérations doivent être effectuées. 3. Execute (exécution) : l'instruction est exécutée par l'unité arithmétique et logique (ALU), et le résultat peut être stocké dans la mémoire ou envoyé à un périphérique d'E/S. 1.4 Le Modèle Harvard Le modèle Harvard est une architecture alternative où les instructions et les données sont stockées dans des mémoires séparées. Cela permet un accès plus rapide et simultané aux deux types d'informations, car le CPU peut lire les instructions dans une mémoire pendant qu'il accède aux données dans une autre. Cette séparation rend les systèmes basés sur l'architecture Harvard plus performants pour certaines applications spécifiques. 1.4.1 Composants du Modèle Harvard Deux Mémoires Distinctes : Une mémoire pour les instructions et une autre pour les données, ce qui permet d'accélérer les processus d'accès. Bus Séparés : Des bus distincts pour la mémoire des instructions et celle des données, permettant un accès simultané et indépendant. Figure 3 Schéma de l'Architecture Harvard Illustration montrant la séparation des mémoires et des bus pour les instructions et les données. 5 1.4.2 Exemple de Complexité du Modèle Harvard L'architecture Harvard est plus complexe à mettre en œuvre au niveau matériel, car elle nécessite la gestion de deux mémoires distinctes et de deux bus séparés. Par exemple, un système basé sur l'architecture Harvard doit disposer de circuits supplémentaires pour gérer les accès aux mémoires d'instructions et de données en parallèle. Cela augmente la taille du circuit, la consommation d'énergie, et les coûts de production. Du point de vue logiciel, la programmation de systèmes Harvard peut également être plus complexe, car le développeur doit s'assurer que les instructions et les données sont correctement gérées dans leurs mémoires respectives. Par exemple, dans les microcontrôleurs basés sur Harvard, le développeur doit souvent gérer explicitement la séparation des instructions et des données, ce qui peut rendre la programmation plus difficile, notamment lorsqu'il s'agit d'effectuer des opérations qui nécessitent une interaction fréquente entre instructions et données. 1.5 Comparaison entre Von Neumann et Harvard Aspect Architecture Von Neumann Architecture Harvard Mémoire unifiée pour les Mémoire séparée pour les Mémoire données et les instructions données et les instructions Accès séquentiel aux Accès simultané aux Accès instructions et aux données instructions et aux données Moins complexe, nécessite un Plus complexe, nécessite deux Complexité matérielle seul bus bus distincts Coût Moins coûteux Plus coûteux Optimisé pour les systèmes Grande flexibilité, idéal pour Flexibilité nécessitant des performances les systèmes polyvalents élevées et prévisibles Figure 3 : Comparaison des Architectures de Von Neumann et Harvard Tableau comparatif des deux architectures en termes de mémoire, accès, complexité matérielle, coût, et flexibilité. 1.6 Pourquoi le Modèle de Von Neumann a-t-il été largement adopté ? Le modèle de Von Neumann a été largement adopté en raison de sa simplicité de conception et de sa flexibilité. Le fait de stocker à la fois les instructions et les données dans une mémoire 6 unifiée permet de réduire la complexité matérielle et les coûts de fabrication. Cette architecture est également plus facile à programmer, car il n'y a pas besoin de gérer des mémoires distinctes pour les instructions et les données. Les ordinateurs basés sur le modèle de Von Neumann sont particulièrement adaptés aux systèmes polyvalents comme les PC, les serveurs, et les systèmes embarqués, qui nécessitent une reprogrammabilité et une grande capacité d'adaptation. En revanche, l'architecture Harvard est plus souvent utilisée dans des systèmes embarqués spécialisés ou des dispositifs nécessitant une performance accrue, comme les microcontrôleurs et les DSPs (Digital Signal Processors). 1.7 Conclusion du Chapitre 1 Le modèle de Von Neumann a marqué une étape cruciale dans l'histoire de l'informatique en proposant une architecture flexible et programmée, où les instructions et les données sont stockées ensemble. Cette approche a facilité la conception et la reprogrammation des ordinateurs, rendant possible la production d'ordinateurs plus polyvalents et accessibles. C'est pour cette raison qu'il est devenu la base des architectures de nombreux systèmes modernes, notamment pour les ordinateurs personnels et les serveurs. Cependant, l'architecture Harvard trouve son utilité dans des contextes où des performances élevées et une séparation stricte des instructions et des données sont nécessaires, comme dans les systèmes embarqués et les microcontrôleurs. Bien que plus complexe et coûteuse, cette architecture permet un traitement plus rapide grâce à l'accès simultané aux instructions et aux données. Ainsi, chaque architecture a ses avantages : le modèle de Von Neumann est privilégié pour sa simplicité et sa flexibilité, tandis que l'architecture Harvard est utilisée dans des cas spécifiques nécessitant une optimisation des performances. Ces deux modèles continuent d'influencer la conception des systèmes informatiques en fonction des besoins particuliers des utilisateurs. 1.8 Ce qui suit dans le cours Le prochain chapitre portera sur l'implémentation pratique de l'architecture de Von Neumann. Nous explorerons les différentes étapes et les considérations nécessaires pour concevoir un système informatique basé sur ce modèle. En particulier, nous nous concentrerons sur le CPU, qui est le cœur du traitement dans cette architecture. Nous étudierons comment les différents composants du CPU, tels que l'unité arithmétique et logique (ALU) et l'unité de contrôle, sont implémentés pour permettre l'exécution des instructions. Cette partie mettra également l'accent sur le fonctionnement interne des registres et des bus, et sur la façon dont le CPU interagit avec la mémoire pour récupérer et traiter les instructions. 7 Chapitre 2 : Conception et Implémentation du CPU dans l'Architecture de Von Neumann 2.1 Introduction Le processeur, ou CPU (Central Processing Unit), est le cœur de l'architecture de Von Neumann. C'est lui qui exécute les instructions des programmes et coordonne les différentes opérations au sein de l'ordinateur. Ce chapitre se concentre sur la conception et l'implémentation du CPU, en détaillant ses composants internes et leurs rôles respectifs dans le fonctionnement général de l'ordinateur. 2.2 Les Composants Principaux du CPU Le CPU est constitué de plusieurs composants essentiels qui travaillent ensemble pour exécuter des instructions. Les composants principaux du CPU incluent : 2.2.1 L'Unité Arithmétique et Logique (ALU) L'ALU est la partie du processeur qui effectue les opérations arithmétiques (addition, soustraction, etc.) et logiques (comparaison, opérations booléennes, etc.). Elle joue un rôle crucial dans l'exécution des instructions en manipulant les données selon les opérations requises par les programmes. Opérations Arithmétiques : L'ALU réalise des opérations comme l'addition, la soustraction, la multiplication et la division. Opérations Logiques : Elle peut effectuer des comparaisons entre des valeurs (par exemple, égalité, supérieur à) et des opérations booléennes (ET, OU, NON). 2.2.2 L'Unité de Contrôle L'unité de contrôle gère l'exécution des instructions en coordonnant les différentes étapes du cycle d'instruction. Elle décode les instructions récupérées en mémoire et génère les signaux de contrôle nécessaires pour activer les différents composants du CPU et orchestrer les opérations. Décodage des Instructions : L'unité de contrôle interprète le code binaire des instructions et décide quelles actions doivent être entreprises. Gestion du Flux de Données : Elle régule le transfert des données entre la mémoire, l'ALU et les registres. 2.2.3 Les Registres du CPU 8 Les registres sont des petites unités de stockage à haute vitesse situées à l'intérieur du CPU. Ils jouent un rôle crucial en stockant temporairement les données et les instructions nécessaires à l'exécution des programmes. Registre d'Instructions (IR) : Stocke l'instruction en cours d'exécution. Compteur de Programme (PC) : Contient l'adresse de la prochaine instruction à exécuter. Registres de Données : Stockent les données utilisées par l'ALU lors des calculs. 2.3 Les Bus de Communication Les bus sont des canaux de communication qui permettent l'échange de données, d'adresses et de signaux de contrôle entre les différents composants du système, tels que le CPU, la mémoire et les périphériques d'entrée/sortie. Dans l'architecture de Von Neumann, les bus jouent un rôle crucial en assurant la transmission efficace des informations nécessaires pour l'exécution des instructions. Ils permettent de connecter et de synchroniser les différents éléments du système, et leur performance a un impact direct sur l'efficacité globale de l'ordinateur. 2.3.1 Types de Bus - Bus de Données : o Le bus de données est responsable du transfert des données entre les composants du CPU, la mémoire, et les périphériques. La largeur du bus de données (par exemple, 8 bits, 16 bits, 32 bits, ou 64 bits) détermine la quantité de données qui peuvent être transmises simultanément. Une largeur de bus plus grande permet un transfert plus rapide des données, ce qui améliore la performance globale du système. Par exemple, un bus de données de 64 bits permet de transférer 64 bits de données en un seul cycle, ce qui est particulièrement avantageux pour les applications nécessitant un traitement rapide des données, comme les jeux vidéo ou les simulations scientifiques. - Bus d'Adresse : o Le bus d'adresse est utilisé pour indiquer l'emplacement en mémoire où le CPU souhaite lire ou écrire des données. La largeur du bus d'adresse détermine la quantité de mémoire qui peut être adressée directement par le CPU. Par exemple, un bus d'adresse de 32 bits permet d'adresser jusqu'à 4 Go de mémoire (2^32 adresses). Le bus d'adresse joue un rôle essentiel dans la gestion de la mémoire et détermine la capacité de l'ordinateur à accéder à de grandes quantités de mémoire, ce qui est crucial pour les applications modernes qui manipulent de vastes ensembles de données. - Bus de Contrôle : o Le bus de contrôle transporte les signaux nécessaires pour coordonner et gérer les opérations du système. Ces signaux incluent les commandes de lecture et d'écriture, les signaux d'interruption, et les signaux de synchronisation. Le bus de contrôle est crucial pour assurer que toutes les opérations du système se déroulent correctement et dans l'ordre voulu. Par exemple, lorsque le CPU souhaite lire des 9 données en mémoire, il envoie un signal de lecture via le bus de contrôle, indiquant à la mémoire de transmettre les données spécifiées par le bus d'adresse. 2.3.3 Caractéristiques de Performance des Bus Bande Passante : La bande passante d'un bus correspond à la quantité de données qu'il peut transmettre par unité de temps, généralement exprimée en Mo/s (mégaoctets par seconde). Une bande passante plus élevée signifie que le bus peut transférer plus de données, ce qui est crucial pour les systèmes nécessitant des transferts de données massifs. Latence : La latence est le délai entre la demande de transfert de données et le début du transfert. Une faible latence est souhaitable pour assurer une communication rapide entre le CPU, la mémoire, et les périphériques, notamment pour les applications en temps réel. Arbitrage des Bus : Lorsque plusieurs composants veulent accéder au bus en même temps, un mécanisme d'arbitrage est nécessaire pour déterminer quel composant obtient l'accès en premier. Des méthodes telles que l'arbitrage par priorité ou l'arbitrage en tourniquet (round-robin) peuvent être utilisées pour gérer ces conflits. En conclusion, les bus de communication jouent un rôle fondamental dans le fonctionnement de l'architecture de Von Neumann. Leur conception et leur optimisation sont essentielles pour garantir une transmission efficace des données et des instructions entre les différents composants du système, influençant directement les performances globales de l'ordinateur. 2.4 Cycle d'Exécution du CPU Le cycle d'exécution du CPU, appelé cycle de Fetch-Decode-Execute, est le processus par lequel le processeur récupère, décode, et exécute les instructions d'un programme. Ce cycle est la base du fonctionnement du CPU et se répète continuellement pour traiter chaque instruction d'un programme. Le cycle comprend plusieurs phases critiques qui permettent de s'assurer que chaque instruction est exécutée correctement et dans l'ordre voulu. 2.4.1 Les Étapes du Cycle d'Exécution 1. Fetch (Récupération) : o Le CPU commence par récupérer l'instruction située à l'adresse indiquée par le Compteur de Programme (PC). Le PC contient l'adresse de la prochaine instruction à exécuter. Cette adresse est envoyée à la mémoire via le bus d'adresse, et l'instruction correspondante est renvoyée au CPU via le bus de données. o Pendant cette phase, le PC est généralement incrémenté pour pointer vers l'instruction suivante, prête à être récupérée au cycle suivant. Cette phase est cruciale car elle permet de s'assurer que le CPU sait toujours quelle est la prochaine instruction à traiter. 2. Decode (Décodage) : o Une fois l'instruction récupérée, elle est envoyée à l'unité de contrôle pour être décodée. L'unité de contrôle interprète l'instruction binaire et identifie les 10 opérations à effectuer, les opérandes concernés, ainsi que les registres à utiliser. Pour déterminer le type d'opération, l'unité de contrôle décode des portions spécifiques du code binaire, qui indiquent s'il s'agit d'une opération arithmétique, logique, ou de contrôle. Par exemple, une instruction d'addition sera identifiée par un code opérationnel spécifique. 3. Execute (Exécution) : o Pendant la phase d'exécution, l'ALU (Unité Arithmétique et Logique) ou un autre composant approprié du CPU exécute l'instruction décodée. Les opérations peuvent inclure des calculs arithmétiques (comme l'addition ou la soustraction), des opérations logiques (comme ET, OU, NON), ou des transferts de données entre la mémoire et les registres. o Les résultats de l'opération sont ensuite soit stockés dans un registre pour un usage futur, soit écrits dans la mémoire principale. Si l'instruction est une instruction de contrôle, comme un saut conditionnel, le Compteur de Programme (PC) peut être mis à jour pour pointer vers une nouvelle adresse d'instruction, modifiant ainsi le flux d'exécution du programme. 2.6 Paramètres d'Optimisation de l'Architecture de Von Neumann Voici des exemples concrets de contraintes qui influencent les paramètres d'optimisation pour une implémentation de l'architecture de Von Neumann : - Contraintes de Performances Vitesse de Traitement : Sur des plateformes comme les serveurs de calcul ou les supercalculateurs, la vitesse de traitement est une priorité. Dans ce cas, des optimisations telles que l'augmentation de la fréquence d'horloge, l'ajout de pipelines plus profonds, et la mise en œuvre de mémoire cache à plusieurs niveaux sont cruciales. Latence et Débit : Pour des systèmes de jeu ou des applications graphiques intensives, la réduction de la latence (le délai pour une instruction) et l'augmentation du débit (nombre d'instructions par seconde) sont essentielles. Cela peut être obtenu par l'ajout d'unités d'exécution parallèles et une meilleure gestion des instructions (multithreading, prédiction de branches, etc.). - Contraintes de Consommation d'Énergie Dispositifs Mobiles et Embarqués : Dans des appareils mobiles (comme les smartphones) ou des systèmes embarqués (par exemple, les systèmes de contrôle automobile), l'optimisation de la consommation d'énergie est essentielle. Pour cela, des techniques comme la réduction de la fréquence d'horloge, le mode "veille" des composants inactifs, et une architecture de jeu de données (réduisant la consommation énergétique des instructions) sont utilisées. Autonomie de la Batterie : Les appareils portables doivent maximiser l'autonomie de la batterie, nécessitant des optimisations telles que l'utilisation de la gestion 11 dynamique de l'alimentation (DVFS) ou la réduction de la taille et de la complexité des registres. - Contraintes de Coût Production à Faible Coût : Pour des produits de masse comme des électroménagers intelligents, le coût est un facteur clé. Dans ce cas, la simplification de l'architecture du CPU comme la réduction du nombre de registres, la limitation du cache, et l'utilisation de bus plus étroits peuvent réduire le coût de production. Coût de Développement : Les contraintes budgétaires peuvent influencer le choix des technologies et des optimisations possibles. Par exemple, des architectures simples avec moins de complexité en termes de pipeline et de cache seront moins chères à développer. - Contraintes Spécifiques à la Plateforme Environnement Temporel Réel : Dans des systèmes critiques en temps réel, comme les systèmes de contrôle aéronautique, les délais de traitement doivent être prédictibles et constants. Cela impose des optimisations visant à minimiser les interruptions et à garantir des temps de latence fixes. Capacités Physiques : Dans des environnements contraints en taille, comme les objets connectés (IoT), la surface du silicium disponible est limitée, ce qui impose des choix réduisant la complexité matérielle, tels que des unités de contrôle simplifiées ou des bus limités en largeur. Robustesse et Tolérance aux Pannes : Pour les satellites ou les systèmes spatiaux, la robustesse est essentielle, nécessitant des circuits redondants et une architecture moins dense pour limiter la vulnérabilité aux radiations. - Optimisations du Cycle d'Exécution Pipelining : Une des techniques majeures d'optimisation du cycle d'exécution est le pipelining. Le pipelining permet de diviser le cycle Fetch-Decode-Execute en plusieurs sous-étapes qui peuvent être traitées simultanément pour des instructions différentes. Par exemple, pendant qu'une instruction est en phase de décodage, la suivante peut être en phase de récupération, et une troisième en phase d'exécution. Cela augmente considérablement le débit d'instructions et améliore les performances du processeur. Étape Instruction 1 Instruction 2 Instruction 3 Cycle 1 Fetch Cycle 2 Decode Fetch Cycle 3 Execute Decode Fetch Cycle 4 Execute Decode Cycle 5 Execute Prévision de Branchements (Branch Prediction) : Les instructions de branchement conditionnel peuvent introduire des délais dans le cycle d'exécution, car le CPU doit 12 souvent attendre pour savoir quelle instruction exécuter ensuite. Les processeurs modernes utilisent des mécanismes de prévision de branchements pour tenter de deviner le résultat d'une condition et commencer à exécuter les instructions suivantes avant que la condition ne soit résolue. Exécution Superscalaire : Certains processeurs sont capables d'exécuter plusieurs instructions en parallèle, grâce à une architecture superscalaire. Cela permet d'avoir plusieurs unités d'exécution (comme plusieurs ALU) travaillant simultanément sur différentes instructions, améliorant ainsi la capacité de traitement du CPU. Ces contraintes influencent directement les décisions d'optimisation dans la conception de l'architecture de Von Neumann, permettant de créer des systèmes adaptés à chaque application et chaque environnement d'utilisation. L'objectif est d'équilibrer les compromis nécessaires pour répondre au mieux aux besoins de la plateforme visée. Cela peut inclure des ajustements pour améliorer les performances, réduire la consommation d'énergie, minimiser les coûts de fabrication, ou encore garantir la compatibilité avec des logiciels existants. Chaque optimisation a un impact sur la conception matérielle, et il est crucial de s'assurer que le design permet une exécution efficace des programmes. Par exemple, des compromis peuvent être faits sur la largeur du bus de données, la taille des registres, ou la complexité de l'unité de contrôle pour atteindre les objectifs spécifiques du système. De même, la fréquence d'horloge doit être choisie avec soin pour assurer un bon équilibre entre performance et consommation d'énergie. Ces aspects matériels sont intrinsèquement liés au jeu d'instructions (ISA), qui sera introduit dans la prochaine section. La conception de l'ISA est une étape essentielle qui précède la conception matérielle, car elle définit les instructions que le matériel devra être capable d'exécuter, orientant ainsi la conception de chaque composant du CPU. L'ISA est l'interface clé entre le matériel et le logiciel, et son design joue un rôle déterminant dans la manière dont le matériel peut exécuter des tâches spécifiques de manière optimale. Pour les développeurs, l'ISA est cruciale car elle définit l'ensemble des instructions disponibles pour écrire des programmes. Un ISA bien conçu simplifie la programmation, réduit la complexité du code, et permet une meilleure optimisation du logiciel pour tirer parti des capacités du matériel. Cela signifie que les développeurs peuvent écrire du code plus efficace, performant, et portable sur différentes générations de processeurs partageant le même ISA. Ainsi, la conception de l'ISA doit également refléter ces compromis afin de garantir que le matériel et le logiciel fonctionnent ensemble de manière harmonieuse et efficace. 2.7 Conception et Histoire du Jeu d'Instructions (ISA) dans l'Architecture de Von Neumann 2.7.1 Introduction au Jeu d'Instructions (ISA) Le jeu d'instructions, ou Instruction Set Architecture (ISA), est un élément central de la conception des processeurs dans l'architecture de Von Neumann. L'ISA définit l'ensemble des 13 instructions que le processeur peut exécuter et décrit l'interface entre le matériel (hardware) et le logiciel (software). En d'autres termes, l'ISA est le pont qui permet aux développeurs de logiciels de contrôler le matériel, spécifiant quelles instructions peuvent être exécutées, comment elles sont codées, et comment elles interagissent avec les ressources du CPU telles que les registres et la mémoire. 2.7.2 Pourquoi Conçoit-on une ISA ? La conception d'une ISA est une étape critique du développement d'un processeur, car elle détermine la flexibilité, la performance, la complexité, et la consommation d'énergie du système. Lors de la conception d'une ISA, les ingénieurs doivent prendre en compte plusieurs aspects : Compatibilité Logicielle : Une bonne ISA assure une compatibilité sur plusieurs générations de matériel. Par exemple, les anciennes versions des processeurs Intel x86 peuvent exécuter le même code que les nouvelles versions, ce qui permet de préserver l'investissement logiciel. Optimisation des Performances : Une ISA bien conçue doit permettre au CPU d'exécuter les instructions de manière efficace, en minimisant les cycles d'horloge nécessaires pour chaque opération. Consommation d'Énergie : La simplicité des instructions peut permettre une meilleure gestion de l'énergie, ce qui est essentiel pour les systèmes embarqués et les appareils mobiles. Facilité de Programmation : Une ISA doit être suffisamment intuitive pour faciliter la tâche des programmeurs. La simplification des instructions complexes en instructions de base permet de rendre la programmation plus directe et le débogage plus simple. 2.7.3 Comment Conçoit-on une ISA ? La conception d'une ISA passe par plusieurs étapes, impliquant des choix techniques et des compromis en fonction des objectifs de la plateforme à développer : 1. Définir les Types d'Instructions : Il est essentiel de décider quelles instructions doivent être incluses, comme les opérations arithmétiques, logiques, de gestion de la mémoire, et de contrôle de flux. 2. Spécifier le Format des Instructions : Les instructions doivent être encodées en binaire, et la taille des instructions doit être déterminée. Par exemple, le format peut être fixe (comme dans les architectures RISC) ou variable (comme dans les architectures CISC). 3. Déterminer les Modes d'Adressage : Les modes d'adressage déterminent comment les opérandes sont spécifiés. Cela inclut l'adressage direct, indirect, immédiat, etc., et influence la manière dont la mémoire et les registres sont accédés. 4. Équilibrer Complexité et Efficacité : Les instructions complexes peuvent réduire le nombre total d'instructions nécessaires pour effectuer une tâche, mais elles nécessitent plus de cycles et un matériel plus complexe pour l'implémentation. Les instructions simples, en revanche, peuvent être exécutées plus rapidement mais peuvent nécessiter plus de lignes de code. 14 2.7.4 Les Différentes Architectures ISA Disponibles et Leur Histoire Il existe plusieurs types d'architectures ISA, chacune développée pour répondre à des besoins spécifiques. Voici un aperçu des principales architectures et leur évolution historique : - CISC (Complex Instruction Set Computing) Développement : L'architecture CISC a été développée dans les années 1970-1980, lorsque la mémoire était coûteuse et limitée. L'idée était de fournir un grand nombre d'instructions complexes qui pouvaient réaliser des opérations en une seule instruction. Cela permettait de réduire la taille du code source. Exemple : L'architecture x86 d'Intel est un exemple classique de CISC. Elle propose des instructions complexes qui peuvent être utilisées pour effectuer des tâches très sophistiquées avec peu d'instructions. Avantage : Réduction de la taille du code, et ainsi moins de mémoire nécessaire pour stocker le programme. Inconvénient : La complexité matérielle est plus grande, ce qui augmente la consommation d'énergie et ralentit parfois l'exécution des instructions. - RISC (Reduced Instruction Set Computing) Développement : L'architecture RISC a émergé dans les années 1980 comme une réponse à la complexité des CISC. Les recherches ont montré que la majorité des instructions complexes n'étaient pas souvent utilisées, et que simplifier le jeu d'instructions pouvait améliorer la vitesse d'exécution. Exemple : Les processeurs ARM sont des exemples populaires d'architectures RISC. Cette architecture est largement utilisée dans les appareils mobiles en raison de son efficacité énergétique. Avantage : Simplicité du matériel, permettant une exécution rapide des instructions et une faible consommation d'énergie. Inconvénient : Le code source peut être plus long car les tâches complexes nécessitent plus d'instructions simples. - VLIW (Very Long Instruction Word) Développement : L'architecture VLIW est apparue pour permettre l'exécution parallèle des instructions. Chaque mot d'instruction très long peut contenir plusieurs opérations qui seront exécutées en parallèle, augmentant ainsi l'efficacité des processeurs. Exemple : Les processeurs Itanium d'Intel utilisent une architecture VLIW. Avantage : Permet un parallélisme élevé, augmentant ainsi les performances. Inconvénient : La complexité logicielle est plus élevée, car le compilateur doit être capable de planifier correctement les instructions pour garantir un parallélisme efficace. - ISA Modernes et Hybrides 15 x86-64 : C'est une extension 64 bits de l'architecture x86, combinant des éléments de CISC avec certaines caractéristiques RISC pour améliorer les performances tout en maintenant la compatibilité avec le logiciel existant. RISC-V : Une ISA moderne, libre et ouverte, conçue pour être simple et extensible. RISC-V gagne en popularité dans les environnements académiques et industriels en raison de sa flexibilité et de son ouverture. 2.8 Conclusion Ce chapitre a détaillé la conception et l'implémentation du CPU dans l'architecture de Von Neumann. Nous avons exploré les différents composants du CPU, notamment l'ALU, l'unité de contrôle, les registres et les bus, et comment ils interagissent pour exécuter les instructions d'un programme. Comprendre ces concepts est essentiel pour appréhender le fonctionnement interne d'un ordinateur et la manière dont les programmes sont exécutés au niveau matériel. 16 Chapitre 3 : L'Architecture du Micro- processeur Intel 8086 Histoire : L'Intel 8085 et ses Limites L'Intel 8085 est un microprocesseur 8 bits emblématique des années 1970, souvent utilisé pour des systèmes simples et pédagogiques. Il repose sur une architecture CISC (Complex Instruction Set Computer) et suit le modèle de Von Neumann. Cependant, bien que performant pour son époque, il présente des limitations significatives qui ont conduit à l'introduction de l'Intel 8086. Caractéristiques principales de l'Intel 8085 : Bus d'adresse de 16 bits : Permet d’adresser jusqu’à 64 Ko de mémoire (216 = 65 536 adresses). Bus de données de 8 bits : Les données sont traitées en morceaux de 8 bits. Modèle de mémoire unique (flat memory) : La mémoire de programme et les données partagent le même espace d’adressage. Registres simples : Inclut des registres comme A, B, C, D, E, H, et L, adaptés à des tâches basiques. Limitations : o Taille de mémoire limitée à 64 Ko. o Pas de mécanisme pour séparer efficacement le code, les données et la pile. o Adapté uniquement à des applications simples et monolithiques. Exemple de problème : Lorsqu’un programme devient plus complexe et nécessite un espace mémoire supérieur à 64 Ko (ou une meilleure séparation entre code et données), l’architecture 8085 atteint rapidement ses limites. L'Évolution : L'Intel 8086 et l'Introduction de la Segmentation L’Intel 8086 est un microprocesseur 16 bits introduit en 1978, qui marque une avancée significative par rapport à son prédécesseur, l’Intel 8085. Conçu pour répondre aux limites des microprocesseurs 8 bits, le 8086 inaugure une architecture puissante et flexible, adaptée à des applications plus complexes et à des besoins mémoire plus importants. Ce chapitre explore les caractéristiques fondamentales du 8086, ses registres, ses mécanismes d’adressage, et son modèle de mémoire segmentée. 17 3.1. Présentation Générale de l'Intel 8086 Caractéristiques principales : 1. Processeur 16 bits : o Le 8086 est capable de traiter des données sur 16 bits, doublant ainsi la largeur du bus de données par rapport à l'Intel 8085. o Cela améliore les performances et permet de traiter des instructions plus complexes. 2. Bus d'adresse de 20 bits : o Permet d’adresser jusqu’à 1 Mo de mémoire, une amélioration majeure par rapport à la limite de 64 Ko de l’Intel 8085. 3. Architecture segmentée : o Introduit un modèle mémoire segmenté pour surmonter les limites des registres 16 bits, tout en permettant une meilleure organisation du code et des données. 4. Jeu d'instructions étendu : o Inclut des instructions plus avancées pour les calculs, les transferts de données, et le contrôle de programme. 5. Modes de fonctionnement : o Mode minimum : Conçu pour une utilisation autonome. o Mode maximum : Adapté aux environnements multiprocesseurs. 3.2. Les Registres du 8086 Le microprocesseur 8086 dispose de 14 registres principaux, organisés en trois catégories : les registres généraux, les registres de segment et les registres spécifiques. 3.2.1. Registres Généraux Ces registres sont polyvalents et utilisés pour les calculs, les transferts de données et les opérations générales. Registre Taille Rôle principal AX 16 bits Accumulateur pour les opérations arithmétiques et logiques. BX 16 bits Utilisé pour les calculs d’adressage (base). CX 16 bits Compteur pour les boucles et les instructions répétitives. DX 16 bits Utilisé pour les opérations d’entrée/sortie et les calculs étendus. - Structure des registres généraux : Chaque registre général de 16 bits (AX, BX, CX, DX) est divisé en deux parties de 8 bits, permettant un accès indépendant à la partie haute ou basse : 18 AX : Composé de AH (High, bits 8-15) et AL (Low, bits 0-7). BX : Composé de BH (High, bits 8-15) et BL (Low, bits 0-7). CX : Composé de CH (High, bits 8-15) et CL (Low, bits 0-7). DX : Composé de DH (High, bits 8-15) et DL (Low, bits 0-7). Cela permet d'adresser séparément les 8 bits supérieurs (High) ou inférieurs (Low) du registre complet. - Avantages de l'utilisation en mode 8 bits : 1. Optimisation des ressources : o Lorsqu'une opération ne nécessite que 8 bits (par exemple, manipuler un caractère ASCII ou effectuer des calculs simples), utiliser les parties AH, AL, etc., permet d'économiser les cycles et la mémoire. 2. Flexibilité : o La division en 8 bits offre plus de registres accessibles, augmentant ainsi les possibilités pour les programmeurs, en particulier pour les calculs ou le stockage temporaire. 3. Compatibilité ascendante : o Cette structure facilite l'exécution de programmes écrits pour des microprocesseurs 8 bits antérieurs (comme l'Intel 8085), tout en exploitant la puissance du 8086. 3.2.2. Registres de Segment Les registres de segment sont spécifiques au modèle mémoire segmenté. Ils permettent d’accéder aux différentes parties de la mémoire. Registre Taille Rôle CS 16 bits Code Segment : Contient l’adresse de base des instructions. DS 16 bits Data Segment : Contient l’adresse de base des données. SS 16 bits Stack Segment : Gère la pile pour les appels de sous-programmes et interruptions. ES 16 bits Extra Segment : Utilisé pour des données supplémentaires. 3.2.3. Registres Pointeurs et Index Ces registres sont utilisés pour adresser des données et pour gérer la pile. Registre Taille Rôle SP 16 bits Stack Pointer : Pointeur de pile. BP 16 bits Base Pointer : Utilisé pour accéder à la pile ou aux données dans le segment SS. 19 SI 16 bits Source Index : Utilisé pour les opérations sur les chaînes de caractères. DI 16 bits Destination Index : Utilisé pour les opérations sur les chaînes de caractères. 3.2.4. Registre d’Instruction et Registre d'État IP (Instruction Pointer) : Contient l’adresse de l’instruction suivante à exécuter dans le segment CS. Registre d’état (Flags) : Contient des indicateurs qui reflètent le résultat des opérations et influencent le comportement du programme. Nom Rôle ZF Zero Flag : Indique si le résultat est nul. CF Carry Flag : Indique une retenue ou emprunt. SF Sign Flag : Indique un résultat négatif. OF Overflow Flag : Signale un dépassement. 3.3. Adressage et Accès Mémoire dans le 8086 Le 8086 introduit plusieurs modes d’adressage pour accéder à la mémoire et aux données. 3.3.1. Adressage Segmenté L’accès à la mémoire se fait par combinaison d’un segment et d’un offset : Adresse physique hex = (Segment hex × 10 hex) + Offset hex Exemple : o CS = 2000h, IP = 10h o Adresse physique = (2000h × 10h) + 10h = 20010h. 3.3.2. Modes d’Adressage Mode Description Direct L’adresse est spécifiée directement. Indirect L’adresse est contenue dans un registre. Indexé Combinaison d’un registre de base et d’un registre d’index. Avec deplacement Utilise un déplacement relatif. 3.4. Pourquoi le Modèle Segmenté ? Le modèle segmenté du 8086 a été introduit pour dépasser les limitations de l’Intel 8085, tout en : 20 1. Étendant l’espace mémoire : Jusqu’à 1 Mo. 2. Favorisant la modularité : Les programmes peuvent organiser leur code, données et pile dans des segments indépendants. 3. Améliorant la flexibilité : Les segments peuvent être déplacés ou redimensionnés sans affecter le programme. Cependant, cette approche introduit également des défis, comme la complexité accrue pour les programmeurs et la gestion du segment:offset. 3.4.1. Segments par Défaut pour Chaque Registre - Registres Généraux Les registres généraux (AX, BX, CX, DX) sont polyvalents et utilisés pour les opérations arithmétiques, logiques, ou pour adresser la mémoire. Lorsque ces registres sont impliqués dans un adressage indirect ou indexé, le segment par défaut est DS (Data Segment). - Registres de Pointeur et d’Index Les registres de pointeur et d’index sont essentiels pour accéder à des tableaux, des chaînes de caractères ou pour gérer la pile. Registre Rôle Segment par défaut BX Base Register : Souvent utilisé pour des adresses DS (Data indirectes. Segment) BP Base Pointer : Utilisé pour accéder aux variables SS (Stack locales sur la pile. Segment) SI (Source Index) Index source : Accède aux données dans des tableaux DS (Data ou chaînes. Segment) DI (Destination Index) Index destination : Utilisé pour écrire des données dans DS (Data des tableaux ou chaînes. Segment) SP (Stack Pointer) Pointeur de pile : Spécifie l’adresse actuelle de la pile. SS (Stack Segment) - Registre d’instruction Registre Rôle Segment par défaut IP (Instruction Pointer) Pointeur d'instruction : Indique l’adresse de CS (Code Segment) l’instruction suivante à exécuter. 21 L’association entre CS (Code Segment) et IP (Instruction Pointer) est essentielle pour exécuter le programme. L’Intel 8086, comme beaucoup d’architectures x86, utilise une représentation Little Endian pour stocker les données en mémoire. Ce choix affecte directement la manière dont les bits et octets sont disposés lorsqu’un nombre multi-octet est enregistré ou lu depuis la mémoire. Rappel : Qu’est-ce que le Little Endian ? Le Little Endian est un ordre de stockage où le poids faible (Least Significant Byte, LSB) d’un nombre est placé à l’adresse mémoire la plus basse, et le poids fort (Most Significant Byte, MSB) est placé à l’adresse mémoire la plus haute. Exemple : Un nombre 16 bits, tel que 1234h, sera stocké en mémoire 1000h comme suit : Adresse 1000h : Octet de poids faible (34h). Adresse 1001h : Octet de poids fort (12h). 3.5. Résumé L'Intel 8086 représente une avancée majeure en termes de puissance et de flexibilité par rapport à l’Intel 8085 : Une architecture segmentée pour étendre la mémoire et structurer les programmes. Des registres spécialisés qui facilitent le traitement de données et l’accès mémoire. Un jeu d’instructions riche et varié pour répondre aux besoins des systèmes plus complexes. Ce processeur a jeté les bases des architectures modernes tout en restant compatible avec les concepts de base des microprocesseurs 8 bits. 22 Chapitre 4 : Assembleur dans l'Intel 8086 Introduction L'Intel 8086 est une architecture CISC (Complex Instruction Set Computer) qui offre un jeu d'instructions varié, permettant une interaction puissante et flexible avec le matériel et les données. Ce chapitre explique de manière exhaustive les principales opérations de son ISA (Instruction Set Architecture), en détaillant chaque catégorie d'instructions, y compris les contrôles de programme, les sauts, et les boucles. 4.1. Organisation Générale des Instructions Les instructions du 8086 sont divisées en catégories fonctionnelles : 1. Transfert de données : Déplacement de données entre registres, mémoire et E/S. 2. Arithmétiques : Opérations mathématiques sur des registres et données mémoire. 3. Logiques et de manipulation de bits : Opérations logiques et de gestion des bits. 4. Contrôle de programme : Instructions de sauts, boucles, et appels. 5. Instructions spéciales : Contrôle des interruptions, des drapeaux et du processeur. Transfert de données : Déplacement de données entre registres, mémoire et E/S MOV (Déplacer) : Copie de données entre registres, mémoire et valeurs immédiates. Registre à registre : Copie la valeur du registre source dans le registre destination. MOV AX, BX ; AX = BX Registre à mémoire : Copie la valeur du registre source dans une adresse mémoire. MOV [1000h], AX ; La valeur de AX est copiée à l'adresse mémoire 1000h Mémoire à registre : Copie la valeur à partir d'une adresse mémoire dans un registre. MOV AX, [1000h] ; AX reçoit la valeur stockée à l'adresse 1000h 23 Registre à immédiat : Copie une valeur immédiate dans un registre. MOV AX, 5 ; AX = 5 XCHG (Échanger) : Échange les valeurs entre deux opérandes. Registre à registre : Échange les valeurs de deux registres. XCHG AX, BX ; AX et BX échangent leurs valeurs Registre à mémoire : Échange la valeur entre un registre et une valeur en mémoire. XCHG AX, [1000h] ; AX échange sa valeur avec celle à l'adresse mémoire 1000h Mémoire à registre : Échange la valeur entre une valeur en mémoire et un registre. XCHG [1000h], AX ; La valeur à l'adresse 1000h est échangée avec la valeur d'AX LEA (Charger l'adresse effective) : Charge l'adresse effective d'un opérande dans un registre. LEA AX, [BX+SI] OFFSET (Calculer l'offset) : Calcule l'offset d'un label ou d'une variable mémoire. MOV AX, OFFSET myVar Arithmétiques : Opérations mathématiques sur des registres et données mémoire ADD (Addition) : Additionne l'opérande source avec l'opérande destination et stocke le résultat dans l'opérande destination. Registre à registre : Ajoute la valeur d'un registre source à un autre registre. ADD AX, BX ; AX = AX + BX Registre à mémoire : Ajoute la valeur d'un registre à une valeur en mémoire. ADD AX, [1000h] ; AX = AX + valeur à l'adresse 1000h Mémoire à registre : Ajoute la valeur en mémoire au contenu du registre. ADD [1000h], AX ; La valeur en mémoire à 1000h est ajoutée à AX 24 Registre à immédiat : Ajoute une valeur immédiate à un registre. ADD AX, 5 ; AX = AX + 5 SUB (Soustraction) : Soustrait l'opérande source de l'opérande destination. Registre à registre : Soustrait un registre d'un autre. SUB AX, BX ; AX = AX – BX Registre à mémoire : Soustrait la valeur en mémoire d'un registre. SUB AX, [1000h] ; AX = AX - valeur à l'adresse 1000h Mémoire à registre : Soustrait un registre de la valeur en mémoire. SUB [1000h], AX ; La valeur à l'adresse 1000h est soustraite par AX Registre à immédiat : Soustrait une valeur immédiate d'un registre. SUB AX, 3 ; AX = AX - 3 MUL (Multiplication) : Multiplie l'accumulateur par un opérande source. Multiplication 8 bits (AL est multiplié par un registre de 8 bits, résultat dans AX) : MOV AL, 5 ; AL = 5 MOV BL, 2 ; BL = 2 MUL BL ; AX = AL * BL = 10 (AX = 000Ah) Multiplication 16 bits (AX est multiplié par un registre de 16 bits, résultat dans DX (Partie supérieur) : AX(Partie Inferieur)) : MOV AX, 5 ; AX = 5 MOV BX, 4 ; BX = 4 MUL BX ; DX:AX = AX * BX = 20 (DX = 0000h, AX = 0014h) DIV (Division) : Divise l'accumulateur par un opérande source. Division 8 bits (Divise AX par un registre de 8 bits, quotient dans AL et reste dans AH) : 25 MOV AX, 10 ; AX = 10 MOV BL, 2 ; BL = 2 DIV BL ; AL = 5 (quotient), AH = 0 (reste) Division 16 bits (Divise DX:AX par un registre de 16 bits, quotient dans AX et reste dans DX) : MOV AX, 10 ; AX = 10 MOV DX, 0 MOV BX, 4 ; BX = 4 DIV BX ; AX = 2 (quotient), DX = 2 (reste) SHR (Décalage à droite) L'instruction SHR effectue un décalage des bits d'un opérande vers la droite. Le bit de poids faible est déplacé dans le drapeau de retenue (Carry Flag), et le bit de poids fort est mis à 0. L’utilisation d’un registre autre que CL comme deuxième opérande est interdit. Mémoire, immédiat : Décale la valeur stockée à une adresse mémoire d'un nombre spécifié de positions. MOV AX, 10 ; AX = 10 (bin : 0000000000001010) SHR [1000h], 1 ; Décale la valeur à l'adresse 1000h de 1 bit vers la droite REG, immédiat : Décale un registre d'un nombre spécifié de positions. MOV AX, 10 ; AX = 10 (bin : 0000000000001010) SHR AX, 1 ; Décale AX de 1 bit vers la droite. AX devient 5 (bin : 0000000000000101) Mémoire, CL : Décale la valeur stockée à une adresse mémoire d'un nombre de positions spécifié par le registre CL (8 bits). MOV CL, 2 ; CL = 2 MOV AX, 16 ; AX = 16 (bin : 0000000000010000) SHR [1000h], CL ; Décale la valeur à l'adresse 1000h de 2 bits vers la droite REG, CL : Décale un registre d'un nombre de positions spécifié par le registre CL. MOV CL, 3 ; CL = 3 MOV AX, 16 ; AX = 16 (bin : 0000000000010000) SHR AX, CL ; Décale AX de 3 bits vers la droite. AX devient 2 (bin : 0000000000000010) SHL (Décalage à gauche) 26 L'instruction SHL effectue un décalage des bits d'un opérande vers la gauche. Le bit de poids fort est déplacé dans le drapeau de retenue (Carry Flag), et le bit de poids faible est mis à 0. L’utilisation d’un registre autre que CL comme deuxième opérande est interdit. Mémoire, immédiat : Décale la valeur stockée à une adresse mémoire d'un nombre spécifié de positions. MOV AX, 5 ; AX = 5 (bin : 0000000000000101) SHL [1000h], 1 ; Décale la valeur à l'adresse 1000h de 1 bit vers la gauche REG, immédiat : Décale un registre d'un nombre spécifié de positions. MOV AX, 5 ; AX = 5 (bin : 0000000000000101) SHL AX, 1 ; Décale AX de 1 bit vers la gauche. AX devient 10 (bin : 0000000000001010) Mémoire, CL : Décale la valeur stockée à une adresse mémoire d'un nombre de positions spécifié par le registre CL (8 bits). MOV CL, 2 ; CL = 2 MOV AX, 16 ; AX = 16 (bin : 0000000000010000) SHL [1000h], CL ; Décale la valeur à l'adresse 1000h de 2 bits vers la gauche REG, CL : Décale un registre d'un nombre de positions spécifié par le registre CL. MOV CL, 3 ; CL = 3 MOV AX, 5 ; AX = 5 (bin : 0000000000000101) SHL AX, CL ; Décale AX de 3 bits vers la gauche. AX devient 40 (bin : 0000000000101000) Logiques et de manipulation de bits : Opérations logiques et de gestion des bits AND (ET logique) L'instruction AND effectue un ET logique entre deux opérandes. Chaque bit de l'opérande destination est comparé avec le bit correspondant de l'opérande source. Le résultat sera 1 si les deux bits sont 1, sinon le résultat sera 0. MOV AX, 5 ; AX = 0101 (en binaire) MOV BX, 3 ; BX = 0011 (en binaire) 27 AND AX, BX ; AX = 0001 (en binaire), seulement le dernier bit est à 1 Registre à registre : AND AX, BX Registre à mémoire : AND AX, [1000h] Mémoire à registre : AND [1000h], BX Registre à immédiat : AND AX, 5 OR (OU logique) L'instruction OR effectue un OU logique entre deux opérandes. Le résultat sera 1 si au moins l'un des bits est 1, sinon le résultat sera 0. MOV AX, 5 ; AX = 0101 (en binaire) MOV BX, 3 ; BX = 0011 (en binaire) OR AX, BX ; AX = 0111 (en binaire), tous les bits sont à 1 Registre à registre : OR AX, BX Registre à mémoire : OR AX, [1000h] Mémoire à registre : OR [1000h], BX Registre à immédiat : OR AX, 5 28 XOR (OU exclusif) L'instruction XOR effectue un OU exclusif logique entre deux opérandes. Le résultat est 1 si un seul des bits est 1, mais pas les deux. MOV AX, 5 ; AX = 0101 (en binaire) MOV BX, 3 ; BX = 0011 (en binaire) XOR AX, BX ; AX = 0110 (en binaire), les bits à 1 sont ceux où les bits des deux opérandes diffèrent Registre à registre : XOR AX, BX Registre à mémoire : XOR AX, [1000h] Mémoire à registre : XOR [1000h], BX Registre à immédiat : XOR AX, 5 CMP (Comparer) L'instruction CMP (Comparer) en 8086 compare deux opérandes en effectuant une soustraction entre eux, mais sans stocker le résultat. Elle met à jour les indicateurs de statut (drapeaux) en fonction du résultat de la comparaison. Description de l'instruction CMP Opération interne : CMP destination, source est équivalente à SUB destination, source, mais sans stocker le résultat de la soustraction. Les drapeaux (Carry Flag, Zero Flag, Sign Flag, etc.) sont affectés selon le résultat de la soustraction. Effet sur les drapeaux : o ZF (Zero Flag) : Si les deux opérandes sont égaux, le drapeau ZF est mis à 1 (sinon il est mis à 0). o SF (Sign Flag) : Si le résultat est négatif (si la soustraction a donné un résultat négatif), le drapeau SF est mis à 1. o OF (Overflow Flag) : Si un dépassement de capacité se produit (ex. : addition ou soustraction entre grands nombres), le drapeau OF est mis à 1. 29 o CF (Carry Flag) : Si un emprunt a eu lieu lors de la soustraction (comme une soustraction avec un nombre plus grand), le drapeau CF est mis à 1. Exemples d'utilisation de l'instruction CMP Registre à registre : Compare deux registres. CMP AX, BX ; Compare AX avec BX Cette instruction effectue la soustraction AX – BX et affecte les drapeaux selon le résultat, mais ne stocke pas le résultat de la soustraction. Registre à mémoire : Compare un registre avec une valeur en mémoire. CMP AX, [1000h] ; Compare AX avec la valeur à l'adresse 1000h Mémoire à registre : Compare une valeur en mémoire avec un registre. CMP [1000h], BX ; Compare la valeur à l'adresse 1000h avec BX Registre à immédiat : Compare un registre avec une valeur immédiate. CMP AX, 10 ; Compare AX avec la valeur immédiate 10 Mémoire à immédiat : Compare une valeur en mémoire avec une valeur immédiate. CMP [1000h], 5 ; Compare la valeur à l'adresse 1000h avec 5 Effet de la comparaison sur les drapeaux ZF = 1 : Les deux opérandes sont égaux. ZF = 0 : Les deux opérandes ne sont pas égaux. SF = 1 : Le résultat de la soustraction est négatif. SF = 0 : Le résultat de la soustraction est positif. OF = 1 : Un dépassement de capacité a eu lieu. CF = 1 : L'emprunt a eu lieu lors de la soustraction (dans le cas où la soustraction a produit un résultat inférieur à zéro). Exemples pratiques : - Comparaison de deux registres MOV AX, 10 ; AX = 10 MOV BX, 5 ; BX = 5 30 CMP AX, BX ; Compare AX avec BX (résultat : 10 - 5) JZ equal ; Si ZF = 1 (égalité), saute à l'étiquette "equal" - Comparaison d'un registre avec une valeur immédiate MOV AX, 10 ; AX = 10 CMP AX, 10 ; Compare AX avec 10 JZ equal ; Si ZF = 1 (égalité), saute à l'étiquette "equal" - Comparaison d'une valeur en mémoire avec un registre MOV AX, 5 ; AX = 5 CMP [1000h], AX ; Compare la valeur à l'adresse 1000h avec AX JNE not_equal ; Si ZF = 0 (différence), saute à l'étiquette "not_equal" Contrôle de programme : Instructions de sauts, boucles et appels JMP (Saut inconditionnel) : Effectue un saut inconditionnel à l'étiquette spécifiée. JZ (Saut si Zéro) : Effectue un saut si le drapeau Zéro (ZF) est activé. JNZ (Saut si non zéro) : Effectue un saut si le drapeau Zéro (ZF) n'est pas activé. JE (Saut si égal) : Effectue un saut si les deux opérandes sont égaux (ZF = 1). JNE (Saut si différent) : Effectue un saut si les deux opérandes sont différents (ZF = 0). JG (Saut si plus grand) : Effectue un saut si ZF = 0 et SF = OF (saut pour plus grand dans les comparaisons signées). JL (Saut si inférieur) : Effectue un saut si SF ≠ OF (saut pour inférieur dans les comparaisons signées). CALL (Appel de procédure) : Appelle une procédure et empile l'adresse de retour. RET (Retour de procédure) : Retourne de la procédure appelée en restaurant les registres. LOOP (Boucle) : Décrémente le registre CX et effectue un saut à l'étiquette spécifiée si CX ≠ 0. ORG 100h MOV CX, 5 label1: Add AX, 1 LOOP label1 RET Notion de label 31 Un label sert essentiellement de point de référence dans le programme. Il est placé à une ligne spécifique du code et est suivi d'un : (deux-points) pour l'identifier. Les labels sont utilisés dans les instructions de saut pour indiquer où le programme doit exécuter son code, en fonction des conditions spécifiées. Les labels sont particulièrement utiles pour : Définir des points de destination pour des sauts conditionnels ou inconditionnels. Organiser le flux du programme, notamment pour les boucles et les procédures. Déclaration d'un label Un label est simplement un nom suivi d'un deux-points. Voici un exemple simple : label1: ; Définition d'un label MOV AX, 5 MOV BX, 10 ADD AX, BX Dans cet exemple, label1 est un label et il marque une position spécifique dans le programme. Si vous souhaitez sauter à cet endroit du code, vous pouvez utiliser ce label dans une instruction de saut. Utilisation des labels avec des instructions de saut Les labels sont souvent utilisés avec les instructions de saut (JMP, JZ, JNE, etc.) pour contrôler le flux du programme. Exemple 1 : Saut inconditionnel (JMP) L'instruction JMP permet de sauter à un label sans condition : START: MOV AX, 5 MOV BX, 10 JMP label1 ; Saut inconditionnel à label1 MOV CX, 20 ; Cette instruction sera ignorée label1: ADD AX, BX ; AX = 15 ; Programme continue ici après le saut 32 Dans cet exemple, l'exécution saute directement au label label1 après l'exécution de l'instruction JMP. Exemple 2 : Saut conditionnel (JZ, JNE, etc.) Les instructions conditionnelles comme JZ (Jump if Zero) ou JNE (Jump if Not Equal) sont souvent utilisées après une comparaison avec CMP. Elles permettent de sauter à un label si une condition spécifique est remplie, en fonction des drapeaux du processeur (comme le drapeau zéro ou le drapeau de dépassement). MOV AX, 5 MOV BX, 5 CMP AX, BX ; Compare AX avec BX JZ equal ; Si AX == BX, saute à "equal" MOV CX, 10 ; Cette instruction est ignorée si le saut a lieu equal: MOV DX, 20 ; Si les valeurs sont égales, DX = 20 Dans cet exemple, si AX et BX sont égaux, le programme saute à equal. Si ce n'est pas le cas, il continue à exécuter la ligne suivante après CMP. Labels et boucles Les labels sont aussi couramment utilisés pour organiser les boucles dans le programme. Par exemple, une boucle peut être implémentée en utilisant un label pour marquer le début de la boucle, avec un saut conditionnel à la fin pour revenir au début si la condition est remplie. MOV BX, 5 ; Nombre d'itérations start: MOV AX, CX DEC BX ; Décrémente BX JNZ start ; Si BX != 0, retourne à "start" Dans cet exemple, le programme continue à exécuter la boucle tant que BX n'est pas égal à zéro. Notez que DEC agit sur le Zero flag. Le saut (JNZ start) fait revenir l'exécution à start jusqu'à ce que la condition (BX != 0) ne soit plus remplie. Référencement des labels Lorsqu'un label est défini, vous pouvez le référencer dans les instructions de saut (comme JMP, JZ, JNE, etc.). Le programme sautera à l'adresse mémoire correspondant à ce label. 33 Voici un exemple de structure générale avec des labels et des sauts conditionnels : MOV AX, 10 ; Charger AX avec 10 CMP AX, 5 ; Comparer AX avec 5 JGE greater ; Si AX >= 5, sauter à "greater" ; Code si AX < 5 MOV BX, 20 JMP end ; Sauter à la fin greater: ; Code si AX >= 5 MOV BX, 30 end: ; Code après les tests Instructions spéciales : Contrôle des interruptions, des drapeaux et du processeur INT (Interruption) : Génère une interruption logicielle. INT 21h IRET (Retour d'interruption) : Retourne d'une routine d'interruption en restaurant les registres. IRET HLT (Arrêt) : Arrête l'exécution du programme. HLT 4.2. Résumé Le jeu d’instructions du 8086 est riche et varié, couvrant un large éventail de besoins pour manipuler des données, contrôler le flux d’exécution, et interagir avec les périphériques. Les instructions de sauts, boucles, et appels permettent une gestion fine du programme, essentielle pour développer des logiciels optimisés sur cette architecture. 34 Chapitre 5 : La Pile d’exécution (Stack) dans l'Intel 8086 Introduction La pile (stack) est une structure de données fondamentale utilisée par le microprocesseur Intel 8086 pour gérer efficacement les appels de fonctions, les interruptions, et le stockage temporaire des données. Fonctionnant selon le principe LIFO (Last In, First Out), elle permet de sauvegarder et restaurer facilement le contexte d'exécution. Ce chapitre explore en détail la gestion de la pile dans le 8086, ses mécanismes et ses applications. 5.1. Définition et Structure de la Pile 5.1.1. Définition La pile est une zone spécifique de la mémoire, définie dans le segment mémoire appelé Segment de Pile (Stack Segment). Elle est utilisée pour empiler (sauvegarder) et dépiler (restaurer) des données ou des adresses. 5.1.2. Fonctionnement LIFO Le principe LIFO (Last In, First Out) signifie que le dernier élément empilé sera le premier à être dépilé. 5.2. Les Registres Associés à la Pile Le 8086 utilise deux registres pour gérer la pile : 1. SS (Stack Segment) : o Contient l'adresse de base du segment de pile. o Permet de localiser la zone mémoire où la pile est stockée. 2. SP (Stack Pointer) : o Contient l'adresse relative (offset) de l'élément supérieur de la pile dans le segment défini par SS. Adresse Physique de la Pile : L’adresse physique de la pile est calculée comme suit : Adresse Physique hex = (SS hex × 10 hex) + SP hex 35 5.3. Les Instructions Associées à la Pile Le 8086 fournit des instructions spécifiques pour manipuler la pile : 5.3.1. Instruction PUSH Sauvegarde une valeur sur la pile. Mécanisme : 1. Le registre SP est décrémenté de 2 (la pile fonctionne à reculons). 2. La valeur est stockée à l’adresse pointée par SS:SP. Exemple : MOV AX, 0x1234 ; Charger 0x1234 dans AX PUSH AX ; Empiler la valeur d’AX (SP = SP - 2, pile = 0x1234) 5.3.2. Instruction POP Restaure une valeur depuis la pile. Mécanisme : 1. La valeur est lue à l’adresse pointée par SS:SP. 2. Le registre SP est incrémenté de 2. Exemple : POP BX ; Dépiler la valeur supérieure de la pile dans BX 5.3.3. Instructions PUSHF et POPF PUSHF : Empile les drapeaux (Flags) du processeur sur la pile. POPF : Restaure les drapeaux depuis la pile. 5.3.4. Instruction CALL Sauvegarde l’adresse de retour (CS:IP) sur la pile avant d’effectuer un saut à une sous- routine. 5.3.5. Instruction RET Restaure l’adresse de retour (CS:IP) depuis la pile, permettant de revenir au programme principal après l’exécution d’une sous-routine. 5.3.6. Instruction IRET 36 Similaire à RET, mais utilisée pour les interruptions. Elle restaure également les drapeaux sauvegardés. 5.4. Applications de la Pile 5.4.1. Gestion des Appels de Sous-routines Lorsqu'une sous-routine est appelée avec CALL, l’adresse de retour est sauvegardée sur la pile. Cela permet de revenir au point d’appel après l’exécution de la sous-routine. Exemple : CALL MaFonction ; Sauvegarde CS:IP sur la pile et saute à MaFonction... MaFonction: ; Corps de la sous-routine RET ; Restaure CS:IP depuis la pile 5.4.2. Sauvegarde des Registres La pile est utilisée pour sauvegarder temporairement les registres avant d'effectuer une tâche, puis pour les restaurer une fois la tâche terminée. Exemple : PUSH AX ; Sauvegarder AX sur la pile MOV AX, BX ; Effectuer une opération sur AX POP AX ; Restaurer AX depuis la pile 5.4.3. Gestion des Interruptions Lorsqu’une interruption se produit : 1. Le processeur empile CS, IP, et les drapeaux sur la pile. 2. Après l’exécution de l’ISR (Interrupt Service Routine), l’instruction IRET restaure ces valeurs. 5.5. Exemple Complet 37 Voici un exemple illustrant plusieurs opérations sur la pile : MOV AX, 1234h ; Charger AX avec 0x1234 PUSH AX ; Empiler AX (SP = SP - 2, sommet pile = 1234h) MOV BX, 5678h ; Charger BX avec 5678h PUSH BX ; Empiler BX (SP = SP - 2, sommet pile = 5678h) POP AX ; Dépiler la pile dans AX (AX = 5678h, SP = SP + 2) POP BX ; Dépiler la pile dans BX (BX = 1234h, SP = SP + 2) 5.6. Avantages et Limitations de la Pile 5.6.1. Avantages 1. Simplicité : Le mécanisme LIFO est facile à implémenter et à utiliser. 2. Flexibilité : Permet de gérer dynamiquement les données et les adresses de retour. 3. Sécurité : Garantit que les données temporaires sont correctement restaurées. 5.6.2. Limitations 1. Dépendance au segment de pile : Une mauvaise gestion de SS:SP peut entraîner des erreurs graves (exemple : dépassement de pile). 2. Taille limitée : La pile est limitée à la taille allouée dans le segment de pile. 5.7. Résumé 1. La pile est une structure mémoire essentielle dans l’Intel 8086, utilisée pour : o Les appels de sous-routines. o La sauvegarde/restauration des registres. o La gestion des interruptions. 2. Les instructions clés pour manipuler la pile incluent PUSH, POP, CALL, RET, PUSHF, et POPF. 3. La pile repose sur le registre SP (Stack Pointer) pour pointer vers l’élément supérieur, et sur SS (Stack Segment) pour définir son segment mémoire. La compréhension de la pile est cruciale pour exploiter pleinement les capacités du 8086, notamment dans les contextes multitâches, d’interruptions et de sous-programmes. 38 Chapitre 6 : Les Interruptions dans l'Intel 8086 Introduction Dans l’architecture du microprocesseur Intel 8086, les interruptions sont essentielles pour gérer les événements matériels, logiciels, et les exceptions. En plus des interruptions standard du processeur, le système DOS fournit une série d’interruptions logicielles permettant d’interagir avec le système d’exploitation et les périphériques. Ce chapitre explore en détail les types d’interruptions, le rôle du PIC (Programmable Interrupt Controller), les mécanismes d’exécution des interruptions, et une liste exhaustive des interruptions matérielles, BIOS, et DOS. 6.1. Types d'Interruptions dans le 8086 Les interruptions se classent en trois catégories principales : Interruptions Matérielles (Hardware Interrupts) Déclenchées par des périphériques externes. Passent par le PIC (Programmable Interrupt Controller), qui les priorise et les signale au processeur via la ligne INTR. - Rôle du PIC (Programmable Interrupt Controller) Le PIC 8259 est un composant externe utilisé avec l’Intel 8086 pour gérer les interruptions matérielles. Il permet de prioriser les interruptions et d’envoyer le numéro d’interruption correspondant au processeur via la ligne INTR. - Fonctionnement du PIC 1. Signal d’interruption : o Un périphérique envoie une requête d’interruption au PIC. 2. Priorisation : o Le PIC détermine la priorité de l’interruption en fonction de son numéro (IRQ). 3. Notification au processeur : o Le PIC envoie un signal sur la ligne INTR pour informer le processeur. 4. Envoi du numéro d’interruption : o Une fois le processeur prêt, il envoie un signal d’acquittement (INTA), et le PIC transmet le numéro de l’interruption. 39 - Carte des IRQ IRQ Description Interruption 0 Minuteur système INT 08h 1 Clavier INT 09h 2 Cascade vers un second PIC INT 0Ah 3 Port série COM2 INT 0Bh 4 Port série COM1 INT 0Ch 5 Réservé ou port parallèle LPT2 INT 0Dh 6 Floppy Disk Controller (FDC) INT 0Eh 7 Port parallèle LPT1 INT 0Fh Le PIC étend la capacité du processeur à gérer plusieurs périphériques en assignant une interruption matérielle unique à chaque périphérique. Interruptions Logicielles (Software Interrupts) Déclenchées par l’instruction INT n, où n est le numéro de l’interruption. Incluent : o Interruptions BIOS : Fournissent des services de bas niveau (accès matériel). o Interruptions DOS : Fournissent des services système, comme la gestion des fichiers ou des périphériques. Interruptions dites “Exceptions” Déclenchées automatiquement par le processeur lors d’erreurs (division par zéro, overflow, etc.). 6.2. Le Tableau des Vecteurs d’Interruption Le tableau des vecteurs d’interruption est situé au début de la mémoire à l’adresse 0000h. Chaque entrée occupe 4 octets (2 pour CS et 2 pour IP) et pointe vers une routine ISR. 40 6.3. Liste Exhaustive des Interruptions Interruptions Matérielles et Système Numéro Description 0 Division par zéro 1 Mode pas-à-pas (Single Step) 2 Non-Maskable Interrupt (NMI) 3 Point d'arrêt (Breakpoint) 4 Dépassement arithmétique (Overflow) 5 Impression d'écran via BIOS 6-7 Non définies 8 Timer système (IRQ0) 9 Clavier (IRQ1) 10-15 Réservées ou matériel spécifique 16-31 Réservées pour Intel 32 à 255 Utilisées par DOS et les interruptions logicielles Interruptions DOS (INT 21h) L’interruption INT 21h (numéro 33 du tableau précédent) est l’une des plus utilisées sous DOS. Elle fournit un large éventail de services pour les opérations sur les fichiers, les périphériques, et les entrées/sorties. Quelquess fonctions de l’interruption : AH Fonction Description 01h Lire un caractère Lire un caractère depuis le clavier, avec écho. 02h Afficher un caractère Afficher un caractère à l’écran (dans DL). 09h Afficher une chaîne Afficher une chaîne se terminant par $. 0Ah Lire une chaîne Lire une chaîne depuis le clavier. 3Ch Créer un fichier Créer un fichier vide. 3Dh Ouvrir un fichier Ouvrir un fichier pour lecture, écriture ou les deux. 3Eh Fermer un fichier Fermer un fichier ouvert. 3Fh Lire dans un fichier Lire des données depuis un fichier ouvert. 40h Écrire dans un fichier Écrire des données dans un fichier ouvert. 41h Supprimer un fichier Supprimer un fichier spécifié. 4Ch Terminer un programme Quitter le programme avec un code de retour. Exemple : Afficher un caractère MOV AH, 02h ; Code de la fonction : afficher un caractère MOV DL, 'A' ; Charger le caractère 'A' dans DL INT 21h ; Appeler l’interruption DOS 41 Exemple : Lire une chaîne MOV AH, 0Ah ; Code de la fonction : lire une chaîne MOV DX, OFFSET BUFFER ; Charger l’adresse du tampon dans DX INT 21h ; Appeler l’interruption DOS RET Avec : BUFFER DB 20 ; Taille maximale de la chaîne DB 0 ; Longueur actuelle (sera remplie par DOS) DB 20 DUP (?) ; Espace pour la chaîne 6.4. Mécanisme d’Exécution d’une Interruption Lorsqu’une interruption est déclenchée, le 8086 suit une série d’étapes pour exécuter la routine ISR correspondante. 6.4.1. Étapes détaillées 1. Détection de l’interruption : o Le processeur termine l’instruction en cours. o Si l’interruption est matérielle, le PIC envoie le numéro de l’interruption via la ligne INTR. 2. Sauvegarde du contexte : o Les valeurs suivantes sont automatiquement empilées : ▪ Les flags (drapeaux du processeur). ▪ CS (Code Segment) de l’instruction interrompue. ▪ IP (Instruction Pointer) de l’instruction suivante. 3. Consultation du tableau des vecteurs d’interruption : o Le processeur calcule l’adresse de la routine ISR en multipliant le numéro d’interruption par 4 (chaque entrée occupe 4 octets). o Il charge les valeurs CS:IP correspondantes. 4. Exécution de l’ISR : o La routine ISR effectue les tâches requises (par exemple, gérer une frappe clavier). 5. Restauration du contexte : o Une fois l’ISR terminée, l’instruction IRET restaure les valeurs empilées, et l’exécution du programme principal reprend. o Les valeurs suivantes sont automatiquement dépilées : ▪ Les flags (drapeaux du processeur). ▪ CS (Code Segment) de l’instruction interrompue. ▪ IP (Instruction Pointer) de l’instruction suivante. 42 6.5. Exemple d’Interaction entre le 8086 et DOS Exemple : Lire et afficher une chaîne MOV AH, 09h ; Afficher une chaîne MOV DX, OFFSET MSG ; Charger l’adresse de la chaîne INT 21h ; Appeler l’interruption DOS MOV AH, 0Ah ; Lire une chaîne MOV DX, OFFSET BUFFER ; Charger le tampon INT 21h ; Appeler l’interruption DOS MOV AH, 09h ; Réafficher la chaîne lue MOV DX, OFFSET BUFFER+2 ; L’adresse commence après la taille et la longueur INT 21h ; Appeler l’interruption DOS RET Avec : MSG DB 'Entrez une chaîne : $' BUFFER DB 20 ; Taille maximale de la chaîne DB 0 ; Longueur actuelle (sera remplie par DOS) DB 20 DUP (?) ; Espace pour la chaîne 6.6. Résumé 1. Interruptions Matérielles : Gérées via le PIC, utilisées pour les périphériques comme le clavier ou le minuteur. 2. Interruptions Logicielles : Incluent les interruptions BIOS (niveau matériel) et DOS (niveau système). 3. Interruptions DOS via INT 21h : Fournissent une interface puissante pour gérer les fichiers, les périphériques, et les entrées/sorties. 4. Mécanisme d’exécution : Sauvegarde du contexte, exécution de l’ISR, et restauration via IRET. Les interruptions, combinées aux services DOS, permettent de gérer efficacement les ressources système et d’offrir une interface flexible pour le développement de programmes sur l’Intel 8086. 43

Use Quizgecko on...
Browser
Browser