samedi 20 avril 2019

Les registres suite : autres registres


2 registres :

L’Ingénieur vit que le registre r0 s’ennuyait et il créa donc un deuxième registre qu’il appelât r1.
Ce nouveau registre peut faire tout ce que nous vu pour le registre r0 mais il peut aussi transférer sa valeur dans r0 ou recevoir la valeur de r0.
Exemple : On peut lui donner la valeur de r0 :
Mov r0,#10
Mov r1,r0
Et on peut donner sa valeur à r0
Mov r1,#20
Mov r0,r1
Et il faut bien faire attention au sens des instructions. Vous remarquerez que les registres de départ contiennent toujours la valeur d’origine. Ce n’est donc pas vraiment un déplacement mais une copie de données.
Nous pouvons additionner les 2 registres :
Mov r0,#5
Mov r1,#10
Add r0,r1
Et r0 contiendra maintenant 15.
Et effectuer des soustractions d’un registre sur l’autre.
Et hourra, nous pouvons effectuer des multiplications :
Mov r0,#5
Mov r1,#10
mul r0,r1
Attention, cette instruction (avec un s) ne positionne pas le flag overflow en cas de dépassement.
Et avec le raspberry pi 3 qui possède un processeur Cortex, des divisions :
Mov r0,#500
Mov r1,#10
udiv r0,r1           @ division non signée
sdiv r0,r1            @ division signée

Attention, il faudra toujours se poser la question du dépassement pour ces opérations.

Puis l’Ingénieur inventa la possibilité d’intervenir sur le registre source avant d’effectuer l’instruction grâce à l »ajout d’un circuit particulier ( barrel shifter). Celui-ci permet d’effectuer des opérations logiques cad  LSL LSR ASR ROT sur le registre de manière interne.
Par exemple :
Mov r1,#5         @ on met 5 dans r1
Mov r0,r1,lsl #1  @ multiplication de r1 par 2 et transfert dans r0
Résultat 10
Remarque : la valeur du registre r1 après l’instruction n’est pas changée
Il est donc possible d’effectuer des multiplications de multiple de 2 + 1 par exemple par 5 :
Mov r0,#6
Add r0,r0,lsl #2    @ multiplication de r0 par 4 puis ajout à lui même

Et aussi des multiplications de multiples de 2 – 1 :
Exemple multiplication par 7
Mov r0,#6
Rsb r0,r0,lsl #3   @ multiplication de r0 par 8 puis soustraction de r0 de ce résultat

3 registres :
Ce 3ième registre s’appelle  r2 et il effectue les mêmes fonctions que les 2 premiers registres. Mais cela permet quelques instructions supplémentaires :
Mov r1,#10
Mov r2,#5
add r0,r1,r2   @ addition de r1 et r2 et transfert dans r0
Attention : ne pas confondre cette instruction avec add r0,r1  où on ajoute r1 à r0 !!
Idem pour la soustraction et la multiplication
Mov r1,#10
Mov r2,#5
mul r0,r1,r2   @ multiplication de r1 et r2 et transfert dans r0
et nous pouvons aussi utiliser le barrel shifter :
Mov r1,#10
Mov r2,#5
Add r0,r1,r2 ,lsl #2  @ multiplication de r2 par 4,addition de r1 et r2 et transfert dans r0
Remarque1 :  r1 et r2 ne changent pas de valeur après l’instruction.
Remarque 2 : pour la multiplication, nous pouvons utiliser l’instruction umull qui stocke le résultat dans 2 registres : un pour la partie basse, un pour la partie haute (> à 32 bits). Ceci est intéressant car on peut détecter un dépassement de capacité en testant le registre qui contient la partie haute. S’il est différent de zéro, c’est qu’il y a dépassement.

Autres registres :
Avec 4 registres, nous pouvons effectuer une multiplication avec addition ou une soustraction en une seule instruction :
            mov r1,#200   
            mov r2,#2
            mov r3,#4
          mlas r0,r1,r2,r3  @r0 = (r1*r2) + r3

            mov r1,#200   
            mov r2,#2
            mov r3,#404
            mls r0,r1,r2,r3  @r0 = r3- (r1*r2)
Pour cette dernière instruction, il n’est pas possible de positionner le registre d’état

En tout nous avons 16 registres de 32 bits, les 11 premiers (r0 à r10) peuvent être utilisés comme les 3 premiers que nous venons de voir. Les registres r11 et r12  peuvent également être utilisés mais ils ont par ailleurs un rôle particulier. Les 3 derniers ne peuvent pas être utilisés de la même façon et nous verrons leur rôle dans les chapitres suivants.

