Liste des Instructions Sparc

1ère partie : Instructions usuelles, opérations sur les entiers

Note: Je ne parle ici que des instructions de l'architecture Sparc V7/V8 ; les architectures supérieures ont d'autres possibilités (par exemple les instructions 64 bits, ou les multiplications et division). Je ne mentionne pas non plus les instructions privilégiées, ni celles du fpu.

Les instructions et les instructions synthétiques

On rappelle que Sparc est un processeur RISC; par conséquent, les instructions disponibles sont à la fois peu nombreuses et générales. C'est pourquoi certaines opérations qui sont des cas particuliers n'ont pas d'instruction machine dédiée ; on utilisera une instruction générale avec les bonnes opérandes à la place.
Ainsi, une opération du style dec reg sera en fait réalisée par sub reg,1,reg. Pour ne pas trop allourdir le style et la charge du programmeur, l'assembleur connait un certain nombre d'instructions synthétiques, qui ne sont pas des instructions machines mais des alias à l'usage du programmeur humain, et les remplace par une véritable instruction avec les bonnes opérandes. On garde ainsi la lisibilité d'un assembleur CISC avec un jeu d'instructions RISC.

Les instructions fondamentales :

Les instructions synthétiques :

Appel/retour de procédure


Les instructions fondamentales :

Lecture / ecriture en mémoire

Une adresse mémoire est toujours exprimée sous la forme [%r1+%r2] ou [%r1+cst], où %r1 et %r2 sont des registres, et cst est une constante signée exprimée sur 13 bits (-4096 à 4095).
On a aussi le droit d'écrire [%r] tout seul, l'assembleur le transformera en interne par [%r+0] ou [%r+%g0].

L'accès à la mémoire, en plus des protections d'accès habituelles, doit se faire avec le bon alignement ; à savoir, l'accès en lecture ou en ecriture à une donnée doit se faire à une adresse multiple de la taille de la donnée.

