Obligement - L'Amiga au maximum

Lundi 02 juin 2025 - 04:05  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Le PowerPC et son assembleur
(Article écrit par Victorien Ferry et extrait de GuruMed.net - novembre 2004)


Voici un article visant à vous expliquer les particularités du langage machine des processeurs de la famille PowerPC, vu depuis le monde des Amiga. On ne va pas rentrer dans les détails, mais on relèvera ses particularités. Programmer cet assembleur est extrêmement intéressant, car il permet de se faire une image exacte du code qui va être exécuté, et on peut en théorie se permettre certaines bidouilles. Mais si du temps du 68000, l'assembleur était nécessaire pour obtenir les meilleures performances, ce n'est plus le cas avec le PowerPC, pour plusieurs raisons :
  • L'assembleur 68000 se justifiait pour manipuler les composants de l'Amiga classique sans abstraction matérielle. Avec les Amiga actuels, on a intérêt à utiliser uniquement le processeur et les fonctions système comme unique interface.

  • L'assembleur PowerPC a été étudié pour que les compilateurs puissent trouver le code le plus optimal de manière simple : pour une opération, il existe moins de possibilités différentes de l'écrire en assembleur PowerPC qu'en assembleur 68k.

  • Les compilateurs ont beaucoup évolués : trouver une écriture assembleur PowerPC plus rapide que celle générée par un compilateur pour un même algorithme est difficile (IBM a fait des expériences : entre un programmeur assembleur expérimenté et un compilateur, le compilateur gagne toujours).

  • Les optimisations que vous trouverez en assembleur PowerPC sont souvent directement adaptables en C/C++.

  • Il existe quatre générations d'exécutables Amiga PowerPC actuellement (WarpOS, PowerUP, AmigaOS 4 et MorphOS) utilisant deux différentes ABI : les "Application Binary Interface", qui définissent, entre autres, le rôle des registres. PowerUP, AmigaOS 4 et MorphOS utilisent l'ABI System V. Un source assembleur PowerPC ne peut s'adresser qu'à une ABI, donc programmer en assembleur, c'est perdre la portabilité d'un système à l'autre.
Malgré tout ces points, l'assembleur peut être parfois utile. Si vous lisez l'anglais, vous en apprendrez toujours plus sur les sites officiels.

1. Quelques spécificités du matériel

Le PowerPC a été inventé par Motorola, IBM et Apple au début des années 1990, et Motorola/IBM ont fabriqué leurs versions de chaque génération de PowerPC. Il s'agissait au départ de faire un processeur RISC grand public. La technologie RISC (Reduced Instruction Set) s'oppose au plus classique CISC (complex Instruction Set). L'idée est d'avoir moins d'instructions, ce qui permet d'accélérer le traitement. Une autre génération de PowerPC professionnel est dénommé "POWER" (Pipeline Orientation With Enhanced RISC) en opposition aux "PowerPC" actuels que nous utilisons. Ces deux architectures ont divergé (d'aucuns disent que le PowerPC n'est plus RISC) et utilisent un jeu d'instruction sensiblement différent : dans les catalogues d'instructions que vous trouverez, certaines ne sont valables que pour les "POWER".

En interne, les PowerPC peuvent ou non gérer des entiers 64 bits mais toujours des flottants 64 bits. L'ABI utilisée ensuite par le système devra en prendre compte. Pour nos Amiga, les registres entiers sont en 32 bits (jusqu'à nouvel ordre) mais les flottants sont utilisables en 32 (float) ou 64 bits (float double). Il existe des instructions pour les entiers 64 bits mais l'ABI décide de leur disponibilité. Encore plus fort : l'ABI peut aussi décider de l'ordre gros-boutiste/petit-boutiste ! Nos Amiga, comme les 68000 et les Mac, sont en gros-boutiste. Il est possible d'imaginer un système PowerPC complet implémenté nativement en petit-boutiste !

2. Le plein de registre

Ce qui frappe le néophyte sur l'assembleur PowerPC, c'est le nombre de registres internes :
  • 32 registres entier 32 bits (GPR, General Purpose Register) notés de r0 à r31 dans les sources.
  • 32 registres flottants accessibles en tant que 32 ou 64 bits (float double IEEE) (FPR) notés de f0 à f31 dans les sources.