vendredi 19 avril 2019

Suite : registres et nombres entiers


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.

mercredi 17 avril 2019

Les registres : le premier registre


Un registre :
Au tout début, l’Ingénieur créa le registre. Il s’agit d’un minuscule composant électrique composé de 8,ou 16 ou 32 ou 64 contacts. Si un contact est ouvert, le courant électrique ne passe pas et cela est représenté par un 0. Si le contact est fermé, le courant passe et cela est représenté par un 1. Chaque position est appelé bit, 8 bits forment un octet(ou byte), et la taille d’un registre représente un mot (word). Ici, comme nous avons un processeur  32bits, le registre et donc un mot ont une taille de 32 bits.Il est aussi possible de nommer un demi-mot (half-word) d’une taille de 16 bits.
L’Ingénieur a appelé ce premier registre r0 mais il aurait pu l’appeler A ou un,  car pour le processeur il s’agit du registre 0.
Que pouvons-nous faire avec ce registre ? Nous pouvons manipuler ses bits avec les instructions disponibles et en premier mettre tous les bits à zero avec l’instruction :
            mov r0,#0
mov représente le code opération de l’instruction et est un raccourci de move (déplacer en anglais). r0 est le nom du registre et #0 représente la valeur immédiate zéro. Donc cette instruction signifie mettre zéro dans le registre destinataire r0. Et oui, dans l’instruction il faut mettre le registre destinataire avant la valeur : cela date des débuts de l’informatique et cela perdure aujourd’hui dans beaucoup de langage d’assemblage. Si vous faites l’inverse, le compilateur signalera une erreur.
Pour vérifier cette instruction, nous allons utiliser le petit programme indiqué dans le chapitre précédent et qui va afficher les 32 bits du registre r0 sous la forme de 0 ou de 1. Comme le programme précèdent, je vous demande de saisir ou de copier ce programme puis de le compiler sans encore avoir les moyens de comprendre tout son fonctionnement. Ce qui est important c’est de voir l’instruction ligne 18  mov r0,#0  suivi de l’instruction bl affichageReg2 qui effectuera l’affichage du contenu.
Par la suite, vous n’aurez qu’à modifier et/ou ajouter de nouvelles instructions à la suite de ces 2 premières.
Voici le résultat :
Vous remarquerez que ce programme affiche un message de début et de fin de programme, ce qui est une bonne façon de s’assurer que les programmes fonctionnent correctement. Vous voyez aussi que l’affichage du contenu du registre s’effectue en découpant les 32 bits en octets ce qui facilite la lecture. Et tous les bits sont bien à zéro.
Mais votre programme n’affiche rien ou alors un message d’erreur comme « erreur de segmentation ». Avez-vous effectué la démarche de mise en place des outils vue au paragraphe précédent ? Effectué le premier test ? Si oui, relisez le programme et vérifier une à une les instructions et sinon, me contacter pour trouver l’erreur.
Maintenant, mettons le premier bit à 1 en utilisant l’instruction :
            mov r0,#1
Recompilons le programme et lançons l’exécution. Voici le résultat :

