inline-Assembler mit Variablen

#3165256
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
#3165291
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.
#3165293
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).
Gast #3165303
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.
Gast #3165324
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
Gast #3165888
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...
Gast #3165913
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
#3167365
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.

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