mikrocontroller.net

Forum: Compiler & IDEs Inline Assembler mit msp430


Autor: Heiko (Gast)
Datum:

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

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:
callback_t ist natürlich als
    void (*callback_t)(void)
definiert.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Autor: Heiko (Gast)
Datum:

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Autor: Heiko (Gast)
Datum:

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

Autor: Heiko (Gast)
Datum:

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

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.