Le bit le plus à droite est bien à un. Ce bit occupe la position 0 du registre et ces bits à droite sont souvent nommés les bits de poids faible. Ceux à gauche sont les bits de poids fort. Car les bits représentent des nombres en notation binaire (voir  https://fr.wikipedia.org/wiki/Syst%C3%A8me_binaire ) et chaque bit exprime une puissance de 2. Donc de 2 puissance 0  à 2 puissance 31 . Pour mettre le bit de la position 1 à 1, il faut mettre la valeur binaire 10 dans le registre avec l’instruction :
            mov r0,#0b10
La partie 0b indique au compilateur que la valeur qui suit est une valeur binaire. Si l’instruction avait été  mov r0,#10, c’est la valeur décimale 10 qui aurait été stockée dans le registre et 10 en binaire est représenté par le nombre 1010  (2 puissance 1+ 2 puissance 3 = 2 + 8 = 10).
Nous pouvons le vérifier :

Début programme.
Valeur du registre : 00000000 00000000 00000000 00001010
Fin programme OK.

Attention, avec le Raspberry pi 1, il n’est pas possible de stocker toutes les valeurs binaires directement dans le registre. Nous verrons pourquoi dans la partie instructions. Il est possible de stocker toutes les valeurs de 0 à 255 (décimal) et les multiples de 4, 8 ,16 et 32 de ces valeurs. Le compilateur vous signalera une erreur si une valeur n’est pas possible directement.
Pour le raspberry pi 3 il est possible de stocker les valeurs de la plage 0-4095 avec l'instruction mov.

Pour faciliter la lecture des nombres en binaire, il est aussi possible de les manipuler en hexadécimal (base 16) : voir https://fr.wikipedia.org/wiki/Syst%C3%A8me_hexad%C3%A9cimal En base 16, la valeur 10 précédente devient A et l’instruction devient mov r0,#0xA. Voui ! il doit y avoir une raison historique pour mettre un x et pas un h. Maintenant c’est plus simple de manipuler les valeurs. Par exemple 255 en décimal est représenté en binaire par 1111 1111 et en hexa  par FF. Vous remarquerez qu’il est facile passer du binaire à l’hexa car il suffit de découper le nombre par 4 bits et de mettre leur valeur en hexa, 1111 devenant F.

Opérations logiques :
Après avoir mis une valeur dans le registre r0, nous pouvons manipuler les bits en utilisant les opérations logiques ET, OR, XOR.
Voyons les instructions assembleur et leur comportement :
Mov r0,#0b1100
And r0,#0b1010
La première instruction met les bits 3 et 2 à 1 et les bits 1 et 0 à 0
La deuxième effectue un ET logique bit à bit soit pour le 3 ième bit 1 ET 1 pour le 2ième 1 ET 0 pour le 1er 0 ET 1 et pour le bit 0, 0 ET 0
Et le résultat est le suivant :

Maintenant remplaçons l’instruction and par eor pour effectuer un OU LOGIQUE puis par xor pour un OU Exclusif. L’assembleur autorise aussi l’instruction BIC  qui effectue une combinaison du ET et du NON, et l’instruction mvn qui effectue une combinaison de la valeur 0xFFFFFFFF et du OU EXCLUSIF.

Voici les résultats de ces 5 instructions :
Vous allez me demander à quoi cela peut bien servir !!!  Et bien cela permet de stocker des valeurs logiques dans le registre et de pouvoir les extraire afin de les utiliser. Nous verrons plus tard que de nombreux périphériques utilisent souvent les bits d’un registre pour indiquer leur état, et qu’ils sont prêts à recevoir ou envoyer des données.

Comparaisons :
Il serait intéressant de pouvoir aussi comparer la valeur du registre avec une valeur donnée ou avec zéro. Pour cela, l’ingénieur a créé un registre spécial dont certains bits vont évoluer avec le résultat des comparaisons : c’est le registre d’état. Dans ce registre un bit (ou drapeau, ou fanion ou flag en anglais) permet de savoir si un résultat est une égalité ou s’il égal à zéro,  c’est le bit z (comme zéro) en position 30. Et pour conditionner une instruction à partir de ce drapeau, il suffit de rajouter eq (de equal en anglais)au code instruction si nous voulons savoir s’il y a égalité ou zéro ou ajouter ne ( de not equal en anglais) pour l’inégalité ou diffèrent de zéro. Voyons sur des exemples
Mettons zéro dans le registre r0 puis effectuons une comparaison avec l’instruction cmp et s’il y a égalité mettons 1 dans r0 et si inégalité mettons 2.
Mov r0,#0
Cmp r0,#0
Moveq r0,#1
Movne r0,#2
Et voici le résultat :

Remplaçons le mov r0,#0 par mov r0,#50 et voici le résultat :
Nous avons bien la valeur 10 soit 2 en binaire.

Mais l’Ingénieur ne s’est pas arrêté là !! il a encore simplifié en permettant d’ajouter à certaines instructions un s final qui va mettre à jour le registre d’état sans avoir à effectuer une comparaison. Donc le programme se réduit à ceci :
Movs r0,#0
Moveq r0,#1
Movne r0,#2
Et les résultats sont identiques !!
Puis pour permettre de tester un bit particulier ou un groupe de bits, l’Ingénieur a ajouté 2 instructions de comparaison : la première TST effectue une comparaison du registre après avoir fait un ET logique avec la valeur et la deuxième TSQ effectue la comparaison après un OU EXCLUSIF logique.
Voyons tout cela :
Mettons la valeur binaire 1100 dans le registre r0 puis modifions uniquement le bit 1 pour le mettre à 1 sans modifier tous les autres. Il nous faut faire un OU logique avec la valeur 0b10 puis nous testons la valeur de ce bit avec l’instruction tst r0,#0b10. Ce qui donne :
            mov r0,#0b1100  @ bit à 1 pour les positions 2 et 3
            eor r0,#0b10     @ maj du bit 1 sans toucher les autres
            bl affichageReg2  @ affichage registre pour vérification
            tst r0,#0b10        @ test du bit 1
            moveq r0,#1         @ si égal à 0, on met 1 dans r0
            movne r0,#2         @ sinon on met 2
            bl affichageReg2  @ et affichage pour vérification
Et le résultat :
Maintenant, nous recommençons le début de l’opération pour mettre les bits 1 2 et 3 à 1 puis nous continuons en mettant le bit 1 à 0 avec l’instruction bic r0,#b10 soit :
mov r0,#0b1100  @ bit à 1 pour les positions 2 et 3
            eor r0,#0b10     @ maj du bit 1 sans toucher les autres
            bl affichageReg2  @ affichage registre pour vérification
            bic r0,#0b10     @ pour remettre à zero le bit 1
            bl affichageReg2  @ affichage registre pour vérification
            tst r0,#0b10        @ test du bit 1
            moveq r0,#1         @ si egal à 0, on met 1 dans r0
            movne r0,#2         @ sinon on met 2
            bl affichageReg2  @ et affichage pour vérification
Et le résultat :

Déplacement de bits :
Les instructions assembleur lsl, lsr et ror permettent de déplacer les bits dans le registre : lsl déplace les bits sur la gauche (comme Left en anglais) lsr les déplace sur la droite et ror effectue une rotation. Il n’y a pas de rotation à gauche car  32 – n rotations à droite correspondent à n rotations à gauche
Exemple :
            mov r0,#0b11100  @ bit à 1 pour les positions 2,3 et 4
            lsl r0,#2     @ déplacement à gauche de 2 positions
            bl affichageReg2  @ affichage registre pour vérification
            lsr r0,#5    @ déplacement à droite de 5 positions
            bl affichageReg2  @ affichage registre pour vérification
            ror r0,#8    @ rotation à droite de 8 positions
            bl affichageReg2  @ affichage registre pour vérification
            ror r0,#32 - 1     @ rotation à droite de 31 positions
                                                           @ ce qui correspond à une rotation à gauche de une position
            bl affichageReg2  @ affichage registre pour vérification

Ce qui donne comme résultat :
Vous remarquerez qu’il est possible d’effectuer un calcul pour une valeur immédiate #32 – 1 mais attention, ce n’est pas le processeur qui effectue ce calcul mais le compilateur !! Ensuite lors de l’exécution de l’instruction lsr r0,#5, le bit le plus à droite est perdu, sur les 3 de départ il n’en reste plus que 2. Mais heureusement l’Ingénieur a prévu le cas et si c’est nécessaire nous pouvons connaitre la valeur du bit perdu. Il nous suffit d’ajouter le code s à la fin de l’instruction pour mettre à jour un bit du registre d’état avec la valeur de ce bit perdu. Ce bit d’état s’appelle le drapeau de retenue ( flag carry  en anglais  ou C). Ce bit d’état peut être testé avec les codes cc (Carry Clear) pour savoir s’il est égal à 0 ou cs (Carry Set) s’il est égal à 1 :
Exemple :
            @recup du carry
            mov r0,#0b101    @ mettre bits 0 et 2 à 1
            lsrs r0,#1       @ decalage de 1 à droit et maj du carry
            bl affichageReg2  @ affichage registre pour vérification
            movcc r0,#1        @ on met 1 si le carry est a zero
            movcs r0,#2        @ on met 2 si le carry est à un
            bl affichageReg2  @ affichage registre pour vérification
Résultat :
Puis ajoutons ceci :
            lsrs r0,#1       @ decalage de 1 à droit et maj du carry
            bl affichageReg2  @ affichage registre pour vérification
            movcc r0,#1        @ on met 1 si le carry est a zero
            movcs r0,#2        @ on met 2 si le carry est à un
            bl affichageReg2  @ affichage registre pour vérification
Pour déplacer d’une position à droite le résultat (qui doit être 10 en binaire) et donc mettre le premier bit (soit 0) dans le carry, tester le carry et vérifier le résultat. Bravo c’est un !!!


Nous pouvons aussi inverser l’ordre des bits par l’instruction rbit
Mov r0,#12
Rbit r0,r0
Nous avons aussi les instructions rev,rev16 et revsh qui inversent les octets, les demi mots. Vous pouvez tester ces instructions sur différentes valeurs.
Enfin nous pouvons compter le nombre de zéros contenus dans le registre en partant de la gauche avec l’instruction clz.

Nous avons bien 26 zéros à gauche dans le registre.