AMD K8 - Partie 3 : Etude de l'Architecture | ||||
By Franck D. - 16/02/2003 | ||||
Technologie AMD64 en détail
L'AMD64 propose un nouveau mode d'exploitation x86, succédant à l'IA32. La démarche entreprise par AMD présente de nombreux points communs avec celle proposée par le 386 lors de l'avènement du 32 bits. En premier lieu, l'AMD64 propose une extension "horizontale" en augmentant la taille des GPR à 64 bits. Les GPR sont bien entendu utilisables sous leurs formes 8, 16 et 32 bits, ce qui assure au K8 la compatibilité descendante. Lorsque le processeur est basculé dans un mode d'exploitation appelé "long mode", le système a alors accès aux registres sous leur forme 64 bits. C'est cette caractéristique qui vaut l'attribut de 64 bits aux processeurs K8. Cette extension horizontale a les conséquences directes suivantes :
Ces deux caractéristiques sont intéressantes, mais à long terme, car elles ne pallient pas à une faiblesse urgente de l'architecture IA32. Mais l'AMD64 apporte un plus que n'a pas apporté le 386 en son
temps : une extension verticale, c'est-à-dire que lorsqu'il est
exploité en mode 64 bits, le K8 propose non plus huit mais seize
GPR.
En plus des GPR, AMD a également jugé opportun d'augmenter le nombre de registres 128 bits SSE/SSE2, portant leur nombre total à 16 lorsque le processeur est exploité en mode 64 bits. En revanche, le nombre de registres flottants x87 reste inchangé, comme le montre le schéma ci-dessus. Nous étudierons les raisons d'un tel choix dans le paragraphe suivant.
Un des principaux défis du K8 a consisté à en faire un processeur inaugurant une nouvelle architecture 64 bits, et cela tout en fournissant les performances maximales avec les systèmes et applications 32 bits actuels. Pour ce faire, nous verrons dans ce chapitre que l'architecture AMD64 n'a pas été créée à partir d'une page blanche, mais qu'elle repose en très grande partie sur l'architecture IA32 existante. Bien entendu cela ne fait pas de l'AMD64 un mode d'exploitation 64 bits comparable à l'IA64, qu'Intel essaie de promouvoir au travers de son Itanium, en ce sens que l'AMD64 présente de nombreuses restrictions liées à son héritage 32 bits. En revanche, cet héritage permet une grande souplesse dans la transition 32 vers 64 bits, souplesse nécessaire à AMD pour imposer son processeur, et par là-même sa nouvelle architecture au sein du grand public.
Le K8 possède fondamentalement deux modes d'exploitation distincts : le "legacy mode" (ou mode "héritage", sous lequel le K8 se comporte comme n'importe quel processeur IA32), et le "long mode", le mode 64 bits. Le tableau ci-dessous résume les différents modes supportés par le K8.
Seule ombre au tableau : Wow64 ne peut évidemment pas encapsuler les applications qui tournent au même niveau de privilège que lui-même, et notamment les drivers système. Cela a pour conséquence que les drivers système doivent être compilés en mode 64 bits, afin de tourner de façon native sur les OS AMD64. La conséquence est fâcheuse : ces systèmes nécessitent des drivers spécifiques. Tout comme cela a été le cas pour Windows XP à son introduction (mais pour d'autres raisons que celles invoquées plus haut), il faudra attendre quelques mois pour voir les drivers 64 bits se généraliser, et nombre de matériels seront inexploitables sous les OS AMD64.
Seize GPR représentent certes une avancée appréciable
par rapport à l'IA32. On peut juste se demander pourquoi AMD n'a
pas été plus loin dans cette démarche en augmentant
le nombre de GPR en mode 64 bits à plus de seize registres. L'encodage des instructions IA32 s'effectue par un octet dans lequel sont codés les registres source et destination des intructions ; c'est l'octet ModRM, acronyme de "Mode / Register / Memory". Sur les 8 bits de cet octet, trois bits encodent le registre source et trois bits encodent le registre destination. Et avec trois bits, on peut encoder huit valeurs différentes, qui correspondent aux huit GPR de l'IA32. Pas question bien sûr de modifier cet octet ModRM, sous peine de rendre le processeur incompatible avec les applications 32 bits. Afin d'encoder 16 registres sources et destination, il manque un bit à chaque partie du registre ModRM, et chacun de ces bits se trouve dans un octet de préfixe, appelé REX, et qui est spécifique à l'exploitation en mode 64 bits. Un autre bit est également nécessaire dans le cas d'instructions faisant intervenir une opérande mémoire, et ce sont au final trois bits d'extension qui permettent la gestion 64 bits.
Pourquoi plus de registres SSE/SSE2 et pas plus de registres flottants
x87 ? Cela dit, les K7/K8 ne sont pas réputés pour briller particulièrement en SSE/SSE2, surtout face au Pentium 4 qui a été dessiné pour fournir des performances optimales sur ces deux jeux d'instructions. Cette différence de performance provient de l'architecture même des unités de calcul flottant des deux processeurs. Les unités de calculs comprennent des circuits logiques dédiés à un type d'opération. Ces circuits obéissent à des schémas logiques classiques, citons par exemple l'arbre de Wallace qui est une méthode d'organisation des portes logiques pour mener une opération telle qu'une addition ou une multiplication. Le Pentium 4 ayant été dessiné pour prendre en charge les opérations flottantes sur des registres 128 bits, les arbres de Wallace de ses circuits logiques ont une largeur de 128 bits, ce qui signifient qu'ils sont capables de traiter en une passe une multiplication ou une addition 128 bits. Attention, cela ne veut pas dire que de telles opérations s'effectuent en un seul cycle, car ces opérations restent soumises au découpage du pipeline. Le traitement en une passe signifie qu'un seul passage dans l'arbre de Wallace sera nécessaire afin d'effectuer une opération sur des registres 128 bits. Dans le K8, les unités de calculs flottants ont été dessinées pour fournir des performances maximales sur des registres x87, soit 80 bits. Les arbres de Wallace ont donc une largeur de 80 bits, ce qui nécessite deux passes pour effectuer une opération sur des registres 128 bits. Cela explique que les performances SSE et SSE2 du K8 soient, dans la
plupart des cas, inférieures à celles obtenues sur un Pentium
4. Cela signifie-t-il pour autant que le K8 va perdre sa suprématie
en calculs flottants lorsqu'il est utilisé dans un environnement
64 bits ? Les calculs flottants vont-ils donc être moins rapide
en mode 64 bits ? En fait, cela dépendra, mais dans la plupart
des cas, la réponse est non. En résumé, le K8 souffre en SSE dès lors que des
instructions vectorielles sont utilisées, mais il se comporte de
façon très performantes sur les instructions scalaires.
A la différence du Pentium 4, qui digère de la même
façon les deux types d'instructions.
Comme vous l'avez compris, nous verrons donc dans un code 64 bits un jeu d'instruction entier opérant que seize GPR 64 bits, et des instructions SSE/SSE2 scalaires opérant quant à elles sur 16 registres 128 bits. Une question importante concerne la taille du code généré.
Le code généré est plus gros en 64 bits, un code
plus gros présente de nombreux désavantages. D'une part
il se décode plus lentement, et d'autre part il remplit plus vite
le cache code du processeur. AMD a cependant prévu quelques astuces afin de limiter la taille
du code 64 bits. Voyons cela sur un exemple concret. mov register, 1 Si le registre fait une taille de 32 bits, la valeur qui lui sera affectée sera elle aussi codée sur 32 bits. Ce qui nous donne en notation hexadécimale : mov eax, 00000001h Si le registre fait 64 bits, nous aurons alors : mov rax, 0000000000000001h Vous l'avez compris, le "1" 64 bits s'encode sur beaucoup plus d'octets que le "1" 32 bits, et la taille de l'instruction 64 bits est au moins 4 octets plus grosse que son pendant 32 bits. Il est d'autant moins intéressant d'encoder la valeur en 64 bits que le besoin actuel d'entiers 64 bits est encore anecdotique. La solution retenue par AMD est dans le tableau des modes d'exploitation, dont nous avons retenu la partie concernée :
mov rax, 00000001h L'instruction 64 bits fait un donc un seul octets de plus que son équivalent 32 bits, cet octet étant le préfixe REX indiquant qu'il s'agit là d'une instruction 64 bits. A noter qu'en pratique, les compilateurs modernes agissent intelligemment, et encodent les opérandes sous leur forme canonique. Ainsi, l'instruction IA32 add ebx,8 est encodée sous la forme 83 C3 08 et non 83 C3 08 00 00 00. De la même façon, l'équivalent AMD64 de cette instruction : mov rbx,8 deviendra 48 83 C3 08. Le préfixe 48 correspond ici au registre REX. En ce qui concerne les opérandes faisant intervenir une adresse mémoire, le choix est plus délicat. L'utilisation d'adresses mémoire de plus de 32 bits risque de s'avérer beaucoup plus courant que des opérandes 64 bits, comme c'est le cas précédemment. AMD a donc choisi la voie inverse : la taille des adresses mémoire fait 64 bits par défaut, et la forme 32 bits nécessite de préfixer l'instruction. Ainsi, la taille par défaut des pointeurs C/C++ est 64 bits.
En outre, il faut également noter que le K8 est bien armé pour encaisser l'inflation de la taille du code généré, en particulier :
|
||||
Fermer |