Forum: Compiler & IDEs Inline Assembler mit msp430


von Heiko (Gast)


Lesenswert?

Hallo,

ich sitze gerade an einem mini Task-Sheduler und stehe vor einem 
Problem.
Und zwar bekomme ich es nicht hin, einen einer c-Funktion übergebenen 
Funktionspointer aus dem Inline Assembler aufzurufen.

Folgendes führt zu einem Reset:

void start_user_thread(callback_t thread)
{
  asm volatile(
    "pop r3 \n\t"
    "call #activate_sheduler \n\t"
    "call r15 \n\t"
    "call #disable_sheduler \n\t"
...
}

wenn ich den "call r15" durch "thread()" in c ersetze, funktioniert 
alles wunderbar. Das Disassemblieren der funktionierenden Funktion 
zeigt: gcc setzt es genauso um, nur dass er den Pointer aus r15 nach r11 
verschiebt und darauf den call macht. Das will ich aber gerade 
vermeiden, da ich das gesicherte r11 nicht auf dem stack haben will.

Weiss jemand wo hier der Fehler ist?

von Heiko (Gast)


Lesenswert?

Nachtrag:
callback_t ist natürlich als
    void (*callback_t)(void)
definiert.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Fehler würde ich nicht sagen.

Das Argument thread wird anscheinend in einem Register übergeben und 
damit wird auch der call gemacht. Selbst bei Stackübergabe würde wohl 
letztendlich ein Register auftauchen.

Ohne Register wäre eine direkte Adressierung (so wie bei 
activate_sheduler/disable_sheduler) nötig, aber dann müsstest du zur 
Compilezeit bereits die Adresse der Callbackfunktion kennen und nicht 
erst zur Laufzeit übergeben.

Ich könnte mir ein hässliches (;-) Gefummel mit indirekter Adressierung 
vorstellen, wenn du eine (oder mehrere ggf. ein Array von...) globale 
Variable (callback_t * pthread) benutzt und kein Funktionsargument.

von Heiko (Gast)


Lesenswert?

Verstehe deine Antort nicht so ganz.
Der Pointer wird in einem Register übergeben (r15) - Das soll auch so 
sein.
Allerdings kann ich die Adresse des Pointers nicht per InlineAssembler 
aufrufen. Wenn ich das per c mache, kommt exakt der gleiche 
Maschinencode dabei raus, aber es funktioniert...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Also deine Problemstelle sieht nicht so aus, wie du oben im asm-Code 
angegeben hast?

Ich bin von obiger Stelle davon ausgegangen, dass du die Stelle durch so 
was ähnliches Ersetzen willst:

void start_user_thread(callback_t thread)
{
  asm volatile(
    "pop r3 \n\t"
    "call #activate_sheduler \n\t"
    "call #thread \n\t"
    "call #disable_sheduler \n\t"
...
}

Jetzt nach deiner Antwort reime ich mir deine Problemstelle so zurecht

void start_user_thread(callback_t thread)
{
  // "Unsichtbar"
  // 1/ thread steht im Argumentregister r15
  // 2/ Arbeitsregister r11 wird auf Stack gesichert
  // 3/ Argumentregister r15 wird in Arbeitsregister r11 kopiert

  asm volatile(
    "pop r3 \n\t"
    "call #activate_sheduler \n\t"
    "call r11 \n\t"
    "call #disable_sheduler \n\t"
...
}

Du hättest aber gerne die von dir angegeben ASM-Fassung ohne das 
Kopieren nach r11?

Wenn das so ist, könntest du mit der erweiterten Argumentliste des asm() 
Statements arbeiten.
http://mspgcc.sourceforge.net/manual/c1308.html

void start_user_thread(callback_t thread)
{
  asm volatile(
    "pop r3 \n\t"
    "call #activate_sheduler \n\t"
    "call %threadreg \n\t"
    "call #disable_sheduler \n\t"
    :
    : [threadreg] "r" (thread)
  );
}

BTW: Wird im Rest der start_user_thread() noch auf das Argument thread 
zugegriffen, so dass der GCC zwangsläufig auf die Idee mit dem 
Arbeitsregister r11 kommen muss?

von Heiko (Gast)


Lesenswert?

Das oben gepostete Stück code ist von mir und führt aber anstelle des 
Springens in thread() direkt zum Reset.

Wenn ich es durch:

void start_user_thread(callback_t thread)
{
  asm volatile(
    "pop r3 \n\t"
    "call #activate_sheduler \n\t"
    )
     thread();
     asm volatile(
    "call #disable_sheduler \n\t"
...
}

ersetze, wird zwar in thread gesprungen, aber da gcc diesen Sprung nicht 
direkt über das Parameterregister r15 erledigt, sondern nach r11 kopiert 
und r11 sichert, sieht der Stack danach nicht so aus wie ich ihn 
brauche.
Da der funktionierende c-Code im disassembler exakt so wie der nicht 
funktionierende Assemblercode aussieht (selbst wenn ich auch r11 pushe), 
gehe ich mitlerweile von irgendeinem Linker Problem aus...

Den geposteten Link werde ich mir auf jeden Fall mal angucken. Danke 
dafür!

Auf thread wird nicht mehr zugegriffen, weshalb mir auch nicht klar ist, 
warum erst nach r11 kopiert wird.

von Heiko (Gast)


Lesenswert?

hab den Fehler gefunden: Obwohl parameterlos und zweizeilig hat 
activate_sheduler() r15 als arbeitsregister missbraucht...

Jetzt sieht der code folgendermaßen aus:

        "pop r3 \n\t"
  "push r15 \n\t"
  "call #activate_sheduler \n\t"
  "pop r15 \n\t"
  "call r15 \n\t"
  "call #disable_sheduler \n\t"
         ...

und läuft perfekt, bzw unterbricht und schaltet um - wie es sich für nen 
Taskswitcher gehört ;-)
Werde das ganze aber trotzdem auf die etwas portablere Syntax aus deinem 
Link umstellen.

Vielen Dank!
Heiko

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.