Note - il existe aussi un adressage en alternate adress space - je cherche encore ce que ça veut dire...
Lecture (load):
Les instructions de lecture sont de la forme ldxxx [adresse],reg. Pour les données de taille inférieure à 32 bits, il faut pouvoir faire la distinction entre interpretation signée et non signée lors du chargement, d'ou le dédoublement des instructions :
ld Charge un mot-mémoire (32 bits) dans le registre spécifié.
(Load)
ldsb Charge un octet dans le registre, avec extension de signe dans les 24 bits hauts du registre.
(Load Signed byte)
ldub Charge un octet dans les 8 bits-low du registre; le reste du registre est mis à zéro.
(load Unsigned byte)
ldsh Charge un demi-mot de 16 bits, avec extension de signe dans les 16 bits haut du registre.
(Load Signed Half-word)
lduh charge un demi-mot, avec mise à zéro des 16 bits hauts du registre.
(Load Unsigned Half-word)
ldd charge un double-mot; le premier mot est copié dans le registre spécifié rn, le mot suivant est copié dans Rn+1. n doit être pair.
(Load double word)
Ecriture (store):
Les instructions d'ecriture sont de la forme stxxx reg,[adresse].
st Ecrit le contenu du registre à l'adresse spécifiée.
(Store)
stb Ecrit les 8-bits bas du registre en mémoire.
(Store Byte)
sth Ecrit les 16 bits bas du registre en mémoire
(Store Halfword)
std Ecrit les registres Rn et Rn+1 dans les 8 octets suivant l'adresse spécifiée. n doit être pair.
(Store doubleword)
Lecture & Ecriture
Il existe deux instructions qui effectuent à la fois une lecture de mémoire vers registre et une écriture à la même adresse mémoire. Elles s'effectuent sur un octet seulement.
ldstub Cette instruction sert d'instruction "Test & Set": dans un cycle indivisible, elle charge l'octet mémoire dans le registre en même temps qu'elle ecrit ce registre en mémoire. La syntaxe est celle d'une instruction load : ldstub [adresse],reg.
(Load/Store unsigned byte)(instruction atomique)
swap Comme son nom l'indique, cette instruction echange le contenu d'un octet mémoire avec un registre. Attention cependant, selon les architectures, ce n'est pas une instruction atomique comme ldstub, et n'est donc pas utilisable en toute sécurité dans un rôle de Test and Set.
(la syntaxe est celle d'une instruction load : swap [adresse],reg)

Toutes ces instructions ont leur homologue en mémoire alternative (asi), en accolant "a" a la fin de l'instruction ( ldsba,stha,ldstuba,swapa..). J'ignore encore le rôle exact et les modalités d'utilisation de cette mémoire...

Arithmétique

Les instructions suivantes acceptent les deux syntaxes : Ces instructions n'influencent pas le registre des indicateurs:
add Le registre de destination reçoit op1+op2
addx Le registre de destination reçoit op1+op2+retenue
sub Le registre de destination reçoit op1-op2
subx Le registre de destination reçoit op1-op2-retenue
Si on veut que les indicateurs reflètent le résultat ( ou que la retenue éventuelle soit mémorisée), on utilisera le postfixe cc:

addcc , addxcc
subcc , subxcc

tagged add et sub.. d'etranges instructions fournies pour faciliter l'implémentation du Lisp:
Les mots additionnés par ces instructions peuvent être soit des entiers normaux codés sur 30 bits, indiqué par le fait que les 2 bits les moins significatifs sont à 0
Soit "autre chose" ( pointeur, code spécial) si au moins un de ces 2 bits est à 1.
les "tagged" instructions effectuent une addition/soustraction normale s'il s'agit d'entiers (et preservent les 2 bits à 0 dans le résultat); si ce n'est pas le cas, c'est un 'cas spécial' et dans ce cas, un Trap est exécuté qui se chargera de le gérer correctement.
L'hypothèse ici est que les cas "deux operandes de type entier" est le plus fréquent, menant à une execution rapide de ce qui nécessiterait un test logiciel incessant. (Voici mes références pour découvrir le rôle de ces instructions étranges....)
taddcc tagged add & modify cc -
tsubcc tagged sub & modify cc -
TADDccTV tagged add & modify cc, and trap on overflow -
tsubccTV tagged sub & modify cc, and trap on overflow -


binaire

Les instructions suivantes acceptent les deux syntaxes : Les instructions bit-bit suivantes acceptent le postfixe cc pour influencer les indicateurs :
or orcc OR logique entre le opérandes source.
orn orncc OR logique entre la premiere opérande et NOT la deuxieme opérande.
( non symétrique)
and andcc AND logique..
andn andncc AND logique... avec NOT la deuxième opérande
( non symétrique)
xor xorcc OR eXclusif
xnor xnorcc op1 XOR (NOT op2)
( commutatif !)
Pas de cc pour les instruction de décalage suivantes:
sll décalage logique vers la gauche de la première opérande du nombre de bits spécifié dans la 2eme.
Les nouveaux bits à droite sont mis à zéro.
(Shift Left Logical)
srl Décalage logique vers la droite. Les bits laissés à gauche sont mis à zéro.
(Shift Right Logical)
sra Décalage arithmétique vers la droite. Les bits de gauche sont assignés à la valeur du msb ( most significant bit) pour conserver le signe .
(Shift Right Arithmetic)

sethi

Vous avez remarqué que les constantes autorisées dans les instructions sont limitées à 13 bits; ce qui pose problème pour remplir tout un registre 32 bits avec une constante.... On utilise alors l'instruction spéciale sethi , dont le codage laisse 22 bits de libres pour la constante.

sethi const22,reg
remplit alors les 22 bits hauts du registre avec la constante spécifiée, les 10 bits bas étant mis à zéro. Pour terminer l'assignement du registre, on positionne ces 10 bits à l'aide d'une instruction or ou add. L'assembleur fournit les opérateurs %hi et %lo qui extraient les 22 bits haut et les 10 bits bas d'une constante pour faciliter ceci:
sethi %hi(constante_1),reg
or reg,%lo(constante_1),reg

branchement conditionnel

Ces instructions utilisent le contenu du registre d'indicateur (positionné par les instructions à postfixe cc) pour tester une condition de saut.
Ces branchements sont relatifs et l'offset est codé sur 22 bits signés, multiplié par 4 en interne ( les instructions étant toutes à un alignement de mot).
Ne pas oublier que ces instructions sont à branchement retardé ! L'instruction qui suit le saut est donc toujours executée, même si le saut est effectué pour sauter cette instruction. Cependant, on peut forcer un effacement du pipe-line pour empêcher cette exécution avec le bit d'annulation; il suffit pour celà de rajouter " ,a " apres l'instruction de saut : ex : be,a label .Ceci donne un comportement aux branchements conditionnels de type "non pipe-liné".
Les indicateurs utilisés sont :
b ; ba Branchement inconditionnel 1
bcc ; bgeu Branch if Cary Clear / Greater or Equal Unsigned
( si cmp op1,op2 donne op1>=op2 avec interpretation non signée
not C
bgu Branch if Greater Unsigned
si op1>op2 dans l'interprétation non signée
not (C or Z)
bge b. if Greater or Equal
si op1>=op2, dans l'interpretation signée
not ( N xor V )
bg ; bgt b if Greater (than)
si Op1>op2, signé
not(Z or (N xor V))
bleu b. if Lower or Equal Unsigned
op1<=op2, non signé
C or Z
bcs ; blu b if Carry Set / Lower Unsigned
op1<op2 non signé
C
ble b. if Lower or Equal
op1<=op2 , interprétation signée
Z or (N xor V)
bl ; blt b. if Lower (than)
op1<op2, signé
N xor V
bpos Branch if test Positive
si un test renvoie le flag "positif" (ou egal=0)
not N
bneg b. if Negative ( strict ) N
bvc b if Overflow clear ( =not overflow) not V
bvs b if Overflow Set V
be ; beq ; bz b. if Equal / Zero
( si les termes comparés sont egaux / si une instruction donne un résultat nul)
Z
bne ; bnz b. if Not equal/zero
Si différent / résultat non nul
not Z
bn Branch Never : n'effectue jamais le branchement.
( hemmm...)
0
(Il existe aussi des branchements conditionnés par les indicateurs du fpu, décrits sur la page du FPU)


Les instructions synthétiques:

Voila les pseudo-instructions qui sont traduites par l'assembleur en vraies instructions; les tables suivantes indiquent :
- Le nom de l'instruction synthétique
- Ce qu'elle fait
- La vraie instruction utilisée (ou une possibilité, il peut y avoir équivalence.)
mov/set
mov op1,%r2 Copie op1 (registre ou constante 13 bits) dans %r2 or %g0,op1,%r2
set Constante,%r Assigne une constante 32 bits au registre sethi %hi(Constante),%r
or %lo(constante),%r
clr %reg Efface le registre
Clear
or %g0,%g0,%reg
clrb/clrh/clr [adress] Efface l'octet/le demi-mot/le mot en mémoire stb/sth/st %g0,[adress]
Arithmétique
inc incremente le registre add reg,1,reg
inccc idem avec positionnement indicateurs addcc reg,1,reg
dec decremente le registre sub reg,1,reg
deccc subcc reg,1,reg
neg reg reg est remplacé par son opposé sub %g0,reg,reg
cmp reg,op2 Compare reg avec op2 (influence les indicateurs) subcc reg,op2,%g0
binaire/test
bset op1,reg Met a 1 les bits de reg spécifiés dans op1
(bit set)
or reg,op1,reg
bclr Met à 0 les bits de reg masqués par op1
(Bit clear)
andn reg,op1,reg
btst Teste les bits de reg avec op1
(Bit Test)
andcc reg,op1,%g0
btog op1,reg Fait commuter les bits de reg spécifiés dans op1
(bit toggle)
xor reg,op1,reg
tst reg Positionne les indicateurs selon le contenu de reg orcc %g0,reg,%g0
not reg NON logique du registre orn %g0,reg,reg
ou
xnor reg,%g0,reg
nop Rien. ( utile pour les delay-slots à la suite des sauts conditionnels et autres branchements) Tout ce qui ne fait rien:
or %g0,%g0,%g0, etc..

Appel/retour de procédure

jmpl [adresse],regd (jump & Link);
  • effectue un appel de routine dont l'adresse est déterminée à l'execution.

  • L'adresse de la routine doit d'abord être déterminée par le programme et placé dans un registre regs; on fera alors en général jmpl [regs],regd - les combinaisons jmpl [regs+r2],regd ou jmpl [rgs+const],regd sont moins fréquentes .
    Le registre regd est utilisé pour mémoriser le PC courant, pour pouvoir effectuer le retour de procedure.
    Conventionnellement, on utilise %o7.
  • Retour de procedure

  • cette instruction est aussi utilisée pour effectuer un retour; si %i7 contient le PC de l'instruction appelante, on pourra rendre la main par jmpl[%i7+8],%g0. car %i7+8 est l'adresse de l'instruction qui suit l'appel ET le delay-slot (qu'on ne veut en general pas executer en double), et le PC actuel etant sans intérêt, il est oublié dans %g0.
    Attention au nom de registre utilisé: %o7 ou %i7 ? cela dépend de la position de la fenêtre de registre; pour être sûr: utilisez les instructions synthétiques et respectez les conventions !
Instruction retardée
call <constante> Effectue un appel de procédure .
Le saut est PC-relatif (c'est l'offset de la procédure par rapport à l'intruction courante qui est codé)
cette instruction peut adresser toute la mémoire (30 bits sont reservés pour l''offset, multiplié par 4 en interne en raison de l'alignement des instructions sur frontière de mot ).
mecanisme : place PC de cette instruction dans %o7, puis saute à l'adresse de la routine.
Instruction retardée (suivie d'un delay-slot)
On peut aussi utiliser la syntaxe call reg ou call imm13, dans ce cas c'est un alias pour jmpl adresse,%o7.
jmp adresse Alias pour jmpl adresse,%g0
ret Retour de sous-routine
(alias pour jmpl [%i7+8],%g0)
retl Return from Leaf sub-routine
Retour d'une routine feuille ( qui n'a pas installé de nouvelle fenêtre de registres)
=jmpl [%o7+8],%g0 ( noter la subtilité...)
save %r1,cst,%r2 Installe une nouvelle fenêtre de registre et alloue la pile
Cette instruction demande le décalage de la fenêtre de registre; Elle en profite aussi pour effectuer une addition.
En pratique cette addition est utilisée pour allouer de la place sur la pile, avec une constante négative:
save %sp,-64,%sp alloue 64 octets sur la pile ( la taille minimale pour que le système puisse swapper les registres sans problème).
Attention!La dénomination des registres change en cours de l'execution de l'instruction; Notons save %sp1,-64,%sp2 : sp2 est le %sp de la nouvelle fenetre(=%o6_2) alors que sp1 est celui de l'ancienne fenetre (=%o6_1 = %i6_2 = %bp_2)
restore Revient à l'ancienne fenêtre de registre. Sa position standard est dans le delay slot de l'isntruction de retour:
ret
restore

(note : la syntaxe complete est celle d'une instruction d'addition (comme save) : restore r1,r_or_imm,rd qui effectue rd:=r1+r_or_imm; cette caracteristique n'est en pratique jamais utilisée; à optimiser ?... :)

Retour