Forum: Compiler & IDEs avr-gcc fixed point und fmul


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo allerseits,

ich beschäftige mich gerade damit, Elm Chans FFT-Code zu verstehen, und 
den in C nachzubauen.

(Bevor jetzt gleich wieder die ASM-Prediger sich berufen fühlen zu 
predigen: Bitte nicht....)

Leider bin ich ziemlich schwach in Assembler, aber das wird schon...

Nachdem meine ersten Versuche allein mit dem preprocessing (Windowing) 
dauernd falsche Ergebnisse geliefert haben, bin ich draufgekommen, dass 
dort intensiv mit der AVR-eigenen Festkomma-Arithmetik (sprich: FMULS) 
gearbeitet wird. Damit hatte ich noch nie zu tun, glaube aber die 
grundlegend verstanden zu haben.

Nun frage ich mich, wie man das in C macht. Dabei bin ich draufgekommen, 
dass der GCC ja eh (zumindest rudimentär) Festkomma-Arithemtik kann (mit 
dem Datentyp _Fract), allerdings bin ich noch nicht dahintergestiegen ob 
und wie das zusammenpasst...

Weiss jemand wie gut und effizient die Festkomma-Arithemtik am AVR 
arbeitet? In ein paar einfachen (und konfusen) Beispielen ist mir 
jedenfalls noch keine FMUL-Instruktion untergekommen.

nebenbei gibts im avr-gcc ja ein paar builtins für fmul. Hilft mir das 
weiter?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Michael Reinelt schrieb:
> Nachdem meine ersten Versuche allein mit dem preprocessing (Windowing)
> dauernd falsche Ergebnisse geliefert haben, bin ich draufgekommen, dass
> dort intensiv mit der AVR-eigenen Festkomma-Arithmetik (sprich: FMULS)
> gearbeitet wird. Damit hatte ich noch nie zu tun, glaube aber die
> grundlegend verstanden zu haben.
>
> Nun frage ich mich, wie man das in C macht.

Genau wie in Assembler.  Der Algorithmus bleibt ja der gleiche.

> Dabei bin ich draufgekommen, dass der GCC ja eh (zumindest
> rudimentär) Festkomma-Arithemtik kann (mit dem Datentyp _Fract),

Es gibt { fract, accum } * { short, /**/, long, long long } * {signed, 
unsigned } * { /**/, sat } = 2 * 4 * 2 * 2 = 32 unterschiedliche 
Fixed-Point Typen.

> allerdings bin ich noch nicht dahintergestiegen ob und wie das
> zusammenpasst...
>
> Weiss jemand wie gut und effizient die Festkomma-Arithemtik am
> AVR arbeitet?

So gut oder schlecht wie GCC / avr-gcc / libc diese unterstützen.

Unterstützung von Seiten der libc:

Momentan keine.  Dies wären vor allem Erweiterungen von printf / scanf 
etc, die mangels Bedarf noch niemand beigetragen hat.

Unterstützung avr-gcc / avr-libgcc:

Für die meisten nicht-saturierenden Typen <= 32 Bit sind Grundarithmetik 
(+, -, *, /, Vergleiche, Typ-Umwandlung) in Assembler implementiert.  In 
manchen Fällen nativ inline, ansonsten per Assembler in der libgcc.

Dies gilt auch für einige oder alle saturierende Typen für +, -, 
Vergleiche.

Elementare Funktionen aus stdfix.h sind per Built-in Funktionen 
implementiert und werden durch stdfix.h darauf abgebildet; dies sind 
abs?, round?, countls?, ?bits und bits?.

Die Typ-generischen Funktionen absfx, roundfx und counlsfx sind 
überladen und bilden auf die entsprechende Built-in Funktion ab.

> In ein paar einfachen (und konfusen) Beispielen ist mir
> jedenfalls noch keine FMUL-Instruktion untergekommen.

fmul[s[u]] sind für Fixed-Point Arithmetik i.W. nutzlos und werden daher 
auch nur in sehr wenigen Fällen erzeugt, etwa bei short fract 
Multiplikation.  Aber bereits bei unsigned short fract, short sat fract 
oder short accum oder unsigned short accum kann man nix mehr damit 
anfangen.

