STM32 Assembler

Gast #5496237
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?
Gast #5496248
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.
#5496259
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).
Gast #5496288
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.
Gast #5496301
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
#5496442
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren