Nous avons
vu que les bits du registre peuvent aussi représenter des nombres entiers qui
vont de 2 puissance 0 à 2 puissance 31 -1
soit 4 294 967 295 et donc l’assembleur permet d’effectuer des
opérations arithmétiques sur ces nombres. Pour faciliter les explications nous
allons ajouter à notre programme une procédure qui effectue l’affichage du
registre en base 10. Je vous demande donc de recopier tel quel ces
instructions à la fin du programme précédent.
/******************************************************************/
/* Affichage d'un registre en décimal */
/******************************************************************/
/* r0 contient la valeur */
affichageReg10:
push {r0-r6,lr} /* save des registres */
ldr r5,iAdrsZoneDec
mov r4,#10
mov r2,r0
mov r1,#10
/* conversion decimale */
1: /* debut de boucle de conversion */
mov r0,r2
/* copie nombre départ ou quotients successifs */
bl division /* division par le
facteur de conversion */
add r3,#48 /* car c'est un chiffre */
strb r3,[r5,r4] /* stockage du byte au debut zone (r5) + la
position (r4) */
sub r4,r4,#1 /* position précedente */
cmp r2,#0 /* arret si quotient est égale à zero */
bne 1b
/* mais il faut completer le debut
de la zone avec des blancs */
mov r3,#' ' /* caractere espace */
2:
strb r3,[r5,r4] /* stockage du byte */
subs r4,r4,#1 /* position précedente */
bge 2b /* boucle si r4 plus grand ou egal a
zero */
@ affichage
ldr r0,iAdrsZonemessDec
bl affichageMess
100:
pop {r0-r6,lr} /* restaur des 2 registres */
bx lr /* retour procedure */
iAdrsZoneDec:
.int sZoneDec
iAdrsZonemessDec:
.int sMessAffDec
/*=============================================*/
/* division
entiere non signée */
/*============================================*/
division:
/* r0 contains N */
/* r1 contains D */
/* r2 contains Q */
/* r3 contains R */
push {r4, lr}
mov r2, #0 /* r2 ← 0 */
mov r3, #0 /* r3 ← 0 */
mov r4, #32 /* r4 ← 32 */
b 2f
1:
movs r0, r0, LSL #1 /* r0 ← r0 << 1 updating cpsr (sets C
if 31st bit of r0 was 1) */
adc r3, r3, r3 /* r3 ← r3 + r3 + C. This is
equivalent to r3 ← (r3 << 1) + C */
cmp
r3, r1 /* compute r3 - r1 and
update cpsr */
subhs r3, r3, r1 /* if r3 >= r1 (C=1) then r3 ← r3 -
r1 */
adc r2, r2, r2 /* r2 ← r2 + r2 + C. This is
equivalent to r2 ← (r2 << 1) + C */
2:
subs r4, r4, #1 /* r4 ← r4 - 1 */
bpl 1b /* if r4 >= 0 (N=0) then branch
to .Lloop1 */
pop {r4, lr}
bx lr
et de remplacer l'instruction bl affichageReg2 par bl affichageReg10 dans la partie main.
Addition :
Nous pouvons
additionner une valeur immédiate au registre r0
par exemple mettre 10 dans r0 puis ajouter 25 par l’instruction add r0,#25 et afficher le
contenu du registre en décimal et le résultat est bien 35. Maintenant nous mettons la valeur maximale 2
puissance 31 – 1 dans le registre et ajoutons 5. Maintenant le résultat est
4 !! car nous avons dépassé la capacité maximale du registre. Mais
heureusement c’est prévu : l’indicateur de retenue (carry) peut être
positionné (en ajoutant le s au code instruction) pour signaler ce dépassement.
Et il y a même une instruction adc qui permet d’ajouter le carry à l’addition
suivante.
Soustraction :
De même nous
pouvons effectuer des soustractions avec l’instruction sub r0,#5. Mais là
aussi, il peut se poser le problème inverse, le nombre calculé peut être
inférieur à 0. Dans ce cas un nouvel indicateur du registre d’état (N pour
négatif) le signale. Mais l’assembleur permet de travailler avec des nombres
négatifs en considérant tous les nombres qui ont le bit 31 à 1 comme négatif et
en calculant leur valeur comme complément à deux.
Par exemple
le nombre négatif – 1 sera représenté par 2 << 31 – 1 soit FFFFFFFF en
hexadécimal et le plus petit nombre négatif par 80000000 en hexa soit
-2 147 483 648 Et comme nous avons utilisé le bit 31 comme
signe, le plus grand nombre positif possible sera 2<<30 – 1 soit 7FFFFFFF
en hexa soit 2 147 483 647 en décimal.
Ceci pose un
problème car si on effectue l’addition 2147483647 + 1 soit cela représentera le
nombre + 2147483648 si on considéré que les nombres sont non signés soit le
nombre – 2147483648 si on considère des nombres signés et bien sûr ce résultat
est faux dans ce cas. Là aussi un indicateur du registre d’état (V comme
overflow dépassement en français) indiquera ce dépassement et bien sûr ce sera
à nous de décider quoi faire dans ce cas.
Mais comment
le processeur sait-il s’il s’agit de nombres signés ou non signés ? Mais
il ne le sait pas et il s’en moque !!! c’est à vous de savoir à tout
moment si vous voulez effectuer des opérations sur des nombres signés ou sur
des nombres non signés et en fonction des indicateurs positionnés de prendre
les mesures qui s’imposent. Et il faudra bien choisir les codes conditions qui
devront s 'appliquer. Nous trouvons :
Pour les
nombres non signés :
Hs : pour supérieur ou égal
Hi :
pour supérieur
Ls :
pour inférieur ou égal
Lo :
pour inférieur
Et pour les
nombres signés :
Ge :
pour supérieur ou égal
Gt :
pour supérieur
Le : pour
inférieur ou égal
Lt :
pour inférieur
Il existe
aussi une instruction de soustraction intéressante RSB qui permet de soustraire
le contenu du registre d’une valeur immédiate :
Mov r0,#4
Rsb
r0,#32 @ soustrait de 32 la valeur de
r0
Multiplication :
Il n’est pas
possible d’effectuer une multiplication avec un seul registre et une valeur
immédiate.
Mais nous
avons vu que nous pouvons déplacer les bits du registre à gauche et à droite
avec les instructions lsl et lsr.
Par
exemple :
Mov r0,#5
Lsl
r0,#2 déplacement de 2 positions sur
la gauche
Le résultat
est 5 * (2puissance 2) = 5 * 4 = 20
Et
maintenant si on déplace les bits à droite d’une position
Lsr r0,#1 le
résultat est 20 / (2 puissance 1) = 10
Attention
cela ne fonctionne que pour des nombres non signés. Pour diviser un nombre signé il faut utiliser
l’instruction asr qui effectue un déplacement à droite mais en dupliquant aussi
sur la droite le bit 31 cad le bit du signe.
Pour multiplier
un nombre signé, il n’y a pas d’instruction spéciale car l’instruction
fonctionne si le résultat ne dépasse pas 2 puissance 30 ( dans ce cas le flag V
overflow est positionné)
Division :
Il n’y a pas
d’instruction de division pour la
plupart des processeurs Arm.
Et voilà,
nous avons vu tout ce qu’un registre peut traiter : des bits et des
nombres entiers. Mais et le reste !!!
Et bien tout ce que peut contenir un registre est soit géré par une
convention soit défini par vous-même.
Par exemple
les caractères A à Z sont codés sur un octet suivant le code ASCII mais ils
peuvent être codés suivant d’autres codes, UFT8 par exemple.
Vous pouvez
mettre dans un registre une couleur de pixel suivant la codification RGB 1
octet pour la luminosité, 1 octet pour la couleur rouge 1 pour le vert et 1
pour le bleu.
Il est aussi
possible de mettre un nombre en virgule flottante en respectant la norme IEEE
754 mais ne croyez pas effectuer une addition avec l’instruction add sur ces
nombres !! Nous verrons cela dans l’utilisation du coprocesseur.
Et il existe
bien d’autres conventions. Et vous, vous pouvez stocker ce que vous voulez dans
un registre : des secondes, des adresses mémoires, des caractères etc mais
ce sera toujours à vous de savoir ce qu’il contient pour éviter d’additionner
des poireaux et des carottes !!
Un dernier
point avec les valeurs immédiates : ce sont souvent des constantes et
l’assembleur dispose d’une pseudo instruction pour définir celles ci. C’est
l’instruction :
.equ NOM,
valeur qui permet d’affecter à
NOM la valeur valeur
Par exemple
.equ NBPOINTS, 5 et nous l’utilisons comme ceci
Mov
r0,#NBPOINTS
Le nom d’une
constante est souvent en majuscule ce qui permet de l’identifier rapidement. La
déclaration est faite aussi souvent en
début du programme.
Nous pouvons
aussi nous interroger sur le registre d’état : c’est un registre de 32
bits dont le nom est cpsr (Current Program Status Register). Il n’est pas
possible d’effectuer directement des opérations logiques sur ce registre. Mais
nous disposons de 2 instructions spéciales :
mrs
r0,cpsr qui permet de récupérer dans r0
le contenu du registre d’état
Et msr
cpsr,r0 qui permet de mettre à jour ce registre. Mais attention ces
manipulations peuvent être dangereuses en cas de modification d’autres bits.
De toute
façon, nous aurons très rarement à modifier ce registre directement.
Aucun commentaire:
Enregistrer un commentaire