Hallo, liebe Gemeinde! Ich möchte diesen thread Nutzen, um den gccasm möglichst gut zu verstehen. Dabei geht es erst mal nur um das Interesse, später am eh esten um asm files, die in c-Projekte eingefügt werden. (wenn ich recht verstehe ist es ein Unterschied, ob ich asm Funktionen aus einem c-Programm aufrufe oder umgekehrt c generierte Funktionen in einem asm Projekt; s.u. Register sichern) Zu mir, ich ein ziemlicher Frischling, habe vor einem halben Jahr mit dem avr tutorial angefangen und dann das c tutorial angefangen. Von daher bin ich vielleicht naiv oder fehlinterpretationen erlegen - ich bitte das zu entschuldigen. Es ist alles nur Hobby! Kein Grund, mich selber unter Druck zu setzen bzw. andersrum kein grund geflamt zu werden wegen blöder Fragen... Also los. Eins nach dem anderen. Wie gesagt es geht darum, wenn überhaupt, *.S Dateien mit asm Funktionen in einem c-Projekt zu verwenden. verstehe ich http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage schon mal richtig, daß ich dann in der asm Funktion die Register R2-R17 und das y-Register sichern muss, wenn diese eins davon verändert und andersrum R18-R27 und Z-Register GANZ beliebig einfach verwendet werden kann? Ganz beliebig, weil der c Compiler vor einem asm Aufruf weiß, daß er eins davon verwendet und deshalb selber, VOR dem Aufruf der asm Funktion diese auf den Stack pusht und auch wieder zurückspeichert? Falls das stimmt: wenn ich eine isr in Assembler schreiben möchte, muss ich alle benutzen register selber sichern und zurückschreiben - gcc weiß ja nicht, wann der Interrupt auslöst.... Dann würde c ja quasi alle Pointer Register sichern, denn ich würde erwarten, daß die sozusagen immer benutzt werden? Eine Konkrete Frage: Wenn ich eine Funktion wie void funk(void* ptr) in asm schreibe, dann wird der pointer als erstes Argument in Register R24/R25 übergeben? Der muss dann direkt in ein Pointer Register x oder z (?) kompiert werden? Diese müsste ich aber nicht selber sichern, weil c das von sich aus täte, wenn die belegt sind..... Wenn das stimmt hat man schon das sichern und kopieren des Pointers als zusätzliche zeit verglichen mit einem reinem Assemblerprogramm, wo ich geziehlt schon ein pointer register laden kann und nciht erst kopieren muss. Eine letzte Frage ist das y-register, welches ich selber sichern muss zu beginn der asm Funktion. Das nennt sich "Framing Pointer". Was ist darunter zu verstehen und was mache ich damit? Ich verstehe die Funktion darin, daß es eine Kopie des Stackpointers ist wenn die Funktion startet. Was ich damit mache ist mir nur nicht klar.... :-( Also jegliche Hilfe, Kommentare, beispiele sind mir sehr willkommen! Flames nicht, denn dafür fühle ich mich nicht sicher genug. Weitere Fragen würd ich hier drinnen posten. Kann aber dauern, denn wie gesagt ich bewege mich beruflich ganz woanders und beschäftige mich aus Interesse und Lust an der Freud damit. Der Ehrgeiz treibt mich aber so weit, genauer verstehen zu wollen, wie das alles Funktioniert und was der c compiler genau macht. :-( Ich bin gespannt! schöne Grüße, Micha!
Schande über mich, Doppelpost! habe vergessen zu Fragen, was es mit Zugriff auf Register auf sich hat. Es wird wiederholt erwähnt, daß ein Offset von 20hex nötig ist, wenn in einer asm Datei ein Register verwendet wird. Ich bin bei meinem Studium von google auf ein #define Ich_hab_es_leiser_vergessen gestoßen, was nötig ist für dieses Offset. Da fehlt mir Wissen, ich kann den Link aber auch nicht mehr finden - Hilfe erbeten!
Dein Fragen sind nicht blöd, jedenfalls nicht blöder als andere ;-) Die FAQ lese ich genauso wie du es tust. Die Überlegung bei der ISR ist auch richtig. Was der GCC bei ISRs in C sichert kannst du dir leicht ansehen, indem du dir ein Disassemblerlisting erzeugen lässt bzw. im AVR Studio disassemblierst. Bei der funk() und den Übergabeparametern hast du grundsätzlich Recht. Das Umkopieren benötigt Zusatzinstruktionen. Du musst abwägen, ob deine ASM-Routine diesen Aufwand lohnt. Allerdings kannst du auch in C veranlassen, dass die Umkopiererei entfällt. Wenn du deine ASM-Routine in Inline-Assembler statt als eigene Funktion schreibst, kannst du den Pointer aus der aufrufenden Routine direkt in die Zielregister laden (nachdem die zuvor gesichert sind). Den Framepointer hat deine aufgerufene ASM-Routine wie in der FAQ geschrieben in Ruhe zu lassen (und zu sichern). Der GCC könnte einen Framepointer benutzen, um in folgender Situation auf die lokalen Variablen a und b zuzugreifen, wenn a und/oder b nicht in einem freien Register gehalten werden können, sondern auf dem Stack residieren. a wäre dann innerhalb caller() z.B. Inhalt von Framepointer+x und b Inhalt von Framepointer+y. Innerhalb meine_ASM_routine() kannst du nicht sicher (ohne Blick in das konkrete Einzeldisassemblat) sagen, auf welche lokale Variable des Aufrufers der Framepointer zeigt. Aus dem Gültigkeitsmodell für Variablen her ist ein mit Framepointer getrickster Zugriff auf a und b aus meine_ASM_routine() heraus illegal. Für den legalen Zugriff müsstest du z.b. die Adressen oder Inhalte als Funktionsparameter mitgeben extern void meine_ASM_routine(void); void caller(void) { int a, b; a = .... meine ASM_routine(); b = a * ... } Wie gesagt, ein Blick in die Disassemblerlistings ist auch nicht schlecht. Dabei ruhig auch mit den Optimierungsstufen experimentieren. Oft sieht man in den unoptimierten Listings fast nix sinnvolles und in den optimierten schon.
Ein dummer Besucher schrieb: > Schande über mich, Doppelpost! > habe vergessen zu Fragen, was es mit Zugriff auf Register auf sich hat. > Es wird wiederholt erwähnt, daß ein Offset von 20hex nötig ist, wenn in > einer asm Datei ein Register verwendet wird. > Ich bin bei meinem Studium von google auf ein #define > Ich_hab_es_leiser_vergessen gestoßen, was nötig ist für dieses Offset. > Da fehlt mir Wissen, ich kann den Link aber auch nicht mehr finden - > Hilfe erbeten! Das steht in http://www.nongnu.org/avr-libc/user-manual/group__avr__sfr__notes.html in Verbindung mit http://www.nongnu.org/avr-libc/user-manual/assembler.html Im Prinzip musst du schauen, ob für deinen AVR _SFR_ASM_COMPAT bzw. wie __SFR_OFFSET definiert sind und dann deinen ASM-Code entsprechend schreiben. Bei der Standardsituation (__SFR_OFFSET (so it will be 0x20 by default)) benutzt du das Makro z.B. _SFR_IO_ADDR(PORTD), wenn du mit out(/in...) auf die SFRs zugreifen willst, d.h. das für den Memeoryadressraum definierte PORTD im I/O Adressraum abbilden willst. Bzw. wenn du auf SFR im Memoryadressraum mit lds/sts zugreifen willst, dann geht das direkt mit z.B. sts PORTD, r24 bzw. besser mit sts _SFR_ADDR(PORTD), r24, wenn nicht standardgemäße __SFR_OFFSET im Spiel sind.
Wunderbare Antwort(en), da bedanke ich mich recht herzlich! Das gibt erst mal wieder eine ganze Zeit neuen Stoff zum nachdenken und ausprobieren.
Ein dummer Besucher schrieb: > Hallo, liebe Gemeinde! > > Ich möchte diesen thread Nutzen, um den gccasm möglichst gut zu > verstehen. Dabei geht es erst mal nur um das Interesse, später am eh > esten um asm files, die in c-Projekte eingefügt werden. (wenn ich recht > verstehe ist es ein Unterschied, ob ich asm Funktionen aus einem > c-Programm aufrufe oder umgekehrt c generierte Funktionen in einem asm > Projekt; s.u. Register sichern) Es ist nicht wirklich ein Unterschied, weil das gleiche Application Binary Interface (ABI) verwendet wird. Wenn also eine C-Funktion aufgerufen wird, so werden nach deren Ausführung Y und R2-R17 unveränderte Wert haben, während davon ausgegangen werden muss, daß R0, R18-27 und Z veränderte Werte haben. R1 hat eine Sonderrolle. Das ABI sagt, daß in diesem Register immer der Wert 0 zu stehen hat. Verändert eine Codesequenz diesen Wert (etwa bei MUL), so muss selbst dafür Sorge getragen werden, daß danach wieder eine 0 darin steht. Wird eine C-Funktion mit einen anderen Wert als 0 in R1 aufgerufen, so wird der C-Code evtl. fehlerhaft ausgeführt weil das ABI verletzt ist, und der Wert darin kann mit 0 überschrieben wirden sein. Die Instruktionen die in einer Funktion zur Ausführung kommen, müssen also dem ABI genügen. Egal, ob sie von einem Compiler erstellt wurden oder Handarbeit sind. Mit dem Wert von Y kannst in Asm nix anfangen. ALso entweder Y sichern oder nicht anfassen, genau wie mit allen anderen call-saved Registern auch. > Also los. Eins nach dem anderen. Wie gesagt es geht darum, wenn > überhaupt, *.S Dateien mit asm Funktionen in einem c-Projekt zu > verwenden. Ein Beispiel, wie's konkret aussehen kann, gibt's in http://www.mikrocontroller.net/articles/AVR_Arithmetik/Sinus_und_Cosinus_%28CORDIC%29 > verstehe ich > http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage schon > mal richtig, daß ich dann in der asm Funktion die Register R2-R17 und > das y-Register sichern muss, wenn diese eins davon verändert und Ja. Zudem siehe R1 oben > andersrum R18-R27 und Z-Register GANZ beliebig einfach verwendet werden Ja. Dito für R0 > kann? Ganz beliebig, weil der c Compiler vor einem asm Aufruf weiß, daß > er eins davon verwendet und deshalb selber, VOR dem Aufruf der asm > Funktion diese auf den Stack pusht und auch wieder zurückspeichert? Im Prinzip ja, auch wenn avr-gcc hier eine etwas andere Strategie fährt: Die call-used Regs werden -- falls verwendet -- im Prolog/Epilog der Funktion verarztet, nicht um jeden einzelnen Funktionsaufrufe herum. > Falls das stimmt: wenn ich eine isr in Assembler schreiben möchte, muss > ich alle benutzen register selber sichern und zurückschreiben - gcc weiß > ja nicht, wann der Interrupt auslöst.... Genau. ALLE verwendeten Rehs sichern und wieder herstellen. Auch R1 und R0. Hier auf keinen Fall am ISR-Ende eine 0 in R1 schreiben, falls die ISR R1 verwendet, sondern auf den ursprünglichen Inhalt restaurieren! > Eine Konkrete Frage: Wenn ich eine Funktion wie void funk(void* ptr) in > asm schreibe, dann wird der pointer als erstes Argument in Register > R24/R25 übergeben? Der muss dann direkt in ein Pointer Register x oder z > (?) kompiert werden? Diese müsste ich aber nicht selber sichern, weil c > das von sich aus täte, wenn die belegt sind..... Wenn das stimmt hat man > schon das sichern und kopieren des Pointers als zusätzliche zeit > verglichen mit einem reinem Assemblerprogramm, wo ich geziehlt schon ein > pointer register laden kann und nciht erst kopieren muss. C (bzw. avr-gcc) sichert X und Z auch nicht. Er verwendet es, wenn er eines davon braucht und weiß, daß der Wert durch einen Funktionaufruf potentiell kaputt geht. Soll ein Wert einen Funktionsaufruf überdauern, so wird er (evtl. nur temporär) in einem call-saved Reg abgelegt oder lebt im Frame der Funktio und wird nur von dort geladen, falls benötigt. > Eine letzte Frage ist das y-register, welches ich selber sichern muss zu > beginn der asm Funktion. Das nennt sich "Framing Pointer". Was ist > darunter zu verstehen und was mache ich damit? Ich verstehe die Funktion > darin, daß es eine Kopie des Stackpointers ist wenn die Funktion > startet. Was ich damit mache ist mir nur nicht klar.... :-( Entweder sichern oder nicht anfassen. Die lokalen Variablen, die eine Routine braucht, müssen irgendwo gemerkt werden. Falls es nicht genug Register gibt, werden die Variablen im Frame angelegt (aber auch dann, wenn man z.B. die Adresse einer lokalen Variablen oder eines Parameters nimmt, eine Struktur mit "krummer" Größe wie 3 Byte anlegt oder eine lokale Variable volatile macht). Da ist Platz auch dem Stack, der don der jeweiligen Funktion dynamisch belegt und wieder freigegeben wird. Weil AVR keine indirekte Adressierung über den SP zulässt, muss ein anderes Register dafür herhalten. Das ABI hat dafür Y auserkoren, und dies ist auch die einzig sinnvolle Wahl (X kann nicht mit Offsets adressieren und Z wird gebraucht für LPM und CALLI, JUMPI).
Noch ein Beispiel: http://www.mikrocontroller.net/articles/AVR_Arithmetik#avr-gcc_Implementierung_.2832_Bit.29
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.