Forum: Compiler & IDEs inline-Assembler mit Variablen


von Le X. (lex_91)


Lesenswert?

Hallo,

eher eine theoretische Frage als ein konkretes Problem.

Beim avr-gcc ist es ja oft so, dass wenn man versucht etwas möglichst 
dynamisch zu machen der Compiler schlechter optimieren kann, da ihm zur 
Compile-Zeit wichtige Infos fehlen.
Beliebtes Beispiel ist ja eine Funktion, der ein Port übergeben werden 
soll,  z.B.:

void set_pin(port *, pin);

So eine Funktion erzeugt viel Code im Vergleich zu
PORTA |= (1 << 3);

Der Compiler kann keinen "sbi" Befehl verwenden da er nicht weiß, dass 
der Port (die übergebene Adresse) im I/O-Bereich liegt.
Ebenso muss er eine hässliche Schleife für die Schiebeoperation 
erzeugen.

Aber da ich als Systemprogrammierer ja weiß, dass meine Funktion nur 
Ports (also I/O-Adressen) bekommt (kann man evtl auch prüfen)könnte ich 
doch per Inline-Assembler den "sbi"-Befehl vorgeben.
Leider kenn ich mich mit inline-Assembler sogut wie garnicht aus.

Gibt es eine Möglichkeit so ein Konstrukt zu verwenden:
asm("sbi port, pin");

und die Variablen port und pin im C-Code zu befüllen?

Viele Grüße,
lex

von Karl H. (kbuchegg)


Lesenswert?

le x. schrieb:


> Der Compiler kann keinen "sbi" Befehl verwenden da er nicht weiß, dass
> der Port (die übergebene Adresse) im I/O-Bereich liegt.
> Ebenso muss er eine hässliche Schleife für die Schiebeoperation
> erzeugen.
>
> Aber da ich als Systemprogrammierer ja weiß, dass meine Funktion nur
> Ports (also I/O-Adressen) bekommt (kann man evtl auch prüfen)könnte ich
> doch per Inline-Assembler den "sbi"-Befehl vorgeben.

Und wie machst du das, wenn alles was du hast eine Adresse ist.
Ob du jetzt weißt, dass es sich dabei um einen Port handelt oder nicht, 
spielt da herzlich wenig Rolle. Oder kannst du zaubern?

> Leider kenn ich mich mit inline-Assembler sogut wie garnicht aus.
>
> Gibt es eine Möglichkeit so ein Konstrukt zu verwenden:
> asm("sbi port, pin");

dann schau dir doch mal an, was du beim sbi Befehl für Argumente 
benutzen kannst. Wenn das möglich wäre, dann könnte das auch der 
COmpiler für dich tun.

von Ralf G. (ralg)


Lesenswert?

le x. schrieb:
> Gibt es eine Möglichkeit so ein Konstrukt zu verwenden:
> asm("sbi port, pin");

Ja, so wird das gemacht. Allerdings steige ich durch die 
Variablenübergabe nicht durch. Deswegen habe ich mich lieber mit dem GAS 
beschäftigt und würde sowas als Funktion in eine eigene Datai/ extra 
Modul packen. Wenn's kurz genug ist, schiebt der Compiler das auch 
'inline' rein (vermute ich mal stark).

von amateur (Gast)


Lesenswert?

So etwas müsste sich doch mit Makros machen lassen. Natürlich mit einem 
Haufen if's und nicht besonders wartungsfreundlich. Das Resultat müsste 
aber auch in einem sbi resultieren, falls der Port das zulässt und ein 
einer Ersatzkonstruktion wenn nicht.

von Oliver (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> dann schau dir doch mal an, was du beim sbi Befehl für Argumente
> benutzen kannst

Ralf G. schrieb:
> Ja, so wird das gemacht. Allerdings steige ich durch die
> Variablenübergabe nicht durch.

was unter anderem daran liegen wird, daß sbi mit Variablen nix anfangen 
kann. Doku zum sbi-Befehl:
1
SBI A,b mit 0 ≤ A ≤ 31, 0 ≤ b ≤ 7

Das sind alles zur Compilezeit bekannte Konstanten. Da könnte man 
höchstens was mit einen define-Makro basteln, das dann aber auch nur mit 
zur Compilezeit bekannten "echten" C-Konstanten gefüttert werden darf.

amateur schrieb:
> So etwas müsste sich doch mit Makros machen lassen. Natürlich mit einem
> Haufen if's und nicht besonders wartungsfreundlich

und im Endeffekt damit kaum schneller oder kürzer als der vom Compiler 
aus
>void set_pin(port *, pin);
erzeugte Code.

Oliver

von Peter D. (peda)


Lesenswert?

Sobald Du aus Konstanten Variablen machst, ist der Kuchen gegessen.

Du kannst aus Variablen keinen Befehl mehr basteln, dazu müßtest Du den 
Code patchen, d.h. er müßte aus dem RAM ausgeführt werden.

Nimm Macros, am besten mit meiner "sbit.h", damit ist es einfach und gut 
lesbar.

Beitrag "Re: Port als Variable"

von Rolf M. (rmagnus)


Lesenswert?

Man muß die Funktion lediglich als inline-Funktion ausführen, dann geht 
das ohne Probleme.

von bal (Gast)


Lesenswert?

Jein.

Auch nur, wenn du die Funktion mit konstanten Werten aufrufst.
Sobald du deine inline-Funktion aus einem Funktionskontext mit Parameter 
aufrufst, muss der Compiler wieder das schlimmste annehmen und den 
kompletten Code reinklatschen.

Unter Umständen sogar eher kontraproduktiv...

von Oliver (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Man muß die Funktion lediglich als inline-Funktion ausführen, dann geht
> das ohne Probleme.

Inline oder nicht inline ist nicht die Frage.

Solange da etwas in der Art steht:
1
set_pin(PORTA, 3);

kann der Compiler das in ein sbi umsetzen.

Aus so etwas hier:
1
for (uint8_t i=0;i<8;i++)
2
   set_pin(PORTA, i);

oder
1
for (uint8_t i=0;i<3;i++)
2
   set_pin(portlist[i], 3);

lässt sich aber nun mal kein einzelnes sbi erzeugen.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

bal schrieb:
> Sobald du deine inline-Funktion aus einem Funktionskontext mit Parameter
> aufrufst, muss der Compiler wieder das schlimmste annehmen und den
> kompletten Code reinklatschen.
>
> Unter Umständen sogar eher kontraproduktiv...

Es verhält sich genau so, als ob ich ein PORTA = (1 << X) direkt 
hinschreibe. Eine Verschlechterung demgegenüber gibt es nicht. Nur wenn 
X eine Compilezeit-Konstante ist, bekomme ich die schnelle Variante.

Oliver schrieb:
> Rolf Magnus schrieb:
>> Man muß die Funktion lediglich als inline-Funktion ausführen, dann geht
>> das ohne Probleme.
>
> Inline oder nicht inline ist nicht die Frage.

Doch. Wenn die Funktion nicht inline aufgelöst wird, bekommst du immer 
die langsame Variante, egal was du übergibst.

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.