Forum: Mikrocontroller und Digitale Elektronik ARM Assembler-Frage


von Vikinger (Gast)


Lesenswert?

Hallo,

wie lade ich auf ARM7 eine 32Bit Konstante in ein Register??
Ich finde einfach keinen passenden Befehl dafür.

Grüße
Erik

von A.K. (Gast)


Lesenswert?

ldr r0,=0x12345678

von Vikinger (Gast)


Lesenswert?

so einen Befehl gibt es nicht,
jedenfalls nicht im "ARM Instruction Set Quick Reference Card v2.1"
('QRC0001H_rvct_v2.1_arm.pdf' von
<http://www.arm.com/documentation/Instruction_Set/index.html>;)

dort gibt es "LDR{cond} Rd,<a_mode2>" (Seite 4)
und in der Tabele "Addressing Mode 2" (Seite 5) gibts kein
32Bit-Wert

schein auch logisch da die Befehle ja offensichtlich nur 32Bit gross
sind

Also wie bekomme ich eine 32Bit-Konstante in ein Register ??

Grüße
Erik

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

ldr wird zumindest vom ARM-Assembler verstanden und je nach Konstante
in unterschiedliche Befehle "übersetzt".

Matthias

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

ich sollte noch ergänzen dass das LDR dann durchaus zu einem
zusätzlichen 32 Bit Wort führen kann. Die Konstante wird dann als Wert
im Programm abgelegt und per relativer Adressierung zum PC in ein
Register geladen. Ein LDR kann also zu zwei 32 Bit Wörtern führen. Der
Opcode selbst und die Konstante.

Matthias

von Vikinger (Gast)


Lesenswert?

> Ein LDR kann also zu zwei 32 Bit Wörtern führen.
> Der Opcode selbst und die Konstante.
also so ein Doppel-Word-Befehl wie bei AVR oder PIC üblich?
Braucht der dann auch 2 Tackte für seine Abarbeitung?
Ich kann mir das noch nicht so richtig vorstellen weil in der
"Quick Reference" sowas einfach nicht drin steht,
gibts da vielleicht was besseres (mit mehr als 6 Seiten) ??

Grüße
Erik the Vikinger

von Marius Schmidt (Gast)


Lesenswert?

Das steht in der quick reference nicht drin weil das ein macro ist
welches das Laden von konstanten vereinfacht - kann sein das es bei
anderen assemblers anders heißt bzw aussieht.

von Vikinger (Gast)


Lesenswert?

> weil das ein macro ist
okay, aber wie mache ich das mit echten Assemblerbefehlen?

Erik

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

das ist kein klasicher 2 Zyklen Befehl wie man ihn von anderen
Prozossoren kennt. ARMs sind näher am RISC-Konzept als z.B. die AVRs
und haben wirklich nur eine Befehlswortlänge von 32 Bit.

Mit "richtigen" ARM Assemblerbefehlen kannst du keine beliebigen 32
Bit Konstanten in ein Register laden. Du mußt im Prinzip das Verhalten
des ARM-Assemblers imitieren und eine Konstante an einer Adresse
ablegen und diese dann mit einem Befehl laden.

Matthias

von Vikinger (Gast)


Lesenswert?

> eine Konstante an einer Adresse ablegen
> und diese dann mit einem Befehl laden
aber die Adresse vor der Speicherstelle ist doch auch wieder eine
32Bit-Konstante?

für "ldr r0,[r1]" muss ich doch auch wieder r1 mit etwas sinvollem
laden

Grüße
vom grübelnden Erik

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

das Register kann aber auch der PC (IIRC R15) sein.

Matthias

von A.K. (Gast)


Lesenswert?

Der übliche Weg: Die Konstanten werden irgendwo im Umkreis von +/- 4KB
um den aktuellen PC herum abgelegt. Geladen werden sie dann mit
        LDR Rx, [PC, #Distanz]

Um das etwas zu vereinfachen, versteht mindestens der GNU-Assembler
auch die Kurzform
        LDR Rx, =Konstante
Die Konstante (engl: literal) merkt sich der Assembler im "literal
pool" und plaziert dessen angesammelten Inhalt im Speicher, wenn das
Statement ".pool" bzw ".ltorg" kommt, oder am Ende vom Quelltext.

von Vikinger (Gast)


Lesenswert?

Aha, wieder was neues gelernt.

Aber wenn ich eine Function, größer als 8kB, hab dann klappt das in der
Mitte nicht mehr, oder?? Da müsste ich dann in die Function gebenenfalls
eine Lücke, dort dann ein ".pool" rein, einbauen und diese
überspringen.

Hab ich das jetzt richtig verstanden?

Grüße
Erik

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

genau. Aber 8k große ARM-Assemblerfunktionen sprich 2k Befehle? Das ist
dann doch schon sportlich :-)

Matthias

von A.K. (Gast)


Lesenswert?

Irgendein Loch findet sich immer. Wenn Du Code findest, in dem
hintereinenander ohne unbedingten Sprungbefehl dazwischen 8KB Code
stehen...

von Vikinger (Gast)


Lesenswert?

Zwei Zusatzfragen hab ich dann aber doch noch zu dieser relativen
Adressierungsart :

wie kommt ihr auf die "+/- 4KB"?

im PDF steht "[Rn,#+/-<immed_12>]"
bedeutet das das im Opcode das Vorzeichen (bzw. die Info ob "+" oder
"-") zusätzlich zu dem 12Bit-Immed drin ist oder wird dafür das
oberste Bit vom Immed benutzt?

Was ist mit den unteren 2 Bits, müssen die immer 0 sein?
Wenn ja dann könnte man doch den Immed immer unm 2 Bits nach links
schieben und so den addressierbaren Bereich vervierfachen.

Grüße
Erik

von A.K. (Gast)


Lesenswert?

12-Bit ohne Vorzeichen, separates Bit für Addition/Subtraktion, also
Distanz -4095..+4095. Rechtsbündig, also nicht geschoben.

von Vikinger (Gast)


Lesenswert?

Danke für die klaren Antworten, bin heute definitiv schlauer geworden.

Grüße
Erik the Vikinger

von Thomas (Gast)


Lesenswert?

ich schließ mich mal bei dem Thread an, ich hab nämlich auch gerade ein 
Problem und zwar mit dem Sprung vom Initialisierungscode zu meiner C 
main Routine. Das ASM Fragment stammt aus einem anderen Programm, wo 
=main kleiner als 12 Bit war. Nur jetzt ist im ersten Segment noch ein 
Bootloader davor und meine main Routine liegt nun auf 0x2528h, wenn ich 
das jetzt so mache wird natürlich alles über 12Bit weggeschnitten und 
ich springe auf 0x529h soweit so gut.

Irgendwie sollte das ja auch relative zum PC addressiert werden können 
dieser steht hier ca bei 0x20F0h aber wie?

Leider bin ich in Assembler nicht wirklich fit, wie könnte eine einfache 
Lösung für mein Problem aussehen?
1
        mov   r0,#0                     // no arguments (argc = 0)
2
        mov   r1,r0
3
        mov   r2,r0
4
        mov   fp,r0                     // null frame pointer
5
        mov   r7,r0                     // null frame pointer for thumb
6
        ldr   r10,=main
7
        mov   lr,pc
8
        bx    r10                       // enter main()

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Thomas wrote:
> Das ASM Fragment stammt aus einem anderen Programm, wo =main kleiner
> als 12 Bit war. Nur jetzt ist im ersten Segment noch ein Bootloader
> davor und meine main Routine liegt nun auf 0x2528h, wenn ich das
> jetzt so mache wird natürlich alles über 12Bit weggeschnitten und
> ich springe auf 0x529h soweit so gut.

Wieso natürlich ?

> Irgendwie sollte das ja auch relative zum PC addressiert werden können
> dieser steht hier ca bei 0x20F0h aber wie?
>
> Leider bin ich in Assembler nicht wirklich fit, wie könnte eine einfache
> Lösung für mein Problem aussehen?

Genauso. Die Adresse von main wird aus einem literal pool aus 
beliebigen 32bit Werten geladen. Es ist daher völlig egal wo sich main() 
befindet. Der Eintrag im pool muss sich innerhalb von +-4K (+-12bit) 
vom PC befinden. Und dafür sollte der Assembler sorgen.

Es würde möglicherweise helfen, das Disassembly zu sehen. Dann weiß man 
was wirklich aus diesem Code gemacht wurde.

Gruß
Marcus
http://www.doulos.com/arm/

von Martin (Gast)


Lesenswert?

>Mit "richtigen" ARM Assemblerbefehlen kannst du keine beliebigen 32
>Bit Konstanten in ein Register laden. Du mußt im Prinzip das Verhalten
>des ARM-Assemblers imitieren und eine Konstante an einer Adresse
>ablegen und diese dann mit einem Befehl laden.

Es gibt ARM-Befehle, die eine Shift-Operation enthalten. Die genaue 
Syntax habe ich jetzt nicht parat.
Aber damit kann man z.B. einen Wert wie 0x1234000 in ein Register laden.
Im Befehl codiert ist nur die Konstante 0x1234 und eine 12, um die 
Anzahl Bits die Konstante vor dem Laden nach links geschoben wird.
Damit passt der Befehl in 32 bit hinein, die Konstanten sind aber im 
Wertebereich eingeschränkt.

Gruß,
Martin

von Urs (Gast)


Lesenswert?

Also, wenn ich mich richtig erinnere (hab' das letzte mal ARM Assembler 
auf einem Acorn RISC PC benutzt), dann hatte der eingebaute Acorn 
Assembler einen Pseudo-Befehl oder Macro zum Laden von Konstanten in ein 
Register gehabt, und diesen in eine Sequenz von einem MOV gefolgt von 
(je nach Art der Konstante) 0-2 ORR oder AND (evtl auch ADD/SUB/RSB, ich 
weiss das nicht mehr so genau) Befehlen umgesetzt.

D.h. um z.B. &1234567 in R0 zu laden, machte der Assembler im 
schlimmsten Fall sowas wie:
MOV R0, #&12000000
ORR R0, R0, #&230000
ORR R0, R0, #&4500
ORR R0, R0, #&67

(Syntax und Befehle aus'm Kopf.)
Ich glaube, Konstanten bei "echten" ARM Befehlen waren darauf 
beschränkt, dass sie sich aus einer 8 Bit Zahl konstruiert werden, die 
um einen gerade Anzahl an Stellen in dem 32 Bit Zahlenbereich rotiert 
wird.
D.h. MOV R0, #&F000000F geht z.B. auch in einem Rutsch.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.