Forum: Mikrocontroller und Digitale Elektronik C-Funktion per Pointer mit Inline ASM aufrufen


von Henning L. (Gast)


Lesenswert?

Hallo, das obige will ich tun ;) Da die normalen C-Funktionszeiger bei
mir nicht funktioniert haben, wollte ich es per inline asm versuchen.
Nach verschiedenfachem rumexperimentieren funktioniert nun das da:

asm volatile(
"push r16\n\t"
"push r17\n\t"
"mov r16, %0 \n\t"
"mov r17, %1 \n\t"
"movw r30, r16\n\t"
"icall\n\t"
"pop r17\n\t"
"pop r16\n\t"
:: "e" (pointer_lowbyte), "e" (pointer_highbyte));

Allerdings sieht das verdächtig nach überflüssigem Code aus. Das wäre
noch nicht so schlimm. Aber ich traue dem Braten nicht, denn folgende
frühere Version:

asm volatile(
"mov r30, %0 \n\t"
"mov r31, %1 \n\t"
"icall\n\t"
:: "e" (pointer_lowbyte), "e" (pointer_highbyte));

funktionierte zwar zuerst, aber der Kompiler hat unvorhersagbar die
Register durcheinandergewürfelt. Aus einem mov-Kommando macht er
nämlich ein ld (aus der Adresse, die er kennt, in ein Zwischenregister)
und dann ein mov (vom Zwischenregister in das angegebene Zielregister
(z.B.r30)). Als Zwischenregister hat er aber unterschiedliche genommen,
auch mal r30 oder r31, und damit jeweils das andere Byte überschrieben,
was zu sehr merkwürdigen Sprungadressen geführt hat, was auch sonst...

Die obere Funktion funktioniert nun, aber ich frage mich wie lange.
Denn es ist ja immer noch nicht vorgegeben, was der Compiler für ein
Zwischenregister benutzt, und damit kann dasselbe Problem auch oben
auftreten.

Also die Frage: wie rufe ich eine Funktion auf, die durch einen Pointer
adressiert ist (und natürlich keine Übergabeparameter hat)? Bzw. wie
bekomme ich den Pointer sicher in inline asm und führe einen call aus?

Um ehrlich zu sein: ich blicke durch inline asm nicht wirklich durch,
z.B. die echten Auswirkungen der compiler constraints, und das
Geschehen bei Übergabe von Parametern/Variablen sind mir noch etwas
schleierhaft. Vielleicht lässt sich ja die Registerbelegung steuern?
Ich hab mal als Alternative "O" ausprobiert, dachte, das muss er doch
akzeptieren als uint8_t oder so, aber da kamen nur Fehlermeldungen.

Ich hatte noch eine Alternative ausprobiert, und zwar die
Pointervariable an Register zu binden:

register uint8_t pL asm("r3");
register uint8_t pH asm("r4");
...code...
asm volatile(
"mov r30, r3 \n\t"
"mov r31, r4 \n\t"
"icall\n\t" :: );

Aber das binding hat gar nicht funktioniert, die Variablen lagen nicht
in den angegebenen Registern. Habe ich die Syntax auch nicht
verstanden?

Danke schonmal,
Grüße, Henning

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

.

  "Da die normalen C-Funktionszeiger bei
   mir nicht funktioniert haben, "

Was spricht dagegen, genau dieses Problem zu lösen?
Der Versuch, das mit Inline-Assembler zu "emulieren", dürfte aufgrund
der gesteigerten Komplexität noch eher zum Scheitern verurteilt sein.

von Henning L. (Gast)


Lesenswert?

Hallo Rufus,

jedes gelöste Problem ist zwar ein schönes Problem, aber so ists für
meinen Fall praktischer. Ich sitze an einem kompakten Menü, wo jeder
Eintrag u.a. einen Pointer und ein Typ-Flag besitzt. Je nach Typ kann
nun entweder eine Funktion aufgerufen werden, die den Variablentyp
hinter Pointer bearbeitet, oder mit derselben Pointervariable direkt
eine benutzerdefinierte Spezialfunktion. So spare ich mir viele
Bedingungsabfragen. Mit C habe ich da einen Typen-Konflikt (vielleicht
ist avr-gcc aber auch toleranter, muss ich mal probieren).

Zweitens habe ich die Auswahl zwischen 2 Problemen. Das hier hat schon
gezeigt, dass es laufen kann. Ich muss nur einen Weg finden, die
Register unter Kontrolle zu halten.

Daher wollte ich es so probieren...
Die Definition von Funktionszeigern jedenfalls mochte der avr-gcc
bisher nicht (in meinen Versuchen).

von Henning L. (Gast)


Lesenswert?

Ich nehm alles zurück.

Ich hab gestern stundenlang getüftelt.

Eben hab ich in 5 Minuten mal alles auf Funktionszeiger umgeschrieben,
und es läuft auf Anhieb perfekt, problemlos, übersichtlich.

...glaub ich bin überarbeitet... :))

Danke für den Hinweis auf den "normalen Weg zurück"...

Grüße, Henning

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.