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