mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ARM Assembler-Frage


Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

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

Grüße
Erik

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ldr r0,=0x12345678

Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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/i...)

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

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

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

Matthias

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marius Schmidt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vikinger (Gast)
Datum:

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

Erik

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

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

Matthias

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

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

Matthias

Autor: A.K. (Gast)
Datum:

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

Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

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

Autor: Vikinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die klaren Antworten, bin heute definitiv schlauer geworden.

Grüße
Erik the Vikinger

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?
        mov   r0,#0                     // no arguments (argc = 0)
        mov   r1,r0
        mov   r2,r0
        mov   fp,r0                     // null frame pointer
        mov   r7,r0                     // null frame pointer for thumb
        ldr   r10,=main
        mov   lr,pc
        bx    r10                       // enter main()

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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/

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Urs (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.