Notions d’architecture des processeurs RISC
La fonction principale d’un processeur est l’exécution d’un programme qui est encodé sous forme d’instructions dans la mémoire (Patterson et Hennessy, 2009). L’architecture d’un processeur est conçue en fonction d’un ensemble d’instructions, dénotée « Instruction Set Architecture » (ISA). Une des ISA les plus répandus est le x86 d’Intel, qui implémente un ensemble d’instructions de type « Complex Instruction Set Computer » (CISC). Cependant, les architectures processeur ARM implémentent plutôt un ensemble d’instructions de type « Reduced Instruction Set Computer » (RISC). Une attention particulière est donc portée pour les architectures RISC dans ce mémoire, puisque l’objectif est de concevoir une mémoire cache pour un processeur ARM. Les architectures de processeur RISC se distinguent par les caractéristiques suivantes.
Tout d’abord, comme son acronyme l’indique, ce type de processeur utilise un ensemble d’instructions simples et limitées. L’ISA implémente un format instructions et des modes d’adressage simples. Ensuite, l’architecture du processeur est basée sur de larges registres mémoires. Cette configuration facilite l’exécution d’opérations simples sur les données à partir d’un registre à un autre. L’exécution des opérations registre à registre ne prend que quelques cycles d’horloge. Contrairement aux architectures CISC, une instruction ne génère pas (ou très rarement) un mi7 croprogramme devant être exécuté sur plusieurs cycles. Finalement, un effort est fait au niveau du compilateur afin d’optimiser l’usage des registres mémoires. L’exécution au sein d’un processeur RISC peut être résumée en quelques étapes, telles qu’illustrées à la figure 1.1. La première étape consiste à aller chercher une instruction dans la mémoire à l’adresse indiquée par le programme. Cette étape est communément appelée « Instruction Fetch ». La deuxième étape consiste à décoder cette instruction pour déterminer quelle opération exécuter sur quelles opérandes. La troisième étape consiste à aller lire les opérandes à l’adresse indiquée (ou pouvant être calculée) par l’instruction dans les registres mémoires. La quatrième étape consiste à exécuter l’opération spécifiée par l’instruction sur les opérandes. Lors de la cinquième étape, le processeur accède la mémoire de données pour lire ou écrire à partir d’un registre. Cette étape est généralement issue d’une instruction de chargement en registre (« Load ») ou de stockage en mémoire (« Store »). Il est à noter que cette étape est située après l’étape d’exécution car le calcul de l’adresse en mémoire est fait par ce dernier. La sixième étape consiste en l’écriture du résultat de l’opération fait à l’étape 4 dans un registre mémoire. Cette étape est habituellement dénommée « Write Back ». La septième et dernière étape consiste à calculer la prochaine adresse de l’instruction du programme.
L’architecture RISC des processeurs ARM
Les architectures RISC varient énormément d’un processeur à un autre, ainsi que dans leur façon d’implémenter ces fonctionnalités. ARM, par exemple, est maintenant à sa huitième version de son ensemble d’instructions, dont les trois premières sont aujourd’hui désuètes (ARM, 2010a). Ce type de processeurs RISC domine le marché des systèmes embarqués par son architecture simple et performante (Stallings, 2010). Les versions les plus récentes sont regroupées sous trois types de profils, soit Application (A), Temps Réel (R) et eMbarqué (M). Le profil A est le plus complet et le plus performant des trois. Il comprend une MMU (« Memory Management Unit ») qui gère les accès dans un contexte multiprocesseur ou avec système d’exploitation. Son architecture inclut plusieurs accélérations et extensions, telles que Trust- Zone, qui permet de protéger les données sensibles. Les jeux d’instructions ARM 32-bit et Thumb 16-bit sont supportés. On retrouve parmi ce type de profil le Cortex-A8 et Cortex-A15, pour ne nommer que ceux-ci.
L’architecture du Cortex-A8 est représentée à la figure 1.2. Le profil R incorpore plusieurs éléments du profil A, tout en misant sur la prévisibilité d’exécution et la faible latence des systèmes en temps réel. Ainsi, ce type de processeur incorpore une MPU (« Memory Protection Unit) » au lieu d’une MMU, ce qui permet de restreindre l’accès des applications à certaines parties de la mémoire seulement. Ce profil propose un meilleur équilibre entre performance et efficacité énergétique pour les systèmes embarqués. Le Cortex- R4 fait partie de cette famille de processeurs. Les jeux d’instructions ARM et Thumb sont aussi supportés. Le profil M est orienté microcontrôleur, se basant sur une architecture simple et à faible puissance. Celui-ci implémente une architecture ARM réduite conçue pour le traitement rapide des interruptions. Ceci permet au processeur de garder un comportement déterministe et prévisible, idéal pour les systèmes embarqués. On retrouve sur le marché le Cortex-M3, entre autres. Les jeux d’instructions supportés sont ARM et une partie de Thumb.
Accès aux mémoires d’instructions et de données Il existe diverses contraintes reliées à l’utilisation de la mémoire pour stocker les instructions et les données du processeur. Richard L. Sites, un des pionniers de l’architecture des processeurs ayant travaillé au développement du DEC Alpha, décrit avec exactitude en 1996 les tendances au niveau de la conception de processeurs. Across the industry, today’s chips are largely able to execute code faster than we can feed them with instructions and data. There are no longer performance bottlenecks in the floating-point multiplier or in having only a single integer unit. The real design action is in memory subsystems – caches, buses, bandwidth, and latency. (Jacob et al., 2010, p. xxxi) La figure 1.3 illustre ces contraintes en fonction de la hiérarchie mémoire d’un processeur. La principale problématique est que la vitesse d’opération d’une mémoire est inversement proportionnelle à sa taille et à sa distance du processeur. Plus une mémoire est proche du processeur, moins elle est dense, mais plus elle est rapide. Le problème est l’inverse pour une mémoire qui est distante du processeur. De plus, le coût par bit de mémoire augmente très rapidement plus l’intégration est faite proche du processeur. Un compromis doit donc être fait entre la rapidité de mémoire et la taille de celle-ci pour éviter que la mémoire soit le goulot d’étranglement des processeurs.
Pour trouver un équilibre acceptable, plusieurs niveaux intermédiaires de mémoire sont intégrés dans les processeurs modernes. Les niveaux de mémoire inférieurs près du CPU, communément appelés mémoires caches, exploitent le concept de localité de référence pour gérer l’information quelles contiennent. D’ailleurs, plusieurs niveaux de cache peuvent être implémentés, du premier niveau de cache L1 jusqu’au dernier niveau LX. Il existe deux façons d’entrevoir le stockage des instructions et des données en cache pour un processeur. Tout d’abord, il est possible d’utiliser une cache unifiée, où sont contenues les instructions et les données accédées par le processeur. Ce type de cache s’inspire de l’architecture von Neumann. Ensuite, il est possible d’implémenter deux caches séparées, soit une cache d’instruction et une cache de données. Ce type de cache s’inspire de l’architecture Harvard. Le principal avantage d’utiliser deux caches séparées est la possibilité de paralléliser les accès aux instructions et aux données sans avoir à utiliser port d’accès double (« dual-port »). Finalement, un processeur peut implémenter qu’un seul type de cache, soit celle d’instructions ou de données, ou l’omettre complètement.
Architecture d’une mémoire cache
Comme il l’a été mentionné précédemment (Jacob et al., 2010), (ARM, 2010a), une cache est un bloc mémoire à haute vitesse localisé très proche du processeur. Une cache contient à la fois les données et les adresses permettant de localiser ces dernières, communément appelé étiquette cache, ou « cache tag ». Afin d’accélérer le processus de lecture et d’écriture en mémoire, une cache se base sur le principe statistique fondamental, soit la localité de référence. Le fonctionnement d’une cache est habituellement transparent aux applications qui sont exécutées par le processeur. Les stratégies et les mécanismes utilisées permettent aux caches d’opérer indépendamment d’un programme et de pouvoir définir quoi retenir dans leur mémoire. Les stratégies utilisées, telles que ceux gouvernant le placement de nouvelles données, l’accès à celles-ci et leur remplacement, déterminent l’efficacité de la cache. De manière conceptuelle, il est possible de diviser la cache en trois composantes fondamentales. Premièrement, son organisation logique permet de déterminer comment les informations y seront stockées. Deuxièmement, les stratégies de gestion du contenu définissent si les informations doivent être placées ou non dans la cache.
Troisièmement, les mécanismes de cohérence de la cache s’assurent que les données et les instructions reçues par le processeur sont à jour et consistantes avec les instances supérieures de mémoire. L’organisation logique d’une mémoire cache peut être caractérisée selon son type d’adressage, l’unification de ses données, son associativité, sa taille et le type éléments mémoire intégré. Du point de vue du processeur, l’organisation logique d’une mémoire cache est transparente. Peu importe la configuration interne de la cache, l’adresse doit établir une correspondance directe entre la donnée demandée et celle qui existe à un des niveaux de la mémoire. Cela étant dit, les performances d’une cache sont fonction de son optimisation selon le type de programmes exécutés par ce dernier. L’approche traditionnelle pour caractériser et optimiser une cache se base sur des programmes de référence, dénommés « benchmarks ». En faisant varier les paramètres définissant l’organisation de la cache et en exécutant différents types de programmes, il est possible d’obtenir des statistiques sur la performance de celle-ci. Des simulateurs de cache tel que Cacti ont été conçus pour automatiser ce travail d’exploration. Cette approche, davantage empirique que théorique, a été préconisée par Hennessey et Patterson (Hennessy et Patterson, 2011) à la fin des années 80.
|
Table des matières
INTRODUCTION
CHAPITRE 1 MÉMOIRES CACHES
1.1 Introduction
1.2 Concepts fondamentaux
1.2.1 Notions d’architecture des processeurs RISC
1.2.2 L’architecture RISC des processeurs ARM
1.2.3 Accès aux mémoires d’instructions et de données
1.2.4 Concept de localité de référence
1.3 Architecture d’une mémoire cache
1.3.1 Adressage mémoire
1.3.2 Associativité
1.3.3 Taille de la cache
1.3.4 Types de cellules mémoires
1.4 Gestion du contenu et de la cohérence d’une mémoire cache
1.4.1 Stratégie d’allocation
1.4.2 Stratégie de remplacement
1.4.3 Mécanismes de cohérence
1.5 Optimisation d’une mémoire cache
1.5.1 Métriques de performance : la latence et le débit
1.5.2 Revue des techniques existantes pour améliorer la performance
1.5.3 Métriques énergétiques : la consommation dynamique et statique
1.5.4 Revue des techniques existantes pour améliorer l’efficacité énergétique
1.6 Conclusion
CHAPITRE 2 PIPELINES ASYNCHRONES
2.1 Introduction
2.2 Principe d’un pipeline
2.3 Architecture des pipelines synchrones
2.4 Architecture des pipelines asynchrones
2.4.1 Encodage des données
2.4.2 Protocole de communication
2.4.3 Famille de circuits logiques
2.4.4 Types d’éléments mémoire
2.5 Revue de pipelines asynchrones existants
2.5.1 PS0 (William et Horowitz)
2.5.2 Micropipeline (Sutherland)
2.5.3 MOUSETRAP (Singh)
2.5.4 Click elements (Peeters)
2.6 Conclusion
CHAPITRE 3 ARCHITECTURE DU PROCESSEUR ARM ASYNCHRONE
ET SA MÉMOIRE L1 SYNCHRONE
3.1 Introduction
3.2 Méthodologie de développement asynchrone d’Octasic
3.2.1 Déconstruction du pipeline classique d’un processeur
3.2.2 Utilisation de jetons pour le partage des ressources
3.2.3 Fonctionnement interne des modules des jetons
3.3 Définition de la cache synchrone
3.3.1 Organisation logique
3.3.2 Gestion du contenu et de la cohérence
3.3.3 Architecture de la cache d’instruction L1
3.3.4 Interfaces de la cache d’instruction L1
3.4 Conclusion
CHAPITRE 4 PROPOSITION D’UNE NOUVELLE CACHE ASYNCHRONE POUR LE PROCESSEUR ARM
4.1 Introduction
4.2 Définition du pipeline asynchrone
4.2.1 Gestion du protocole de communication par les éléments Click
4.2.2 Arbitrage des étages du pipeline et génération du signal d’horloge par les jetons
4.2.3 Opération du pipeline asynchrone
4.3 Définition de la cache L1 asynchrone
4.3.1 Partitionnement de la cache d’instruction en ressources
4.3.2 Fonctionnement de la cache d’instruction asynchrone
4.3.3 Séquence de purge et de réinitialisation
4.4 Interfaces extérieures
4.4.1 Interface avec le PCBP en entrée
4.4.2 Interface avec IDecode en sortie
4.4.3 Interface avec le niveau de mémoire L2
4.5 Conclusion
CHAPITRE 5 ANALYSE DE PERFORMANCES DE LA CACHE ET DU PIPELINE
5.1 Introduction
5.2 Validation de la fonctionnalité de la cache asynchrone
5.2.1 Environnement de conception et de simulation
5.2.2 Caractéristiques des bancs de test
5.2.3 Limitations
5.3 Résultats des bancs de tests individuels
5.3.1 Placement préliminaire
5.3.2 Vitesse d’opération par étage du pipeline
5.3.3 Vitesse d’opération aux interfaces de la cache asynchrone
5.4 Comparaison avec la cache d’instruction synchrone
5.4.1 Taille physique
5.4.2 Performance en terme de vitesse d’exécution
5.4.3 Performance en terme d’efficacité énergétique
5.5 Analyse des résultats
5.5.1 Analyse individuelle
5.5.2 Analyse comparative
5.6 Conclusion
CONCLUSION
BIBLIOGRAPHIE
Télécharger le rapport complet