| Sélectionnez votre chapitre | ||||||||


Cette page vous propose de découvrir, en français, le processeur
ARM. Ce n'est pas une documentation technique. Pour obtenir plus de détails,
je vous conseille de consulter les Data Sheets fournis par ARM.
Pour tout commentaire, écrivez à Stanislas
Renan.
Dernier changement majeur de ce document effectué le 22 novembre 2002.
Dernier changement mineur de ce document effectué le 22 novembre 2002.
Dernière mise à jour cosmétique effectuée le 14
avril 2003.
Merci à Gérard Blanchet pour ses pages
explicatives, en français, sur les architectures.
Remarque concernant le sommaire
Le processeur ARM (Acorn RISC - Reduced Instruction Set Computer - Machine) est conçu par la société ARM Ltd (Advanced RISC Machines), ex-filiale de la défunte société Acorn, et construit par VLSI Technology ou parfois Gec Plessey, Sharp ou TI.
Acorn fut une société anglaise qui construisait au début des années 1980 un micro appelé BBC, d'architecture 8 bits, très répandu dans the île. Elle a entrepris très tôt - dès 1983 - l'implantation d'un microprocesseur RISC (sur le modèle de Berkeley) sur silicium. À l'époque, la mode était aux processeurs CISC (Complex Instruction Set Computer) 8/16 bits et Intel vendait son 8086. L'objectif d'Acorn était de concevoir un processeur puissant à faible consommation. ARM est née du succès de cette entreprise, en novembre 1990.
Les ordinateurs Acorn ont été très répandus dans les pays du Commonwealth ainsi qu'en Allemagne et sont surtout utilisés dans l'éducation. Le marché français n'a malheureusement pas obéi à l'enthousiasme qu'avait suscité l'apparition du premier ordinateur RISC Acorn, l'Archimèdes, suivant le marché de masse de l'époque et restant apathique comme à son habitude.
Mon objectif dans cette page est de vous introduire aux merveilleuses possibilités qui découlent des recherches de la société Acorn (puis ARM) dans le domaine des processeurs. Une grande partie des actions Acorn ont été détenues par la multinationale Olivetti, mais ça, on s'en fout. Acorn était une des dernières société à proposer une plate-forme munie d'un OS non compatible MS-DOS ayant survécu à la déferlante IBM PC. Etant un ancien Atariste et toujours amateur de ces superbes machines, je tiens à défendre ici mes nouvelles amours de sillicium.
une simplification du core (noyau)
du processeur tout en permettant au programmeur d'effectuer facilement
toutes ses opérations;
la possibilité de cabler les
instructions qui seront exécutées directement en dur, sans
l'aide d'un fastidieux microcode;
une réduction de la
complexité matérielle du processeur donc une
réduction de son coût de fabrication;
la possibilité d'augmenter la
fréquence d'horloge grâce-à la baisse - relative -
de la température de fonctionnement.Les microprocesseurs ARM et RISC, en général, implantent une architecture appelée Load and Store ou Chargement/Rangement en français. La caractéristique de cette architecture est de ne pouvoir effectuer des opérations que de registre à registre. Pour en savoir plus, se reporter à la page de Gérard Blanchet sur les architectures RISC.
Le processeur ARM est souvent décrit comme l'une des plus belles implantations du concept RISC, c'est-à-dire l'une des plus fidèle à l'idée de simplicité.
La lecture de cette section n'est pas obligatoire pour comprendre l'ARM, mais comporte certains détails de nommage. Vous pouvez la lire ou bien vous rendre directement à la section suivante.
Le nom de chaque processeur ARM est dépendant de sa
complexité.
En fait, chaque évolution du core du processeur obtient un
numéro : 2,3... Après lui avoir adjoint toute son interface
de communication (bus, etc.), le nom gagne 2 zéros : 200,300...
Après son couplage avec un PMMU et le cache, il gagne 10 points :
210,310.
Si on lui adjoint toute une artillerie de processeurs vidéo et
sonore, etc., on reprend l'étape d'avant, on ajoute 50 et on
multiplie par 10: 7500,...
Cette logique n'est malheureusement pas respectée par Acorn! Ainsi le premier processeur commercialisé (sans cache) se nommait ARM2. Puis est apparu l'ARM250 avec le PMMU. Une nouvelle version plus rapide a ensuite vu le jour, avec cache : l'ARM3. Puis on a sauté à une étape plus respectueuse envers la règle et sont apparus les core ARM6 et 7, les chips ARM600 et 700 et les processeurs ARM610 et 710. L'ARM 700, par exemple, peut se voir adjoindre une FPU (Floating Point Unit) mais pas le 710, figé à son rôle de processeur. L'ARM 7500FE+ est un ARM700 associé à un VIDC20, le processeur vidéo et sonore d'ARM, et à une unité de calcul en virgule flottante.
On peut aussi parfois apercevoir des versions mutées des
cores, comme le 7D, le 7DM ou le 7a (ce dernier, issu d'une rumeur
des news, aurait des capacités de dialogue avec la mémoire
externe améliorées...),
qui sont les processeurs de base auquels on a adjoint des
particularités souvent intéressantes pour les industriels
car elles réduisent énormément certains coûts
de fabrication et, surtout, de contrôle qualité.
L'une des plus connues est l'extension T pour
Thumb, dotant les processeurs ARM d'un nouveau jeu d'instructions
sur 16 bits, prétendu efficace et très dense.
Une nouvelle définition du jeu d'instructions a été publiée par Advanced Risc Machines, l'ARMv4. Ce jeu, qui est décrit dans le manuel du processeur 810, est quasi identique à celui des cores précédents, en ajoutant entre autres les types halfword et signed halfword et en modifiant le comportement de certaines exceptions. Le StrongARM, conçu par Digital et désormais soutenu par intel, implante cette version. Le core ARM8 est sensé l'implanter, mais il n'a, à ma connaissance, jamais été fondu. À l'heure actuelle, ARM propose une version plus rapide de ce noyau, nommée ARM 9 ainsi qu'une implantation sous forme de processeur, les ARM 910T et 940T.
Le core ARM 10 a été dernièrement annoncé (en octobre 1998), mais il faudra attendre pour obtenir des renseignements dignes de foi. Pour grignoter, il est prévu que celui-ci soit doté d'une unité de calcul sur flottants. À voir...
De façon générale, la plupart des développements d'ARM depuis l'ARM 7 visent le marché de l'embarqué, et, en particulier, celui, très en vogue, des télécommunications. ARM tente donc de produire des noyaux puissants et consommant peu.
Les processeurs ARM610, 710, (810) et 910 et StrongARM ont un port de test, le port JTAG, et répondent à la norme IEEE 1149.1 .
-Le tableau suivant présente la taille des caches en Ko selon le modèle ainsi que la taille en mots (32 bits) et le nombre d'adresses du tampon d'écriture (WB) :
![[Taille des caches]](pix/CacheS.gif)
Taille des caches selon le processeur
-L'ARM 2 n'a pas de cache et les ARM3, 610, 710 et 810 ont un cache
unique pour les données et les instructions. Le StrongARM
a une structure de Harvard, donc deux caches distincts et les
entrées de son tampon d'écriture ont une taille variant
de 1 à 16 octets (il est en fait conçu par DEC).
Le cache permet de minimiser la perte de performance due à la
vitesse de réaction faible de la RAM classique. Il coûte
malheureusement trop cher pour être de grande taille. Le tampon
en écriture réduit encore le nombre de ces accès
en permettant de les regrouper.
-Les processeurs des familles 8, 9 et SA-1 (StrongARM) ont un
pipe-line à
5 niveaux (grossièrement : lecture de l'instruction; lecture
des registres et test de branchement; exécution; écriture
dans le cache; écriture dans les registres, mais cela
varie selon le processeur) et une unité de
prédiction de branchement (sauf SA-1).
Leurs prédécesseurs ont un pipe-line à 3 niveaux
(lecture de l'instruction, décodage, exécution).
-L'ARM 810 (s'il a jamais été contruit)
possède un
pipe-line à 5 étages et un cache unifié de 8ko
(aux lignes de 16 octets = 4 mots),
une unité de prédiction des branchements, un bus de
lecture à vitesse doublée (les lectures dans le cache
sont ainsi plus rapides, mais pas les écritures).
Il ne comporte pas que des améliorations, puisque les
instructions suivantes
ADD, ADC,
CMP, CMN,
RSB, RSC,
SUB, et SBC comportant
un décalage
immédiat codé sur plus de deux bits prennent un cycle
supplémentaire! étrange.
-L'ARM 910T possède deux caches de 4ko chacun. Un pour
les données, l'autre pour les instructions. L'ARM 910T a une
unité de gestion de la mémoire plus évoluée
que celle du 940T (pour les systèmes plus
complexes comme les micro-ordinateurs par exemple).
Tous les processeurs issus de l'architecture d'ARM (exception faite de l'extension Thumb de l'ARM7TDMI) ont leurs instructions codées sur 32 bits, la taille d'un mot. Cette taille d'instruction fixe est une particularité très intéressante des processeurs RISC en général. Sur un processeur CISC comme l'Intel 80486 par exemple, cette taille varie de 1 à 15 octets, ce qui rend certaines instructions très lentes à décoder. Les instructions de l'ARM sont presque toutes exécutées en un seul cycle apparent et ont la particularité d'être denses. Il est ainsi possible de trouver parfois jusqu'à quatre opérandes pour une seule instruction.
Exemple : add r0,r1,r2,lsl r3
:: r0:=r1+r2*(2**r3)
rn" représente un registre interne du
processeur qui en comporte 16 visibles au même moment (+2 registres
d'état, pour les ARM 610 et suivants). Au total, les processeurs
ARM 2 et 3 ont 27 registres 32 bits tandis que les processeurs ARM 610
et suivants ont 31 registres 32 bits (dont 6 registres d'état).Leur nom est souvent redéfinissable dans les assembleurs. Tous les registres jouent le même rôle (adresse et donnée) aux exceptions suivantes près :
r15, souvent noté pc, est le
compteur ordinal (ou Program Counter) et, pour simplifier pour
l'instant, pointe sur l'instruction à lire dans la
mémoire (ceci n'est pas exact et sera complété
plus loin).r14, souvent noté link, est un
registre au comportement normal mais qui est corrompu suite aux deux
instructions :bl, pour Branch Link, qui saute (modifie
r15) à une adresse absolue, codée sur 24
bits, placée en paramètre dans l'instruction et copie
l'ancien pc dans r14 pour le retour de
sous routine (un 68000 effectue une telle sauvegarde sur la pile,
et effectue alors des accès mémoire lents).swi, pour Software Interrupt, qui appelle
une routine système ou une librairie utilisateur
indiquée en paramètre dans l'instruction (à la
manière d'un trap du 68000, en beaucoup
plus puissant). Cette instruction modifie r14. Le
traitement associé peut modifier les registres mais il
s'agit alors d'une modification logicielle et non plus
matérielle (ex: swi OS_Mouse (&EF00001C)
renvoit, sous RISC OS, les coordonnées de la souris et
l'état des boutons dans les registres
r0 à r2). De toute évidence
ces dernières modifications sont désirées...Tous les autres registres sont utilisés comme registres de donnée ou d'adresse, librement. Les registre peuvent être "dédoublés" dans les commutations de mode, ce qui permet de ne pas avoir à sauver puis restaurer le contexte sur/depuis une pile (procédé de fenêtrage des registres).
lsl : Logical Shift Left.add r0,r1,r2,lsl #2 ::
r0:=r1+r2*(2**2)=r1+r2<<2lsr : Logical shift Right.add r0,r1,r2,lsr r3 ::
r0:=r1+r2/(2**r3)=r1+r2>>r3asl : Arithmetic Shift Left.asl est un synonyme de lsl. Il est
préférable d'utiliser le mnémonique
lsl à la place.asr : Arithmetic Shift Right.asr #%1001,#1 donnerait le résultat : #%1100ldr r14,[r8,r9 asr #2] ::
r14:=contenu de (r8+r9/4).ror : ROtate Right.add r0,r0,r1,ror #1 :: r0:=r0+(r1>>>1+
(r1 ET 1)<<31)rol n'existe pas, il faut utiliser cette
instruction avec (32-n) rotations pour l'émuler.rrx : Rotate Right eXtended.add r0,r1,r2,rrx :: r0:=r1+(r2|c)>>>1+
c<<32)and : AND.and r0,r1,r2 :: r0:=r1 ET r2orr : ORr.orr r0,r1,r2 :: r0:=r1 OU r2or.bic : BIt Clear.bic r0,r1,#15 :: r0:=r1 ET NON #15 = r1 ET #&FFFFFFF0
.eor : Exclusive OR.eor r0,r1,r2 :: r0:=r1(+)r2
tst : TeST.tst r1,#3 :: r1 ET #3, bits d'état
N et Z mis en place selon le résultat.teq : Test EQuality.teq r0,r1 :: r0(+)r1, bits d'état
N et Z mis en place selon le résultat.
Le bit C est mis en place par le décalage
éventuel.cmp : CoMPare.cmp r0,r1 :: r0-r1, bits d'état
N et Z mis en place selon le résultat.
Les bits C et V sont mis en place par l'ALU.cmn : CoMpare Negative.cmn r0,r1 :: r0+r1, bits d'état
N et Z mis en place selon le résultat.
Les bits C et V sont mis en place par l'ALU.mov : MOVe.mov r0,#0 :: r0:=0mov peut être utile pour les
décalages que l'on n'a pas pu placer dans une autre
instruction. Par ailleurs, mov r0,r0 est l'instruction
conseillée pour ne rien faire, i.e. NOP.mvn : MoVe Not.mvn r0,#0 :: r0:=-1mov.
Attention l'opérande est ici
complémentée, ne pas confondre avec cmn
qui prend l'inverse (i.e. le complément à
deux).add : ADD.add r0,r1,r2 :: r0:=r1+r2sub : SUBstract.sub r0,r1,r2 :: r0:=r1-r2adc : ADd with Carry.adc r0,r1,r2 :: r0:=r1+r2+csbc : SuBstract with Carry.sbc r0,r1,r2 :: r0:=r1-r2-(1-c)rsb : Reverse SuBstract.rsb r0,r1,r2 :: r0:=r2-r1sub, selon la syntaxe précédemment
vue.rsc : Reverse Substract with Carry.rsc r0,r1,r2 :: r0:=r2-r1-(1-c)str : STore Register.strb)
en mémoire.str r0,[r1] :: @r1:=r0str r9,[r2,-r4,asr r5] :: @(r2-(r4>>>r5)):=r9ldr : LoaD Register.strb)
en mémoire.ldr r0,[r1] :: r0:=@r1ldrb r1,[r3],#7 ::
r1:=@r3 (octet) puis r3:=r3+#7stm : STore Multiple.stmia r0,{r1,r3-r7,r14} ::
@r0:=r1 ... @(r0+#24):=r14ldm : LoaD Multiple
Lecture d'un ou plusieurs mots en mémoire.ldmdb r1!,{r0} :: r1:=r1-#4 puis r0:=@r1strh : STore Register Halfword.
ARMv4.strh r0,[r1] :: @r1:=r0 (bits 15 à 0)strh r9,[r2,-r4,asr r5] ::
@(r2-(r4>>>r5)):=r9 (bits 15 à 0)ldrh : LoaD Register with Halfword.
ARMv4.ldr r0,[r1] :: r0:=@r1ldrh r1,[r3],#7 ::
r1:=@r3 (bits 15 à 0) puis r3:=r3+#7ldrsh : LoaD Register with Signed
Halfword. ARMv4.ldr r0,[r1] :: r0:=@r1ldrsh r1,[r3],#7 ::
r1:=@r3 (bits 15 à 0) puis r3:=r3+#7ldrsb : LoaD Register with Signed
Byte. ARMv4ldr r0,[r1] :: r0:=@r1ldrsb r1,[r3],#7 ::
r1:=@r3 (bits 7 à 0) puis r3:=r3+#7mul : MULtiply.mul r0,r1,r2 :: r0:=r1*r2mla : MuLtiply with Accumulation.mla r0,r1,r2,r3 :: r0:=r1*r2+r3umull : Unsigned MULtiplication Long.
ARM 7DM.umull r0,r1,r2,r3
:: r0:=low(r2*r3) et r1:=high(r2*r3)
r0 contient les 32 bits de poids faible du
résultat de la multiplication, r1 les 32 bits
de poids fort.umlal : Unsigned MuLtiplication with
Accumulation Long. ARM 7DM.umlal r0,r1,r2,r3
:: r0:=r0+low(r2*r3) et r1:=r1+high(r2*r3)
r0 contient les 32 bits de poids faible du
résultat, r1 les 32 bits de poids fort.smull : Signed MULtiplication Long..
ARM 7DMsmull r0,r1,r2,r3
:: r0:=low(r2*r3) et r1:=high(r2*r3)
r0 contient les 32 bits de poids faible du
résultat, r1 les 32 bits de poids fort.smlal : Signed MuLtiplication with Accumulation
Long. ARM 7DM.smlal r0,r1,r2,r3
:: r0:=r0+low(r2*r3) et r1:=r1+high(r2*r3)
r0 contient les 32 bits de poids faible du
résultat, r1 les 32 bits de poids fort.b : Branch.b routine :: pc:=@routinepc comme destination.bl : Branch with Link.pc dans r14.bl routine :: r14:=pc puis pc:=@routinecdp :
Coprocessor Data Processing (..?.).cdp 2,3,c0,c1,c2
:: opération 3 du coprocesseur 2 avec ses registres
c0, c1 et c2.ldc : LoaD Coprocessor register.ldc 4,c1,[r1,#8] :: c1:=@(r1+8) pour le
coprocesseur 4stc : STore Coprocessor register.stc 5,c2,[r3,#42] :: @(r3+42):=c2 pour le
coprocesseur 5mcr : Move Register to Coprocessor.mrc 12,5,r0,c4,c5 :: traitement de r0 par le
coprocesseur 12mrc : Move Coprocessor word to
Register.mcr.mcr 15,0,r3,c0,c0 :: r3:=ID processeurswi : SoftWare Interupt.swi LeJoliModuleQueJ'aiInstalléMoiMême
:: appelle une routine système ou d'un module.pc l'adresse d'une
routine de décodage du numéro de swi.
Cette routine trouvera le module correspondant au numéro
demandé et y sautera.
Le registre r15 sera sauvé
dans r14_svc, registre de lien du mode superviseur,
pour pouvoir retourner au programme appelant. Aucun registre
utilisateur n'est donc modifié de façon
matérielle.swp : SWaP. ARM 3 et
cores suivants (dont l'ARM 2AS).swp r0,r1,[r2] :: 9 r0:=@r2 puis @r2:=r1swp est,
pour un ARM 2, une instruction indéfinie
(voir plus loin).msr : Move Register to Status register
ARM 6 et cores suivants.mcr.msr CPSR_ctl, r0 :: modifie un bit du registre
d'état courant selon le contenu de r0CPSR référence
le mode courant, SPSR le mode
privilégié courant.mrs : Move Register to Status register
ARM 6 et cores suivants.mcr.mrs r0, CPSR :: r0:=registre d'état courant
msr.
La syntaxe et le nombre d'instructions peuvent être
déroutants au début, surtout si vous avez
déjà programmé en assembleur CISC avec l'ordre des
registres inversé.
Il faut de plus savoir que le processeur ARM travaille en
Little Endian, c'est-à-dire qu'il stocke les mots en
mémoire en commençant par l'octet de poids faible pour
arriver à celui de poids fort. Ainsi, si r0=#&FF000102
est stocké en mémoire, on trouvera, dans cette case
mémoire la valeur #&020100FF. Pour les curieux, les processeurs
ARM sont capables de travailler dans les deux modes fréquemment
rencontrés : le big et little endian.
Pour programmer l'ARM, il faut d'abord s'imprégner de la
"philosophie" de ses concepteurs. Ensuite penser très fort
à ce que l'on désire programmer. Enfin, on peut respirer
et aller se coucher.
Plus sérieusement, la puissance de ce processeur réside
dans sa simplicité. Tout algorithme programmable avec un CISC peut
se coder avec ce RISC (je ne l'ai pas démontré). Cela
peut parfois prendre plus de temps. Parfois moins.
Exemple : avez-vous remarqué qu'il n'existe pas d'instruction de division ?
QUOI!! Comment procède-t-on alors ?
On doit émuler cette instruction à l'aide de celles qui
sont à notre disposition :
From: zrzm0370@rusmv1.rus.uni-stuttgart.de (Joerg Scheurich)
Subject: integer division
Date: 10 Jun 91 11:25:36 GMT
div-short:
----------
; division routine
; 1. calculate flag if result is negate and convert operands to positiv
; 2. second "divide" with unsigned suczessive Approximation
; 3. fix the sign of result
.MACRO INTdivide
LDR R2,%2
LDR R3,%3
MOV R0,#0
CMP R2,#0
RSBLT R2,R2,#0
SUBLT R0,R0,#1
CMP R3,#0
RSBLT R3,R3,#0
MVNLT R0,R0
STR R0,minusflag
MOV R0,#32.
MOV R1,#0
\loop ADDS R2,R2,R2
ADCS R1,R1,R1
CMP R1,R3
SUBGE R1,R1,R3
ADDGE R2,R2,#1
SUB R0,R0,#1
CMP R0,#0
BNE \loop
LDR R0,minusflag
CMP R0,#0
RSBNE R2,R2,#0
STR R2,%1
.ENDM
Ce qui fait beaucoup d'instructions et prend jusqu'à 382 cycles sur les anciens processeurs ARM2, le tout en 100 octets et 4 registres. Il existe une méthode plus rapide qui prend alors de 32 à 116 cycles selon les cas, en 452 octets et 4 registres, toujours sur le même processeur (devenu très lent selon les critères actuels puisqu'il est seulement un peu plus rapide qu'un i386...).
Voilà, vous avez vu l'exemple du pire cas possible dû au
jeu d'instructions réduit d'un processeur RISC. Ce cas est
extrêmement rare. La plupart des programmes assembleur ne font
jamais appel à une instruction de division.
Les autres assez rarement, très peu le font souvent comme un
ray-tracer, qui nécessite alors l'adjonction d'une FPU pour le
calcul sur les flotants.
Pour être honnête, la FPU développée par ARM
est nulle selon les critères actuels puisque elle ne permet de
monter que jusqu'à 5Mflops. Pour le calcul intense sur flotants,
une solution Acorn est idiote. Mieux vaut acheter une machine à
base de PowerPC ou de 68060, mais le prix n'est pas le même...
PC
Les opérations que nous venons de décrire ne modifient
pas - excepté celles dont c'est le seul rôle comme cmp
ou les décalages (dans certains cas) - les bits du
registre d'état.
usr : user, le mode utilisateur dans lequel les
programmes communs fonctionnent.svc : supervisor, le mode superviseur dans
lequel les appels système (swi) sont
exécutés.irq : Interrupt Request, le mode interruption
dans lequel des processus de contrôle fonctionnent.fiq : Fast Interrupt Request, le mode
interruption rapide dans lequel des petits processus
fonctionnent.abt : Abort, le mode dans lequel sont
traités les erreurs d'adresse.und : Undefined, le mode dans lequel sont
traités les instructions indéfinies.pc est
codé sur 24 bits :
pc sont
toujours nuls. Il est donc inutile de les stocker. Pour
différencier ces deux familles de mode, on ajoute le suffixe
_32 aux précédents, (pour mode 32 bits). Les modes 26 bits ont un registre r15 très
spécial codé comme suit :

| |||||||||||||
|
8 des 32 bits du pc sont utilisés pour marquer
l'état du processeur. Les quatre bits de poids fort constituent
l'équivalent du CCR (Condition Code Register) du
68000 et les deux bits suivants ainsi que les deux bits de poids faible
l'équivalent du SR (Status Register). On
accède très facilement à toutes les informations,
contrairement à ce que l'on pourrait penser de prime abord.
On pourra appeler les 4 bits de poids fort les bits condition, les deux bits précédents, les bits de masque d'interruption et les 4 bits de poids faible ceux du mode du processeur.
Tous les bits du registre r15 sont accessibles quel que
soit le mode dans lequel on se trouve, exception faite du mode
utilisateur. La commutation de mode est
généralement effectuée à l'aide de
l'instruction teqp, variante de teq, comme
suit :
teqp pc,r0 :: passe en mode utilisateur depuis le mode
superviseur par exemple.
L'espace adressable en mode dit 26 bits est de 2**26=64Mo. Un PMMU permet de dépasser cette limite. Le RiscPC par exemple, muni d'un ARM 610 ou 710, peut gérer jusqu'à 256Mo de RAM, ce qui est bien supérieur aux 64Mo initiaux. Le processeur ARM610 pourrait gérer encore plus de mémoire, théoriquement jusqu'à 2**32=4Go, en mode 32 bits (celui utilisé par RiscBSD l'unix NetBSD pour Acorn).
La manipulation des bits condition est absurde en écriture,
excepté lors de bidouilles infâmes du genre d'une protection
contre le piratage, ce qui n'est pas mon propos. Pourtant, on aimerait
bien les voir changer selon notre désir pour faire des tests par
exemple. Et bien tout cela est possible, facilement et de façon
très puissante, bien supérieure aux CISC classiques. Il est
possible d'ajoindre à presque toutes les intructions
(excepté celles qui, par essence modifient les bits condition et
celles de saut) un suffixe noté 's' qui signifie
Set par exemple. Ainsi, si l'on désire savoir s'il y a eu
débordement lors d'une addition, on écrit :
adds r0,r1,r2
Il nous faut ensuite pouvoir tester ces bits. On pourrait penser que, parce que l'ARM est de technologie RISC, il va nous falloir faire quelque chose du genre :
and r0,pc,#&10000000 ;on masque le bit 28 : oVerflowcmp r0,#&10000000 ;test d'égalitéand r0,pc,#&BitEqual ;le bit Eq ? peut-être Z?...instruction magique ?
mais l'on s'aperçoit qu'il nous manque encore une instruction, pour réagir à la comparaison (ce code est absurde et boucle sur lui même). Je vous dévoile en bloc le tout : chaque instruction (toutes, sauf celles qui sont en opérande) peuvent avoir un suffixe condition. L'instruction est exécutée si la condition est vraie. Ce principe est BEAUCOUP plus puissant que sur un 68000 qui ne permet que les sauts conditionnels.
bvs oVerflowSet
Ainsi, si on veut, par exemple placer 0 dans un registre s'il
y a débordement et sauter à une routine sinon, on
écrit:
adds r0,r1,r2 ;addition qui place les bits CCRmovvs r3,#0 ;annule r3 si débordementbvc AutrePart ;sinon on va ailleursswieq MonModule ;appel routine si résultat nul...
Comme on peut le voir, ce système est très puissant, il permet par exemple de différer l'action par rapport à un test:
bics r0,r1,#3 ;place les deux bits de poids faible;de r1 dans r0ldr r2,[r3,r0 lsl#4];prend le r0ième mot dans; la table pointée par r3bleq TraiteR0Nul ;saute à une routine de;traitement si r0=0blne TraiteR0PasNul ;et à une autre si r0<>0
Il faut bien sûr faire attention à ce que, lors du retour de
TraiteR0Nul, le bit N n'ait pas été
positionné à 1, sinon les deux routines sont
exécutées.
Cependant, comme on l'a vu, le pc est placé dans
r14 lors d'un saut. Donc les bits conditions avec. Pour
revenir d'un sous-programme, on place généralement
r14 dans r15 à la fin de celui-ci, ce qui
restaure le contexte si r14 n'a pas été
modifié entre temps... Dans la pratique c'est très efficace,
mais on utilise plutôt les instructions de rangement multiple de
registre (ldm et stm) afin de sauvegarder la
valeur des registres modifiés.
Les conditions portent les doux noms suivants :
EQ (EQual) MI (MInus) HI (HIgh)
NE (Not Equal) PL (PLus) LS (Less or Same)
CS (Carry Set) VS (oVerflow Set) GE (Greater or Equal)
CC (Carry Clear) VC (oVerflow Clear) LT (Less Than)
GT (Greater Than) LE (Less or Equal)
AL (ALways) NV (NeVer)
Alors, où en est-on ? On sait utiliser une instruction simple comme:
add r0,r1,r2
add r0,r1,r2,lsl#2
On connait aussi le moyen de positionner les bits d'état et utiliser leur résultat. Qu'est-ce qui nous manque, sinon plein de choses ? Réflechissons, généralement un processeur manipule des...registres, oui d'accord mais ces registres contiennent des...nombres, ok, ok, mais ces nombres proviennent de la mémoi...re voilà ! quand on veut on peut. Les accès mémoire. Alors, qu'en sait-on ?
ldr, str s'occupent de l'échange
d'un mot ou d'un octet.
ldm, stm s'occupent de l'échange
d'un ou plusieurs mots.
Bien, mais d'après ce que je sais des systèmes informatiques, on utilise assez souvent en programmation des piles, des tas, des tables, etc. Il nous faut donc un système d'incrémentation (post- ou pré-), qui existe bien entendu. Comme par hasard, c'est un suffixe des instructions ldm et stm. Il existe deux notations différentes, deux façons de voir les choses :
ia (Increment After)
ib (Increment Before)
da (Decrement After)
db (Decrement Before)
Ces quatres suffixes ont le même effet lorsqu'ils sont placés
derrière stm ou ldm.
Exemple:
ldmib r13,{r0} ;place @(r13+4) dans r0
stmib r13,{r1} ;place r1 dans @(r13+4)
L'autre notation, notation "C", représente un niveau
conceptuel plus élevé. En effet, on associe par paires les
suffixes qui vont permettrent de gérer une pile ou un tas à
l'aide de ldm et stm.
fd (Full Descending)
fa (Full Ascending)
ed (Empty Descinding)
ea (Empty Ascending)
Exemple:
stmfd r13!,{r0} ;sauve r0 en mémoire
; votre super code...
; ...
ldmfd r13!,{r0} ;restaure r0 depuis la pile
avec la notation précédente, cela donne :
stmdb r13!,{r0}
; votre hyper code...
; ...
ldmia r13!,{r0}
Chacun ses choix. S'il est plus facile de lire la notation
"C", celle-ci est beaucoup moins parlante quant à ses
effets.
Le symbole "! " indique si le registre doit être ou non
affecté par le déplacement. Il est possible d'écrire
en mémoire avec incrémentation sans que le registre soit
modifié. Ceci n'est pas l'objet d'une pile. Cela peut permettre de
modifier certaines valeurs pointées par un registre sans modifier le
registre pour ensuite lire une de ces valeurs sans calcul de
déplacement. Pourquoi pas...
Cette section regroupe quelques documents issus des sites d'ARM et d'Intel. Ils concernent uniquement les architectures et les composants datant d'après 2000 ou bien reprennent des documents sur le StrongARM avec les logos intel et %s/Digital/Intel/g.
Ces documents sont issus des sites d'ARM et de Digital. Ils concernent les architectures et les composants plus anciens, mais comme très peu de choses ont changé, ils sont de très bons documents de référence, et montrent l'évolution au fil des ans. Ils sont surtout intéressants pour les personnes qui veulent produire du code compatible avec les anciens processeurs.
Quelques documents pour implanter en assembleur des fonctions particulières :
J'apprécie particulièrement la lecture de remarques, corrections et critiques, positives ou négatives, que vous pouvez m'expédier à stan@renan.org.
REMARQUE IMPORTANTE: les renseignements présentés ici ne sont absolument pas garantis exacts. Si vous décelez une erreur, pensez à m'en faire part, merci.
Vous avez été
Retour à l'accueilCopyright © Stanislas Renan 1995-2003 sauf les logos ARM et ARM powered © ARM Ltd.