Hallo allerseits, da sich hier ja ein paar Assembler-Gurus tummeln... ich habe beschlossen mich mal an Assembler am AVR zu versuchen. Anbei mein erster (noch unvollständiger) Versuch. Es handelt sich um den ersten (und einfachsten) Teil eines FFT-Moduls, basierend (ok, abgeschrieben) von Elm-Chans Fast FFT Module. Mir gehts nicht darum, warum ich funktionierenden Code nochmal schreibe? sondern ums Lernen. lernen kann ich am besten wenn ich bestehenden, guten Code versuche zu verstehen und versuche selbst zu verändern und erweitern. Der Code macht nix anderes als einen Block von Festkomma-Werten (zukünftig vom ADC) entgegenzunehmen, eine Window-Funktion drüberzulegen, und im FFT-Eingangspuffer abzulegen; dabei werden Real- und Imaginärteil auf identische Werte gesetzt (warum? müsst ihr Elm Chan fragen :-) Etwas unsicher bin ich bei zwei Sachen: - was ist die übliche Extension für asm-Files, welche dann in C-Code eingebunden werden? Ich hab irgendwo .sx gelesen, aber irgendwie kommt mir das fremd vor.... .s oder .S möchte ich vermeiden, da das die temporärfiles vom gcc sind. - wie geht man mit "gemeinsamen" include-files (fft.h) um? Passt das mit der "Sicherung" per #define FFT_ASM so? Ansonsten sind sicher 1000 Anfängerfehler drinnen, bitte um wohlwollende Korrektur :-) Danke, Michi Edit: ich hab beim ersten mal die falsche header-Datei erwischt, die ffft.h (drei f) ist die originale vom Elm-Chan. Könnte ein Mod das entfernen? Danke!
chris schrieb: > wo sind die ASM-Datein????? gibbets nicht, das assemblerprogramm ist als inline assembler-code geschrieben. Schadir mal die ffft.h an und scroll nach unten. MfG,
Fpga Kuechle schrieb: > chris schrieb: >> wo sind die ASM-Datein????? > > gibbets nicht, das assemblerprogramm ist als inline assembler-code > geschrieben. Schadir mal die ffft.h an und scroll nach unten. NEIN!!!! die ffft.h ist das original vom Elm Chan, hab leider die falsche Datei erwischt, habs aber eh dazugeschrieben. Bitte löschen bzw. ignorieren! der ASM-Code steckt in der fft.sx; das war eine meiner Fragen welche extension man verwendet, wenn man C und asm mixt. .sx stand in irgendeinem der vielen Tutorials.
dann wäre .asm die bessere Endung da wäre bei mir gleich das Atmel Studio gestartet worden.
1 | 1: lpm r18, Z+ ; window (lo byte) |
2 | lpm r19, Z+ ; window (hi byte) |
3 | ld r20, X+ ; input (lo byte) |
4 | ld r21, X+ ; input (hi byte) |
5 | |
6 | FMUL16x16 r25,r24,r23,r22,r21,r20,r19,r18,r15 ; output = input * window (LSBs not used) |
7 | |
8 | st Y+, r24 ; output re (lo byte) |
9 | st Y+, r25 ; output re (hi byte) |
10 | st Y+, r24 ; output im (lo byte) |
11 | st Y+, r25 ; output im (lo byte) |
12 | |
13 | subi r16, 1 ; loop (lo byte) |
14 | #if FFT_SIZE > 256 |
15 | sbci r17, 0 ; loop (hi byte) |
16 | #endif |
17 | brne 1b ; loop over FFT_SIZE |
Der letzte Befehl , soll das ein Sprung zum Label 1 in der ersten Zeile werden. Ist der Sprung relativ? Wenn ja ist es dann OK das die Zeile eins drüber per präprozessor eingefügt wird oder nicht? bessere Labelnamen z.B. LOOP_WINDOW wären sehr hilfreich. Das zero register für die FMUL sollte vor jedem Aufruf auf 0 gesetzt werden. Bei dir scheint es nur einmal ge-CLR-ed zu werden.
Fpga Kuechle schrieb: > dann wäre .asm die bessere Endung da wäre bei mir gleich das Atmel > Studio gestartet worden. .sx ist eine der Standard-Extensions die GCC kennt. Sie kennzeichnet Assembler-Quellen, über die vor der Assemblierung noch der C-Präprozessor (cpp) läuft. .asm ist hingegen keine Standard-Extension, d.h. ohne weiteres Zutun wird die Datei dann als Linker-Description-File interpretiert... > st Y+, r24 ; output re (lo byte) > st Y+, r25 ; output re (hi byte) > st Y+, r24 ; output im (lo byte) > st Y+, r25 ; output im (lo byte) Sieht komisch aus das. Mindestens eins von Kommentar oder Code ist falsch. Es sei denn lo(Im) = hi(Im) = lo(Re) = hi(Re). >> brne 1b ; loop over FFT_SIZE > Der letzte Befehl, soll das ein Sprung zum Label 1 in der ersten > Zeile werden. Braucht es nicht mehr zu werden; ist es schon. > Ist der Sprung relativ? Ja, BRNE nimmt nur relative Offsets. > Wenn ja ist es dann OK das die Zeile eins drüber > per präprozessor eingefügt wird oder nicht? Kein Problem. Der Assembler sieht nix vom Präprozessor, da er danach läuft. > Das zero register für die FMUL sollte vor jedem Aufruf auf 0 gesetzt > werden. Es genügt diese Register auf den Wert zu setzen, den man drin braucht. KeinProblem sofern es am Ende des Codes, bzw. sobald wieder C-Code ausgeführt wird, wieder 0 enthält.
Johann L. schrieb: > Fpga Kuechle schrieb: >>> brne 1b ; loop over FFT_SIZE > >> Der letzte Befehl, soll das ein Sprung zum Label 1 in der ersten >> Zeile werden. > > Braucht es nicht mehr zu werden; ist es schon. > Warum heisst dann das Label '1' aber das Argument von BRNE '1b'? > Das zero register für die FMUL sollte vor jedem Aufruf auf 0 gesetzt >> werden. > > Es genügt diese Register auf den Wert zu setzen, den man drin braucht. > > KeinProblem sofern es am Ende des Codes, bzw. sobald wieder C-Code > ausgeführt wird, wieder 0 enthält. ? so wie ich den Kommentar bei der Definition des Macros verstehe, muss das Register immer auf 0 gesetzt sein, bevor das Makro aufgerufen wird. Aufgerufen wird es direct nach dem Label 1. Es ist nicht erkennbar das es dabei immer auf 0 gesetzt wird. MfG,
Fpga Kuechle schrieb: > Warum heisst dann das Label '1' aber das Argument von BRNE '1b'? UNIX-Assembler-Syntax: das sind “local labels”, die bekommen nur eine Zahl als Namen, und dem Sprungziel wird ein “b” oder “f” angehangen. Es wird dann jeweils nach dem nächstgelegenen Label mit dieser Nummer rückwärts oder vorwärts gesucht. Ist besonders praktisch innerhalb von Codeschnipseln, die sich nur auf sich selbst beziehen und dann eingebettet werden können in ein größeres Stück (bspw. in Form von Inline Assembler).
Johann L. schrieb: >> st Y+, r24 ; output re (lo byte) >> st Y+, r25 ; output re (hi byte) >> st Y+, r24 ; output im (lo byte) >> st Y+, r25 ; output im (lo byte) > > Sieht komisch aus das. Mindestens eins von Kommentar oder Code ist > falsch. Es sei denn lo(Im) = hi(Im) = lo(Re) = hi(Re). Es ist nur der Kommentar in der letzten Zeile falsch. Das bissel Code ist KEINE FFT, sondern nur die vorgelagerte Windowing-Funktion für eine solche. Im Text des OP ist das auch korrekt beschrieben, nur der Name der Datei ist irreführend, wenn keine FFT in der Dose ist, sollte auf dem Dosenetikett eigentlich auch nicht FFT draufstehen... Warum allerdings das Ergebnis der Windowing-Funktion gleichmäßig auf Real- und Imaginärteil verteilt wird, das weiß ich auch nicht (und hat sich auch der der Autor des OP schon in selbigem gefragt). Ich kenne ansonsten keine FFT-Implementierung, die das macht, da wird beim Windowing überall nur der Realteil bearbeitet und der Imaginärteil mit Nullen gefüllt, bevor die eigentliche FFT auf die Daten losgelassen wird. Diese Frage kann also wohl nur Elm beantworten. Ich vermute (ohne es selbst überprüft zu haben): Es spielt mathematisch keine Rolle, ob da überall Null drinsteht oder immer derselbe Wert wie im zugehörigen Realteil und Elm hat diese (für mich auch neue) Tatsache benutzt, um ein "paar" (immerhin mindestens 256) Takte durch das Entfallen der ansonsten fälligen zusätzlichen Schleife zur Initialisierung des Imaginärteils der Daten zu sparen. > KeinProblem sofern es am Ende des Codes, bzw. sobald wieder C-Code > ausgeführt wird, wieder 0 enthält. Das ist gewährleistet. Das Zero-Register wird nämlich zu Beginn der Routine auf den Stack gerettet und am Ende wiederhergestellt. D.h.: Wenn vorher eine Null drinstand, wird sie auch hinterher wieder drinstehen. Und innerhalb der Routine wird das Register nur einmal schreibend angefaßt und dabei wird auch nur eine Null reingeschrieben. Das FMUL-Macro benutzt das Register ausschließlich lesend. Oder anders ausgedrückt: Da könnte man wahrscheinlich noch locker fünf Takte sparen...
Michael Reinelt schrieb: > Ich hab irgendwo .sx gelesen, aber irgendwie kommt mir das fremd vor.... > .s oder .S möchte ich vermeiden, da das die temporärfiles vom gcc sind. Die Endung ".S" beschreibt eine Original-Quelldatei, und ".s" ist etwas, was Präprozessor und/oder Compiler mal ausgespuckt haben. Da unter Windows beide Dateien gleich sind, kann man das da nicht machen; mit ".asm" ist man aber in jedem Fall auf der sicheren Seite.
Danke fürs Drüberschauen! (und Danke @Mods fürs aufräumen) Copy&Paste-Fehler im Kommentar ist korrigiert. Nachdem .sx GCC-Standard ist, werd ich dabei bleiben, auch wenns im ersten Moment (nicht nur für mich) ungewohnt ist. c-hater schrieb: > wenn keine FFT in > der Dose ist, sollte auf dem Dosenetikett eigentlich auch nicht FFT > draufstehen... Ist ja noch nicht fertig, im Endausbau wird der Inhalt schon zum Etikett passen. c-hater schrieb: > Ich vermute (ohne es selbst überprüft zu haben): Es spielt mathematisch > keine Rolle, ob da überall Null drinsteht oder immer derselbe Wert wie > im zugehörigen Realteil und Elm hat diese (für mich auch neue) Tatsache > benutzt, um ein "paar" (immerhin mindestens 256) Takte durch das > Entfallen der ansonsten fälligen zusätzlichen Schleife zur > Initialisierung des Imaginärteils der Daten zu sparen. Vermute ich auch. Ich denke der Unterschied zwischen Im=0 und Im=Re ist (neben einer leichten Skalierung um Sqrt(2) eine Phasenverschiebung, die sollte egal sein. "Sparen" täte man sich vermutlich nix, die beiden "st Y+" könnte man auch mit meinem zero-reg aufrufen. Wenn der Rest mal fertig ist kann ich ja schauen obs einen unterschied macht. Eine Frage ist noch unbeantwortet: die "Absicherung" per #ifdef FFT_ASM im Header-File, passt das so, ist das so üblich? Ansonsten habts ihr keine Fehler gefunden?
Jörg Wunsch schrieb: > Fpga Kuechle schrieb: >> Warum heisst dann das Label '1' aber das Argument von BRNE '1b'? > > UNIX-Assembler-Syntax: das sind “local labels”, die bekommen nur > eine Zahl als Namen, und dem Sprungziel wird ein “b” oder “f” > angehangen. Es wird dann jeweils nach dem nächstgelegenen Label mit > dieser Nummer rückwärts oder vorwärts gesucht. Wieder was gelernt - local labels. Danke für die Erklärung. MfG,
Michael Reinelt schrieb: > "Sparen" täte man sich vermutlich nix, die beiden "st Y+" könnte man > auch mit meinem zero-reg aufrufen. Ähm ja, auch wieder wahr. Umso interessanter wäre es, zu erfahren, was sich der gute Elm nun tatsächlich dabei gedacht hat.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.