Forum: Compiler & IDEs Inline assembler


von Peter D. (peda)


Lesenswert?

Eine Frage an die GCC-Profis.

Ich hab jetzt mal versucht, schnelle Interrupts mit Inline-Assembler zu
schreiben.
Die Syntax ist zwar etwas gewöhnungsbedürftig, aber sonst klappt das
ganz prima.

Bloß leider wird trotzdem diese ganze PUSH/EOR/POP-Arie eingefügt, was
ja allein schon mal 15 Zyklen wegfrißt, also die Interruptzeit fast
verdoppelt.

Kann man denn garnichts dagegen tun ?

Warum wird auch ausgerechnet R1 als Null genommen und somit diese ganze
Arie erst notwendig (wegen MUL-Befehl). Jedes andere (R3..R15) ist doch
wesentlich besser geeignet.
Und wenn man schon ein Null-Register reserviert, dann könnte man auch
gleich eins fürs SREG sichern reservieren.
In Assembler habe ich das immer so gemacht und das bringt sogar weitaus
mehr als das Null-Register.

Damit würde sich nämlich die Interruptrahmenzeit von 25 auf 12 Zyklen
verringern !


Peter

von Joerg Wunsch (Gast)


Lesenswert?

> Ich hab jetzt mal versucht, schnelle Interrupts mit Inline-Assembler
> zu schreiben.

Warum dann nicht gleich komplett in Assembler?

> Kann man denn garnichts dagegen tun ?

__attribute__((naked)) kennst Du aber, oder?

> Warum wird auch ausgerechnet R1 als Null genommen...

Da mußt Du mal die Designer fragen, Denis und vielleicht auch Marek.
Möglicherweise haben sie diese Entscheidung getroffen, als es noch
keine AVRs mit Hardwaremultiplizierer gab.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Danke Joerg,

"Warum dann nicht gleich komplett in Assembler?"

Ich will die #define und Variablen aus den C-Files mitverwenden und
nicht zusätzliche .equ definieren müssen.


"__attribute__((naked)) kennst Du aber, oder?"

Bisher noch nicht.
Ich hatte noch ne ältere signal.h, da war das EMPTY_INTERRUPT noch
nicht drin. Die jetzige ist vom 10.9.03 0:24Uhr, damit ergibt sich aber
folgender Fehler:

TEST.C:7: error: parse error before '{' token



Peter

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Schau mal in die signal.h:

#define EMPTY_INTERRUPT(signame)                \
void signame (void) __attribute__((naked)) ;           \
void signame (void) { _asm__ __volatile_ ("reti" ::); }

EMPTY_INTERRUPT ist also für leere Interrupthandler vorgesehen.
Probier's mal damit:

SIGNAL(SIG_OVERFLOW0) __attribute__((naked))
{
  ...
}

von Joerg Wunsch (Gast)


Lesenswert?

> EST.C:7: error: parse error before '{' token

Ja, siehe Doku:

    Defines an empty interrupt handler function. This will not
    generate any prolog or epilog code and will only return from the
    ISR. Do not define a function body as this will define it for you.

Nein, Du brauchst eher sowas wie

SIGNAL(SIG_FOO) __attribute__((naked));

SIGNAL(SIG_FOO) {
  ...
  asm volatile("reti");
}

von Peter D. (peda)


Lesenswert?

Danke Joerg, das hats gebracht.

Mit Assembler, Registervariablen und "Nacktheit" habe ich nun die
Interrupts 3* schneller gekriegt !
D.h. unter reinem C hätte ich einen 30MHz Quarz gebraucht.

Wie es scheint sind die Register R2..R13 unbenutzt, d.h. sie können für
Variablen genutzt werden. Leider gibt es aber keinen Linkerfehler, wenn
man ein schon anderweitig benutztes Register als Variable nimmt.


Peter

von Joerg Wunsch (Gast)


Lesenswert?

> Wie es scheint sind die Register R2..R13 unbenutzt, d.h. sie können
> für Variablen genutzt werden.

Der Compiler würde sie benutzen, wenn er Bedarf an Registern hat.

> Leider gibt es aber keinen Linkerfehler, wenn man ein schon
> anderweitig benutztes Register als Variable nimmt.

Das ist jenseits dessen, was der Linker zu sehen bekommt.

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.