News   Magazin   Börse   Links   ArcArchie   Homepages
 Magazin  Beschreibung des ARM Prozessors Home 
Hardware   Software   Praxis   Sonstiges  
Kurze Beschreibung des ARM Prozessors  von Michael Kircher

Der Artikel ist ursprüglich in der C-F 4/99 in einer Assemberrubrik erschienen.
Da in dieser Rubrik der ARM Prozessor bereits öfter angesprochen wurde, folgt nun eine kurze Beschreibung, die sich im wesentlichen auf die Integerbefehle des ARM2/3 beschränkt. Über Coprozessor-Befehle lassen sich auch eine FPU und die MMU ansprechen. Den Vergleich mit Intels x86'ern, den Motorola 68K Prozessoren oder dem 65xx mag jeder gern selbst ziehen ...


Registermodell und Betriebsmodi:

Der ARM ist ein 32 Bit RISC Prozessor. Er hat 16 Register, bezeichnet mit R0 bis R15. Diese sind i.A. frei verwendbar, mit zwei Ausnahmen: R15 enthält den Program-Counter (PC) zusammen mit dem Processor-Status-Register (PSR) wie folgt:

Bit 31: N Flag (Negative Flag)
Bit 30: Z Flag (Zero Flag)
Bit 29: C Flag (Carry Flag)
Bit 28: V Flag (Overflow Flag)
Bit 27: I Flag (Interrupt disable)
Bit 26: F Flag (Fast Interrupt disable)
Bit 25-2: PC
Bit 1 : M1 Flag (Bit 1)
Bit 0 : M0 Flag (Bit 0)

R14 erhält bei einem Unterprogrammsprung die Rücksprungadresse zusammen mit einer Kopie des PSR. Ansonsten kann das Register frei verwendet werden.

Der Wert in M1, M0 bestimmt den Betriebsmodus der CPU. Alle nicht User-Modi sind privilegiert, dürfen die Interrupt-Flags, sowie den Betriebsmodus ändern und verfügen über eigene Kopien einiger Register (in Klammern angegeben):

0: USR: User Mode
1: FIQ: Fast Interrupt Mode (R8-R14)
2: IRQ: Interrupt Mode (R13,R14)
3: SVC: Supervisor Mode (R13,R14)

Sobald eine Exception auftritt, kopiert der ARM die Rücksprungadresse in das R14 des jeweiligen privilegierten Modus, R14_usr wird also nicht überschrieben. Da von R13 ebenfalls eigene Exemplare in den verschiedenen Modi existieren, wird R13 vereinbarungsgemäß als Stackpointer benutzt.


Befehlsausführung:

Jeder Befehl des ARM ist konditioniert ausführbar. Dazu wird hinter dem Opcode der Conditioncode angehängt, von denen es 16 gibt:

NE: Z=0 (ungleich)
EQ: Z=1 (gleich)
PL: N=0 (positiv)
MI: N=1 (negativ)
CC: C=0 (kein Übertrag)
CS: C=1 (Übertrag)
VC: V=0 (kein Überlauf)
VS: V=1 (Überlauf)
AL: (immer; ist Vorgabe)
NV: (niemals)
LS: (niedriger oder gleich)
HI: (höher)
LT: (kleiner als)
GE: (größer als, oder gleich)
LE: (kleiner als, oder gleich)
GT: (größer als)

AL ist Default und kann weggelassen werden. Für CC oder CS kann auch LO oder HS gesetzt werden, zusammen mit LS und HI beziehen sie sich auf das Ergebnis eines nicht-vorzeichenbehafteten Vergleichs. LT, GE, LE und GT hingegen beziehen sich auf einen Vorgleich zweier vorzeichenbehafteter Zahlen! Einem Nicht-Vergleichsbefehl, der auf der Arithmetisch-Logischen Einheit (ALU) ausgeführt wird, steht es frei, das PSR dennoch zu beeinflussen. In diesem Fall hängt man ein S an den Conditioncode. Arithmetische Befehle setzen N, Z, C, V, logische Befehle nur N, Z, und C vom Shifter, V bleibt unverändert.


Befehlsvorrat:

Die Mnemonics der 25 Grundbefehle leiten sich durch Zusammenziehen der Großbuchstaben in den nachfolgend ausgeschriebenen Formen ab: ADD, ADd with Carry, SUBtract, SuBtract with Carry, Reverse SuBtract, Reverse Subtract with Carry, AND, OR Register, Exclusive OR, BIt Clear, MOVe, MoVe iNverted, CoMPare, CoMpare Negated, Test EQuivalence, TeST bits, MULtiply, MuLtiply and Add, LoaD Register, STore Register, LoaD Multiple registers, STore Multiple registers, Branch, Branch and Link, SoftWare Interrupt.