Petits rappels : les registres sont en théorie utilisés comme variables locales d'une fonction. En 680X0, il existe des registres entier d'adressage (pointeurs) et des registres entiers de calcul. Ici, les registres entiers peuvent chacun avoir l'un ou l'autre rôle. Certains registres ont un rôle strict défini par l'ABI et ne peuvent pas être utilisés pour autre chose : ainsi, un des 32 registres entiers est le pointeur de pile, et un autre sera un pointeur vers la TOC (Table Of Content), les variables globales. L'ABI défini enfin quels registres doivent être gardés intacts (persistants) ou pas (volatiles) lors d'un retour de fonction. Donc, vous aurez compris qu'une connaissance parfaite de votre ABI favorite est nécessaire à l'écriture du moindre code.

3. Un processeur qui mise sur ses caches

Les instructions PowerPC assemblées font en général quatre octets, alors que sur les 68000 et les processeurs Intel, on a plutôt deux octets. Cela signifie qu'une fois assemblé, un code PowerPC peut être plus long. Nous verrons que pour d'autres raisons, il est parfois plus court.

Mais ce n'est pas fini : 4*32 + 8*32 = 384. Les registres du PowerPC pèsent 384 octets. Chaque fois qu'on veut stocker un état des registres, c'est 384 octets qui doivent être écrit puis lu. Si une tâche utilise le VPU (Vector Processing Unit, l'AltiVec), on atteint un kilo-octet de registres internes, quand un 68000 n'avait que 64 octets !

Cela reflète la politique PowerPC de se baser sur ses gros caches internes : les problèmes de performances du bus liés à tous ces accès sont annulés par l'efficacité du cache. Par exemple, la pile d'une tâche ne va réaliser vraiment ses écritures/lectures qu'en dernier recours.

4. La syntaxe, le système de mnémonique

Dans les faits, le PowerPC est un des processeurs qui possède le plus d'instructions assembleurs bien qu'il soit RISC. Il existe une syntaxe de base définie par IBM : "#" pour les commentaires, les mnémoniques des instructions sont clairement définie, comme les "pseudo op" : les directives de compilations, (commençant par "." comme ".align") qui sont définies aussi. Ensuite, les applications d'assemblage (passembleur, Powerassembleur sur Amiga) peuvent rajouter d'autres mnémoniques et d'autres pseudo op en interne !

Nous allons vous apprendre à lire l'assembleur PowerPC.

Si vous lâchez un assembleuriste 68000 ou x86 sur de l'assembleur PowerPC, il ne va rien comprendre. En 68000, vous aviez une instruction "move" unique pour réaliser une copie de valeur, entre registres ou mémoires. Le format de données était explicite, donné par ".b" (un octet) ".w" (deux octets) et ".l" (quatre octets). La source et la destination du "move" pouvait être un registre ou une mémoire, et il y avait plusieurs modes d'indexations possibles. En PowerPC, vous trouverez un jeu d'instructions pour remplacer "move". Notez que pour toutes les mnémoniques assembleur PowerPC, le registre affecté ou lu est toujours à gauche :
  • li r4,456 # étend la valeur 456 définie sur 16 bits dans le registre r4 en 32 bits (load immediate).
  • mr r4,r5 # copie de registre 32 bits source r5 vers un registre destination r4 (move register).
  • lbz r5,décalage (r6) # lit valeur 8 bits à l'adresse pointée par r6+décalage dans r5 et les 24 bits de poids fort sont mis à zero (8 bits non signé).
  • lba r5,décalage (r6) # pareil mais les 24 bits forts sont étendus par le signe (8 bits signé).
  • lhz r5,décalage (r6) # lit une valeur 16 bits vers 32 bits, en tant que non signé (load half and zero).
  • lha r5,décalage (r6) # lit une valeur 16 bits vers 32 bits, en tant que signé (load half algebraic).
  • lwz r5,décalage (r6) # lit une valeur 32 bits à l'adresse pointée par r6+décalage (load word and zero). Note importante : dans le cas de lwz sur une ABI 32 bits, le "z" s'adresse aux 32 bits non implémentés, et "lwa" n'a pas de sens.
  • lwzx r5,r6,r7 # comme lwz, mais l'adresse lue est donnée par r6+r7.
  • lwzu r5,décalage (r6) # comme lwz, mais après r6 = r6 + décalage.
  • lwzux r5,r6,r7 # comme lwzx, mais ensuite r5 = r6 + r7.
  • lfs f0,décalage (r6) # lecture d'un float quatre octets dans le registre flottant f0.
  • lfd f0,décalage (r6) # lecture d'un float double huit octets.
  • stb r5,décalage (r6) # écrit l'octet de poids faible de r5 à l'adresse r6+décalage (store byte).
  • stw r5,décalage (r6) # écrit les 32 bits de poids faible à l'adresse r6+décalage (store word).
  • stfsux ... # devinez !
