Forum: Mikrocontroller und Digitale Elektronik STM32 Assembler


von kilaz (Gast)


Lesenswert?

Hi,

ich verwende ein STM32F4 Board mit FreeRTOS und ich versuche gerade, 
mein Assembler etwas zu verbessern.

unsigned int my_pc = 0x08000890;
_asm __volatile_
(
  "movw R1, #0x0fd0\n"
  "movt R1, #0x1000\n"
  "ldr r15,[r1]\n"
);

Ich speichere in my_pc einen gewünschen, neuen Program-Counter. Der Wert 
0x08... ist der PC an der Stelle unsigned int my_pc. Dannach lade ich 
mir diesen Wert in Register R1 - dabei ist 0x10000fd0 die Adresse im 
Speicher, wo my_pc liegt. Nun möchte ich meinen tatsächlichen PC 
abändern, sodass ich erneut bei unsigned int my_pc lande.
Mit gdb habe ich rausgefunden, dass ich R1 nun tatsächlich 0x10000fd0 
steht. Allerdings komme ich hier in den Trap handler:
prvGetRegistersFromStack (pulFaultStackAddress=0x10000f90
Wieso stimmt die Adresse nicht überein?

Verwende ich nun diesen Code, funktioniert mein Vorhaben wie gewünscht:
unsigned int my_pc = 0x08000890;
_asm __volatile_
(
  "movw R1, #0x0fd0\n"
  "movt R1, #0x1000\n"
  "ldr r4,[r1]\n"
  "mov pc,r4\n"
);
Wo liegt hier das Problem?

von Dr. Sommer (Gast)


Lesenswert?

Das unterste Bit der Adresse muss 1 sein, sonst weist du den Prozessor 
an, in den ARM-Modus zu wechseln, was der Cortex-M4 nicht kann. Ich 
würde dir empfehlen, erstmal nur mit nacktem Assembler anzufangen, weil 
Inline Assembler noch eine ganze Reihe an Tücken hat und auch noch 
schlecht dokumentiert ist.

von Dr. Sommer (Gast)


Lesenswert?

PS: Direkt in den PC eine Adresse zu schreiben ist etwas unüblich und 
hat gewisse Einschränkungen - normalerweise nimmt man dafür die 
Branch-Anweisung "B".

von Jim M. (turboj)


Lesenswert?

Auf einem Cortex-M kann man keinen graden Wert in den PC laden => 
Thumb-Bit muss gesetzt sein, sonst Fault.

In der Version die funktionier muss also noch was anders sein.

Noch eine Kleinigkeit: Der Wert im PC selbst ist grade, wenn man den 
ausliesst. Die "push PC" und BL/BLX Instruktionen handhaben das mit dem 
Thumb Bit korrekt AFAIK (so das man den Wert hinterher einlesen kann, 
Bit 0 hat den Wert 1).

von Dr. Sommer (Gast)


Lesenswert?

Jim M. schrieb:
> In der Version die funktionier muss also noch was anders sein.

Bei manchen Schreib-Operationen auf den PC wird das Thumb Bit ignoriert, 
und der aktuelle Modus beibehalten. Welche das sind kann ich mir aber 
auch nicht merken :)
"B" schaltet nicht um, "BX" schon, und nur letzteres kann man mit 
Registern als Ziel nutzen.

von foobar (Gast)


Lesenswert?

1
unsigned int my_pc = 0x08000890;
2
void foo() {
3
    asm("bx %0"::"r"(my_pc));
4
    //oder
5
    goto *my_pc;
6
}
1
foo:
2
  push  {r7}
3
  add  r7, sp, #0
4
5
  movw  r3, #:lower16:my_pc
6
  movt  r3, #:upper16:my_pc
7
  ldr  r3, [r3, #0]
8
  bx r3
9
10
  movw  r3, #:lower16:my_pc
11
  movt  r3, #:upper16:my_pc
12
  ldr  r3, [r3, #0]
13
  orr  r3, r3, #1
14
  bx  r3

von no asm (Gast)


Lesenswert?

Schon richtig, wenn die Befehle verfügbar sind: unbedingter Sprung, 
sonst Push-Pop.

von Markus F. (mfro)


Lesenswert?

kilaz schrieb:
> unsigned int my_pc = 0x08000890;
> _asm __volatile_
> (
>   "movw R1, #0x0fd0\n"
>   "movt R1, #0x1000\n"
>   "ldr r15,[r1]\n"
> );

Das kann (neben dem schon erwähnten Thumb-Bit) gut gehen oder auch nicht 
(je nachdem, was sonst noch an C-Code aussenrum ist).

Wenn Du dem C-Compiler Register klaust, ohne ihm das mitzuteilen, geht 
das früher oder später schief. Lies' dir das Kapitel "extended asm" im 
gcc-Handbuch aufmerksam durch.

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.