Befehlsformat:

Der ARM ist eine Drei-Operanden Maschine. Sämtliche datenverarbeitenden Befehle arbeiten nur auf den Registern. Von den beiden Quell-Operanden kann <shift> vor der eigentlichen Verarbeitung durch die ALU noch durch einen Barrel-Shifter geleitet werden.

Syntax: Opcode <dest>,<reg>,<shift>

Als <dest> und <reg> können alle Register von R0 bis R15 angegeben werden. <shift> kann ebenfalls ein einfaches Register, aber auch ein konstanter Wert, oder ein geshiftetes Register sein, wobei hier das Quellregister NICHT verändert wird. Es sind allerdings nicht alle konstanten Werte zulässig, denn sie werden aus einer 8-Bit Konstante gebildet, die anschließend um eine gerade Anzahl an Stellen im 32-Bit Word nach rechts rotiert wird. Damit kann <shift> folgende Formen annehmen:

<shift> := <reg>
<shift> := #imm
<shift> := <reg>,<Shift-Opcode> #imm
<shift> := <reg>,<Shift-Opcode> <reg>
<shift> := <reg>,RRX


Schiebebefehle:

LSL: Logical Shift Left
LSR: Logical Shift Right
ASR: Arithmetic Shift Right
ROR: Rotate Right
RRX: Rotate Right Extended

RRX schiebt nur um eine Stelle, und benutzt das Carry-Flag als Bit 33!


Datenverarbeitende Befehle:

ADD, ADC, SUB, SBC, RSB, RSC,
AND, ORR, EOR, BIC - Syntax:
Opcode<cond><S> <dest>,<reg>,<shift>

MOV, MVN - Syntax:
Opcode<cond><S> <dest>,<shift>

CMP, CMN, TEQ, TST - Syntax:
Opcode<cond><S|P> <reg>,<shift>

MUL<cond><S> <dest>,<reg>,<reg>
MLA<cond><S> <dest>,<reg>,<reg>,<reg>

Hierzu einige Anmerkungen: RSB und RSC sind Reverse-Subtract - da <shift> flexibler ist, macht es Sinn, die Subtraktion auch in die umgekehrte Richtung ausführen zu können. MVN invertiert sämtliche Bits, bevor es das Ergebnis des Shifts in das Zielregister kopiert. BIC entspricht AND NOT. CMP, CMN, TEQ, TST führen nominell die Befehle SUB, ADD, EOR und AND aus, verwerfen aber das Ergebnis. S braucht daher bei den Vergleichsbefehlen nicht angegeben zu werden, da deren Sinn es ja gerade ist, die Flags zu beeinflussen. Wird dagegen P angegeben, so wird das (ansonsten ja weggeworfene) Ergebnis des Vergleichs DIREKT in das PSR kopiert! MUL und MLA haben die Einschränkung, daß <dest> nicht PC oder gleich dem ersten Quelloperanden sein darf.


Transportbefehle:

LDR, STR - Syntax:
Opcode<cond><B> <reg>,[<base>]
Opcode<cond><B> <reg>,[<base>,±<offset>]
Opcode<cond><B> <reg>,[<base>],±<offset>


B spezifiziert einen Bytezugriff. Wenn B nicht angegeben wurde, muß die berechnete Adresse durch 4 teilbar sein. In der prä-indizierten Form schreibt ein Ausrufezeichen hinter der eckigen Klammer das Ergebnis der Adreßberechnung nach <base> zurück. Dieses erfolgt bei post-indexed automatisch. In der post-indizierten Form kann dem Gesamtopcode noch ein T angehängt werden. Dies simuliert in privilegierten Modi einen User-Mode Zugriff.

<reg> und <base> sind wie in den ALU-Befehlen die Register R0 bis R15. <offset> kann ähnlich wie <shift> ein einfaches Register, eine Konstante, oder ein geshiftetes Register sein. Im Unterschied zu den ALU-Befehlen sind als konstante Werte nur die Zahlen 0 bis 4095 zulässig. Außerdem darf bei den Schiebebefehlen die Größe des Shifts nicht mehr durch den Inhalt eines weiteren Registers angegeben werden.

LDM, STM - Syntax:
Opcode<cond><type> <base>,{<reg_list>}

<reg_list> ist eine komma-separierte Liste aller Register, die transportiert werden sollen. Die Reihenfolge spielt keine Rolle, und man kann mehrere aufeinanderfolgende Register auch durch einen Bindestrich zusammenfassen. Es werden immer die Register mit der niedrigsten Nummer zuerst transportiert!