Pourquoi ces noms si complexes et incompréhensibles ? Les noms des mnémoniques PowerPC sont les initiales de la phrase décrivant leurs actions. Toutes les instructions commençant par "l" (load) chargent depuis la mémoire vers un registre (à part "li", load immediate). Toutes celles commençant par "st" (store) écrivent la mémoire. Suit ensuite le format déplacé : en PowerPC, le vocabulaire n'est pas le même qu'en 68000, les "mots" PowerPC (word) font quatre octets (deux en 68k) mais ce n'est qu'une question de convention et de vocabulaire. On a :
  • b (byte) un octet.
  • h (half) entier deux octets.
  • w (word) entier quatre octets.
  • fs flottant quatre octets IEEE.
  • fd flottant double huit octets IEEE.
Ensuite, viennent les lettres d'option de la copie :
  • "z" après un "l" signifie que les bits de poids fort du registre sont mis à 0 (cas d'un entier non signé, sauf lwz de cas particulier).
  • "a" remplace "z" pour étendre le signe pour les nombres signés.
  • "i" pour "immediate", valeur donnée dans l'instruction.
  • "x" pour "indexed" indique que qu'on additionne deux registres pour trouver l'adresse à lire.
  • "u" pour "update" indique que le pointeur utilisé va être incrémenté après la copie ((a0)+ en 680x0).
  • "." ne marche pas pour les "load" et les "store" mais pour les opérations de calcul et de logique : indique optionnellement si l'instruction doit mettre à jour le registre d'état cr0 dont les bits indiquent les dépassements et l'égalité à 0, pour un prochain test (voir chapitre 13).
5. Le système d'abstraction de mnémonique par macro

Attention : les mnémoniques PowerPC sont déjà des abstractions par rapport au code assemblé ! Il existe un jeu d'instructions PowerPC officiel ("lwz" et "mr" en font partie) mais parmi elles certaines sont déjà des macros : "mr r4,r5" est une macro équivalente à "or r4,r5,r5".

Ne cherchez pas d'équivalent au "tst.l" du 68000, rajoutez un "." à l'instruction précédente, ou au pire faite "or. r5,r5,r5".

De même, beaucoup d'instructions de décalage officielles sont des macros de "rlwinm". Pour l'assembleur passembleur, certaines de ces macros sont déclarées en interne, d'autres font appel à un fichier d'en-tête spécial. N'importe qui peut créer ses propres macros, mais je ne le conseille pas. Certaines macros ont l'air intéressantes, mais elles correspondent parfois à plusieurs instructions, donc on perd la lisibilité des cycles effectivement exécutés pour un code.

6. Un gros piège : la notation des registres

Comme je l'ai déjà indiqué, les registres entiers sont notés de r0 à r31, il faut écrire "mr r5,r6" (copie r6 sur r5). Mais voilà, ces "rx" sont des macros ! L'assembleur PowerPC peut se contenter de cet équivalent : "mr 5,6" ou même "or 5,6,6".

C'est également vrai pour les registres flottants notés de f0 à f31. Je vous conseille fortement d'utiliser uniquement les notations "rx" et "fx" à chaque fois qu'il s'agit de registres, et de n'utiliser des valeurs entières que pour décrire des valeurs entières, des valeurs de décalages ou de positions de bits, sinon votre code sera illisible.

7. Le FPU : l'unité gérant les nombres réels flottants

Comme le FPU n'est jamais en option, je vous encourage à les utiliser autant que possible, ce qui laisse d'autant plus de registres libres pour les entiers. Attention à cette particularité importante du PowerPC : tous les accès mémoire FPU, en float ou en double, en lecture ou en écriture, doivent se faire sur des adresses multiples de 4 ou une exception est générée !

Cela signifie que si on a cette structure C alignée sur quatre octets :

struct maStructAvecUnFloat{

	short mas_deuxoctets;
	float mas_unfloat;

};

Si on réalise une lecture sur "mas_unfloat", il y a exception processeur, et sur la plupart des systèmes, cela se traduit par une émulation de l'instruction de lecture ou d'écriture (ralentissement significatif). Note : sur WarpOS, l'outil ShowHALInfo permet de tracer le nombre d'exceptions FPU émulées. Donc faites bien attention à aligner vos flottants.

Autre particularité du FPU : il existe une instruction assembleur de conversion d'un flottant vers un entier, mais il n'existe pas d'instruction de conversion d'un entier vers un flottant, il faut taper l'algorithme "de normalisation" pour créer le type flottant IEEE. Cela peut être très frustrant. Le fait est que j'ai programmé un moteur 3D en assembleur PowerPC sans m'être posé la question ! En effet, dans la grosse majorité des algorithmes, on dispose des flottants en entrée, et la conversion vers les entiers se fait une fois pour toutes en cours de route (dans le cas d'un pipeline 3D, on dispose des flottants décrivant la géométrie en entrée, et le passage en entier se fait seulement au niveau de l'écriture des pixels).

Les mêmes registres flottants peuvent être utilisés en tant que "float" quatre octets ou "float double" huit octets. Les fonctions de lecture/écriture mémoire (lfs, stfs ou lfd,stfd) décident de leurs types. Certains "cast" entre float et double écrits en c/C++ sont donc implicites une fois compilés. A noter que toutes les instructions de calcul flottant existent en version double et simple (on ajoute "s" dans ce cas) sauf pour la copie de registre à registre valable pour les deux : "fmr".

Quelques mnémoniques flottantes intéressantes :
  • fmadd frt,fra,frc,frb # deux cycles.
  • fmadds frt,fra,frc,frb # un cycle : précision simple.
  • fmadd. frt,fra,frc,frb
  • fmadds. frt,fra,frc,frb
...réalise une multiplication et une addition en un ou deux cycles, équivalente à :

{

	float frt,fra,frc,frb;
	frt = ( fra*frc ) + frb ;

}

Le calcul ci-dessus peut être compilé en une instruction PowerPC ! (code plus court). Ce n'est pas tout :
  • fmsub frt,fra,frc,frb # correspond à "frt = ( fra*frc ) - frb ;"
  • fnmadd frt,fra,frc,frb # correspond à "frt = -(( fra*frc ) + frb) ;"
  • fnmsub frt,fra,frc,frb # correspond à "frt = -(( fra*frc ) - frb) ;"
Les derniers GCC et vbcc génèrent de telles instructions (à vérifier !). Dernier point intéressant pour le C/C++ : chaque fois que vous écrivez une valeur flottante dans votre code :
  • float fa = 0.4f ; // quatre octets en variable globale.
  • double da = 0.4 ; // huit octets en variable globale.
...le compilateur va rajouter une variable globale contenant "0.4f" et compiler l'affectation comme :

lfs f0,varglobale1 (rtoc)
lfd f1,varglobale2 (rtoc)

Car il n'existe pas d'affectation immédiate flottante en PowerPC. Ce serait un moindre mal, mais les compilateurs actuels vont ajouter des données globales pour chaque écriture d'une valeur dans vos sources C, même si cette valeur apparaît plusieurs fois. Pour ces raisons, écrivez toujours "0.2f" et pas "0.2" quand vous le pourrez. La solution ultime en C est de créer son ".o" de valeurs flottantes globales récurrentes, et affectez ces variables globales à des variables locales le moment venu, au lieu d'écrire des valeurs directes dans vos équations. Cela accélérera vos calculs FPU (chez Intel, c'est pareil).

Avis aux petits malins qui pensent optimiser en pensant que ceci donne la valeur 0.0f à f0 :

fsub f0,f0,f0

Cela ne marchera pas si f0 est "NaN" (Not a Number). On fait les malins et voilà ce que ça donne.

8. La plupart des instructions pour le même prix !

La grande majorité des instructions PowerPC prennent un cycle. C'est le cas des additions, soustractions, opérations logiques, mais aussi des multiplications et décalages. Beaucoup d'optimisations autrefois valables pour la famille 680x0 ne se justifient plus :

a *=256;

...est aussi rapide que :

a <<=8;

Du côté du FPU, les additions et multiplications prennent également un cycle. La grosse exception reste les divisions. Les cycles varient en fonction de la génération de processeur :
  • divw r4,r5,r6 # division entière 32 bits : 21 cycles.
  • fdiv f3,f4,f5 # division en flottant huit octets (double) : 31 cycles.
  • fdivs f3,f4,f5 # division en flottant quatre octets (float) : 17 cycles.
Il faut donc éviter de faire des divisions dans les boucles. Si vous utilisez les flottants et que vous divisez par une valeur constante dans une boucle, n'écrivez pas ceci :

{
float fa = fb / 5.0f ;
...
}

...mais cela (la valeur 0.2f sera stockée et aucune division réalisée) :

float f_1div5 = 1.0f / 5.0f ;
{
float fa= fb * f_1div5 ;
...
}

Mais c'est peut-être automatique pour votre compilateur.

9. Le PowerPC peut paralléliser beaucoup de calculs

Le PowerPC peut également paralléliser un grand nombre de calculs dans les mêmes cycles si des instructions consécutives utilisent des registres différents et des instructions permettant cette parallélisation (notion de pipeline dans le processeur, qui parallélise les instructions). Le FPU peut aussi travailler en parallèle avec les entiers, dans les mêmes cycles. Par exemple :
  • Ivw r13,r13,r14
  • fmadd f0,f1,f2,f3
  • add r5,r5,r6
  • add r7,r7,r8
  • add r9,r9,r10
  • add r11,r11,r12
  • ...
Les quatre additions peuvent être réalisées dans un cycle, et l'exécution de la division entière est parallèle (mais continue après les "add"). Il existe de meilleurs exemples de parallélisation. Notez que les compilateurs sont censés en prendre compte.

10. Les mnémoniques de décalage de bits

Le PowerPC est très puissant en décalage de bit. A noter qu'en PowerPC, les bits sont numérotés dans l'ordre inverse de la convention 68000: le bit de poids le plus fort est le zéro, le bit de poids le plus faible est noté 31 (les sens gauche-droite de nature schématique, restent les mêmes). D'autre part, il semble que les bits notés 0 à 31 en 32 bits deviennent les bits 32 à 63 dans une ABI PowerPC 64 bits !).

L'instruction "Rotate Left Word Immediate Then AND with Mask" demande cinq paramètres !
  • rlwinm r_destination, r_source, nombre de bits de décalage à gauche (0-31), 1er bit du masque inclus (0-31), dernier bit du masque inclus (0-31)
Cela permet de prendre n'importe quelle suite de bits dans un registre, et de la copier au bit près dans un autre, en mettant les autres bits à 0. La plupart des instructions de décalage de bit sont des macros de rlwinm. Il n'y a pas besoin de version pour un décalage vers la droite : il suffit de spécifier (32-nombre de bits de décalage à droite) au nombre de bit de décalage à gauche. Malin non ?

Pour le même prix, on peut aussi utiliser "rlwimi" (Rotate Left Word Immediate Then Mask Insert) qui prend les mêmes paramètres, mais insère la suite de bits dans le registre destination, laissant les autres bits inchangés.

Le compilateur sait utiliser au mieux ces instructions :

int a = (b>>6) & 0x00ffff00 ;

...peut être compilée en une instruction assembleur PowerPC, qui plus est parallélisable. Là encore, on voit qu'un code PowerPC est parfois plus court. Les décalages algébriques (signés) à droite comme sraw et srawi ne sont pas des mnémoniques de ces instructions.

11. les mnémoniques logiques et arithmétiques

Les mnémoniques logiques et arithmétiques ont trois paramètres :
  • add r_destination,r_a,r_b # réalise r_destination = r_a + r_b
  • and r_destination,r_a,r_b # opération logique "et".
  • ...
Toutes ces mnémoniques prennent deux registres pour faire leurs calculs, et mettent le résultat dans un troisième. Cela économise des instructions d'affectations, et là aussi rend le code plus court. Voilà.

12. Des instructions de manipulation du cache puissantes

Ces instructions ne sont jamais et ne peuvent pas être utilisées par le compilateur, pourtant leurs maîtrises permettent d'accélérer de façon significative certaines routines ! Mais attention, il faut comprendre le mécanisme du cache et surtout le fait que les lignes de cache sont lues et écrites par bloc de 32 octets, lesquelles sont alignés sur des adresses multiples de 32. Si on fait un accès en lecture ou écriture, la ligne de cache "touchée" est d'abord chargée dans le cache, et l'opération effectuée dans le cache. Le cache sera validé en écriture RAM plus tard, à un moment indéterminé.

dcbt r4,r5

"Data Cache Block Touch" permet de préparer le chargement d'une ligne de cache, une zone mémoire de 32 octets qui sera ensuite lue plus vite par les instructions suivantes. Cela permet de paralléliser le chargement des données par le bus. L'adresse affectée est donnée ici par r4+r5.

dcbz r4,r5

"Data Cache Block to Zero". Encore plus fort, le fin du fin : lorsque vous effacez une zone mémoire, habituellement, vous mettez des registres à zero puis vous écrivez ces registres. Chaque ligne de cache va donc charger une mémoire en cache où elle va se faire écraser aussitôt par des zeros. "dcbz" permet de déclarer les 32 octets d'une ligne de cache comme chargés et mis à 0 sans chargement par le bus, ce qui accélère considérablement cette écriture. Dans les faits, et après des tests de performances sérieux, toutes écritures visant à écraser 32 octets à la suite peut être accélérée par un facteur 4 avec "dcbz". L'adresse affectée est donnée ici par r4+r5.

Il existe tout un jeu d'instructions de manipulation du cache interne ("dcbst" qui force une écriture dans l'instant, "dcbi" qui invalide une ligne de cache, etc.).

Notez que chacune des instructions "dcb(x)" peut potentiellement fonctionner ou pas, selon le contexte : certaines zones mémoire (la mémoire vidéo par exemple) ne peuvent pas être mises en cache. Un "dcbz" peut donc échouer selon la zone concernée.

Précision importante : les instructions "dcb(x)" sont faites pour manipuler des lignes de cache de 32 octets, avec lesquelles les PowerPC travaillent depuis les premières générations jusqu'au G4. Sur le G5, les lignes de cache sont à 128 octets. D'après des documentations d'Apple, sur G5, "dcbz" charge implicitement 128 octets et écrit 32 d'entre eux à zéro. Il a donc le même comportement qu'une écriture classique et ne génère pas de bogue. De plus, une nouvelle instruction G5, "dcbzl" permet d'effacer les 128 octets d'un CL sans lecture implicite. Selon une autre documentation IBM, le "dcbz" prend l'un ou l'autre comportement selon le système. Il est donc conseillé d'utiliser "dcbz" seulement après avoir testé que votre processeur est un G4 ou inférieur.

13. Les sauts gratuits et les huit registres d'état

L'instruction "b label" permet de faire un saut simple jusqu'à un label. Si le code exécuté et le code de destination du saut se trouvent déjà dans le cache instruction, le saut lui-même prend zéro cycle. Il est instantané.

Encore plus fort : un test, quel que soit l'assembleur, se déroule en deux temps. On met à jour un registre d'état, par exemple en comparant deux nombres, puis on réalise un branchement (saut) ou non, vers un code particulier d'après cet état (logique du "if" en C et BASIC). En assembleur PowerPC, si la mise à jour du registre d'état à été faite trois cycles avant le branchement de test, et si tous les codes concernés sont en cache instruction, ce branchement prend également zéro cycle. Il est instantané. Si vous avez compris, en PowerPC, un test peut potentiellement prendre zéro cycle !

Dans les 680X0, on avait un registre d'état qui stockait les dépassements, l'égalité à 0, le "plus petit que" et le "plus grand que", ce qui permet ensuite de faire des branchements (saut de test).

Sur PowerPC, on a huit registres d'état notés cr0, cr1, cr2, ..., cr7 (en fait tous font partie d'un registre entier spécial accessible) qui peuvent stocker huit images de ces états. L'option de test "." affecte toujours "cr0" :

sub. r5,r6,r7

Des instructions de comparaison comme "cmpwi" peuvent affecter l'un ou l'autre :

cmpwi cr1,r5,421 # compare valeur de r5 avec "421".

Les instructions de branchement conditionnel peuvent utiliser l'un ou l'autre :

beq cr1,label

...ou pas : utilisation implicite de cr0 :

beq label

Il est possible de faire des copies d'état entre ces registres :

mcrf cr1,cr0

Cependant, le code généré par les compilateurs n'utilise que cr0, cette capacité à retenir plusieurs registres d'état n'est accessible que depuis l'assembleur (même chose pour la famille des processeurs Intel).


[Retour en haut] / [Retour aux articles]