> nebenbei gibts im avr-gcc ja ein paar builtins für fmul. Hilft mir das
> weiter?

Je nachdem, was du machen willst und brauchst (oder glaubst zu 
brauchen).

Die o.g. 32 Fixed Typen im Verbund mit den 9 Standard-Typen (float + { 
signed, unsigned } * { char, int, long, long long } = 1 + 2 * 4 ergeben 
bereits 41 unterschiedliche Typen, die man z.B. ineinander umwandeln 
(casten) kann.  Bei t = 41 Typen und s = 9 Standard-Typen sind das 
bereits t * t - s * s - (t - s) = 1568 mögliche Typ-Casts, wobei 
triviale Casts und solche zwischen Standard-Typen bereits außen vor 
sind.

In Anbetracht der Fülle an Typen und Operationen ist es kaum möglich 
sinnvoll auf deine Frage zu Antworten und auf jede mögliche Kombination 
von Typen und Operation einzugehen.

An einfachsten schaust du dir also die entsprechenden Header und Quellen 
des avr-gcc an.  Jeder, der ein bisschen programmieren, AVR-Assembler 
und abstrakt denken kann, sollte nach einigen Minuten die 
Transferleistung erbringen können, zu beurteilen, ob die von ihm / ihr 
benötigten Funktionen mit der gewünschten Effizienz und / oder 
Rundungsgenauigkeit zur Verfügung stehen.

stdfix.h:
http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/stdfix.h?view=markup

avr-libgcc (fixed)
http://gcc.gnu.org/viewcvs/gcc/trunk/libgcc/config/avr/lib1funcs-fixed.S?view=markup

Einiges davon verwendet den nicht-fixed Teil:
http://gcc.gnu.org/viewcvs/gcc/trunk/libgcc/config/avr/lib1funcs.S?view=markup

Was in der avr-libgcc in Assembler steht kann auch daraus entnommen 
werden, was alles aus dem Umfang der default libgcc entfernt wird. 
Make-Schnippel:
http://gcc.gnu.org/viewcvs/gcc/trunk/libgcc/config/avr/t-avr?revision=216525&view=markup#l212

Was nativ inline expandiert, ist Teil der Maschinenbeschreibung. 
"define_insn" liest sich wie Inline-Assembler, nur dass es zusätzlich 
eine algebraische Umschreibung davon enthält:
Fixed-Teil der Maschinenbeschreibung (<= 32 Bits):
http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr-fixed.md?view=markup
http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr.md?view=markup

Falls für 64-Bit Operationen spezieller Code erzeugt wird, dann ist der 
in:
http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr-dimode.md?view=markup

Falls define_insn kein asm-Template hat, dann ist es ein 
C/C++-Schnippel, der i.d.R. Support-Funktionen aus dem C/C++-Teil 
verwendet (z.B. avr_out_fract, avr_out_plus, avr_out_round, 
avr_out_compare, avr_out_compare64, avr_out_bitop, ...):
http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr.c?view=markup

: Bearbeitet durch User
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Johann L. schrieb:
> In Anbetracht der Fülle an Typen und Operationen ist es kaum möglich
> sinnvoll auf deine Frage zu Antworten und auf jede mögliche Kombination
> von Typen und Operation einzugehen.

Wow, und ob die Antwort sinnvoll war! Danke! Da bin ich jetzt erstmal 
beschäftigt mit Lesen... (wenn nur der Sch*ss Beruf nicht wäre...)

die stdfix.h hab ich mittlerweile auch gefunden, ich hab nur falsch 
gesucht (die gehört ja zum gcc, nicht zur libc)

In der Zwischenzeit versuche ich intensiv, den originalen asm-Code zu 
verstehen, da komm ich langsam voran. Dann schau'mer mal wie sich das in 
C umsetzen lässt.

ich fürchte nur das wird ein unfairer Vergleich, weil Elm-Chans asm 
schonmal von Haus aus nicht der Schlechteste ist, und er natürlich auf 
viele Sonderfälle (Überlauf bei -1*-1 etc) erst gar nicht reagiert, weil 
er das schon vorab ausschließt.

Aber ich finde die Fract-Unterstützung extrem spannend!

An der Stelle einen ganz herzlichen Dank für deinen Einsatz, Johann!

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.