<type> gibt an, wie <base> bei jedem Transport verändert werden soll. Bei einfachen Block-Zugriffen wählt man <type> aus:

IA: Increment After
DA: Decrement After
IB: Increment Before
DB: Decrement Before

Da für Stack-Zugriffe zwei verschiedene Typen erforderlich sind, je nachdem, ob man LDM oder STM ausführt, kann man mit <type> auch die Art des Stacks angeben:

EA: Empty Ascending
ED: Empty Descending
FA: Full Ascending
FD: Full Descending

Empty bedeutet, der Stackpointer zeigt auf das nächste freie Element im Stack. Full bedeutet, der Stackpointer zeigt auf das letzte abgelegte Element. Descending, Ascending bedeuten, der Stack wächst nach unten oder nach oben.

Soll <base> nach Ausführung des Befehls ge-updated werden, so muß ein Ausrufezeichen hinter <base> gesetzt werden.

Hinter der geschweiften Klammer der Register-Liste kann noch ein Hoch-Zeichen (^) stehen: Falls bei LDM der PC in der Register-Liste steht, wird dann das PSR ebenfalls beschrieben (bei STM wird es allerdings immer abgespeichert). Wenn in privilegierten Modi bei LDM und STM der PC nicht in der Liste steht, erfolgt der Zugriff nicht auf die Kopien von (R8-R12 im FIQ Mode,) R13 und R14, sondern auf die ursprünglichen User-Mode Register!


Sprungbefehle:

B, BL - Syntax:
Opcode<cond> <adr>

B springt direkt nach <adr>, BL kopiert vorher noch die Adresse des nächsten Befehls, zusammen mit einer Kopie des ursprünglichen PSR, nach R14. Der Rücksprung erfolgt mit Hilfe eines arithmetischen Befehls (s.u.)

SWI<cond> <nr>

Betriebssystemaufruf: Es wird die Routine <nr> aufgerufen, <nr> kann von 0 bis 16777215 gewählt werden.


Besondere Eigenarten von R15:

R15 als Zieloperand von ALU-Befehlen: Falls S nicht angegeben wurde, wird nur der PC beschrieben, ansonsten sowohl PC als auch PSR. Der Rücksprung aus einer Unterroutine, die mit BL aufgerufen wurde, kann daher einfach durch MOV PC,R14 ohne, oder MOVS PC,R14 mit Wiederherstellung des ursprünglichen PSR erfolgen.

R15 in LDR: es wird nur der PC geladen, das PSR nicht.

R15 in STR: (sehr selten) - PC+PSR werden geschrieben.

R15 als Operand 1 in ALU-Befehlen oder als Base in LDR|STR: Es sind nur die Bits 2-25, also nur der eigentliche PC sichtbar. Gelesen wird aufgrund von Pipelining immer die Adresse des übernächsten Befehls! In den Transport-Befehlen sollte vom Rückschreiben in den PC abgesehen werden, da das Resultat undefiniert ist!

R15 als Operand 2 in ALU-Befehlen, Offset in LDR|STR (sehr selten) oder in der Registerliste von LDM|STM: Es sind PC und PSR sichtbar. Auf älteren ARMs wird bei STM der Wert von PC+12, auf neueren allerdings PC+8 gespeichert! Man sollte sein Programm also so schreiben, daß es mit beiden Fällen zurechtkommt.

Nicht verwenden sollte man R15 als Ziel von MUL|MLA, als Quelle der Shift-Anzahl und als <base> von LDM|STM. Auch hier sind alle 32 Bits sichtbar, was zu einem Address Exception Error führt, es sei denn, alle Flags sind gelöscht und alle Interrupts sind erlaubt.


Die Hardwarevektoren:

&00000000: ARM Reset
&00000004: Undefined Instruction
&00000008: Software Interrupt (SWI)
&0000000C: Prefetch Abort
&00000010: Data Abort
&00000014: Address Exception
&00000018: IRQ Vector
&0000001C: FIQ Vector

Diese springt der ARM im Supervisor-, die Interruptvektoren im jeweiligen Interrupt-Modus an. FIQ zeichnet sich insofern noch aus, als daß die zugehörige Routine nicht erst noch durch einen Befehl bei &1C angesprungen wird, sondern direkt dort beginnt! Zusammen mit der großen Anzahl eigener Register sorgt dies für eine sehr schnelle Bearbeitung der anfallenden Aufgabe.
Hardware   Software   Praxis   Sonstiges  
ArcSite   News   Magazin   Börse   Links   ArcArchie   Homepages