Hallo AVR-Fans, um meinen Strom von Anfragen nicht abreissen zu lassen, kommt hier schon wieder die nächste :-) Also: Wie kann ich in GCC-Assembler-Code eine Sprungtabelle im ROM definieren und zwar so, daß die Adresse NICHT zur Laufzeit durch zwei geteilt wird (ich kenne bereits die Funktionen pm_lo8 und pm_hi8, mit denen man so ähnliche Dinge erreicht, aber die helfen nichts) Beispiel: ziel1: ; code... ziel2: ; code... sprung_tabelle: .word ziel1 >> 1 .word ziel2 >> 1 So würde es im Prinzip aussehen, weil der Prozessor Wortadressen benötigt (von Vorwärtsreferenzen wage ich momentan noch gar nicht zu träumen). Leider packt das aber der Assembler nicht. Gibt's eine korrekte Vorgehensweise? Oder anders: Gibt's eine Doku mit allen Funktionen des Assemblers? In freudiger Erwartung Christian
Nun, das einfachste ist, Du läßt das den Compiler machen und schaust Dir den generierten Assemblercode an. ;-) Ich habe folgendes Stückchen C mal durch den Compiler gejagt (avr-gcc -S ...): void foo(void) { } void doo(void) { } void (*footab[])(void) _attribute_ ((progmem)) = { foo, doo }; Das pm() scheint der Trick zu sein. Das besagt offenbar, daß der entsprechende Wert aus dem program memory zu nehmen ist. Normalerweise findest Du die Doku des GNU Assemblers im Netz (oder bei WinAVR auch mit auf der Platte). Allerdings scheinen mir die plattformabhängigen Teile für AVR nicht dokumentiert worden zu sein. :-( Wenn ich mal viel Zeit habe, schaue ich mir mal an, ob man da wenigstens eine kurze Zusammenfassung innerhalb der avr-libc Doku einarbeiten kann.
Ja, durch den Assembler jagen ist nicht schlecht...ich hab diese pm() Funktion mal direkt im Assembler getestet, die tut einfach nichts :-(. Naja, damit ich mal langsam vorwärts komme, rechne ich halt nun doch zur Laufzeit um (damit kann man "nur" 64k>Byte< des verwendeten ATmega128 erreichen, was derzeit aber ein eher theoretisches Problem ist). Ziel war es ursprünglich, einen bestehenden Quelltext 1:1 von GCC-AS übersetzen zu lassen und zwar so, daß sich der gleiche Binärcode ergibt. Damit könnte ich feststellen, ob sich Fehler bei der "Portierung" eingeschlichen haben. Man glaubt nicht, was das für Probleme aufwirft! Erst im nächsten Schritt wollte ich dann Schritt für Schritt C-Code einbinden. Naja vielleicht finden wir ja noch den Befehl (mal im Quelltext von GCC-AS nachschaun)
Habe gerade mal ins tc-avr.c geschaut: case BFD_RELOC_AVR_16_PM: bfd_putl16 ((bfd_vma) (value >> 1), where); break; Sieht also so aus, als würde dieser pm() Operator bereits die Umrechnung von Byte- auf Wortadressen vornehmen.
Ich hab mal Dein foo-Beispiel durch den Compiler geschoben: Damit liegt die Tabelle aber noch im RAM. Das sieht man deutlicher, wenn man mal eine Funktion über die Tabelle aufruft, z.B. footab[0](). Da greift er dann mittels lds-Befehl auf die Tabelle zu. Wenn ich aber stattdessen statt _attribute_ ((progmem)) einfach nur PROGMEM schreibe (mit passendem Include), dann greift er mit dem lpm-Befehl in die Tabelle. Nur - die Tabelle wird einfach direkt vom Compiler korrekt erzeugt. Damit konnte ich also auch keine Assembler-Geheimnisse entlocken...es bleibt spannend!
Ob Du __attribute__((progmem)) oder __attribute__((_progmem_)) schreibst (was anderes ist PROGMEM nicht), ist weitgehend egal. Im generierten Assemblercode siehst Du, daß er das nach section .progmem.data setzt, das ist genau das, wo es hingehört. Daß Du auf ein progmem-Array nicht direkt zugreifen kannst sondern nur mit LPM, liegt in der Verantwortung des Programmierers. Der Compiler benutzt LPM nie von sich aus! Wenn das also bei Dir dann irgendwann doch geklappt hat, hast Du das irgendwo in einem Macro oder sowas indirekt selbst getan. Was fehlt Dir denn noch an Assembler-,,Geheimnissen''? Das pm() war der eigentliche Trick.
Ja, wie gesagt, der pm()-Operator liefert mir als Ergebnis leider nur das zurück, was ich als Argument übergeben habe (komisch). Benötigen tue ich das Teilen durch zwei. Moment mal, hast Du .progmem.data gesagt? Das ist quasi eine subsection oder wie, da muß ich nochmal forschen!
Jetzt frag' mich mal jemand was ich früher gemacht habe: Es interessiert mich nicht mehr. Fakt ist: der pm()-Operator tut was er soll. Die Software ist jetzt 1:1 auf den neuen Assembler übernommen: Ab jetzt wird nur noch C programmiert :-)))))
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.