Hallo, ich habe ein Problem mit dem inline assembler von gcc für AVR. Ich möchte aus Geschwindigkeitsgründen für zwei Pointer vordefinierte Register benutzen und die dann direkt aus dem inline assembler ansprechen. (im Beispiel val_ptr und ref_ptr) Funktioniert auch, wenn ich die Pointer (val_ptr und ref_ptr) in C für irgendwelche Operationen benutze. Setze ich die Pointer ausschliesslich im inline assembler ein, werden die Zuweisungen val_ptr=val_tab; ref_ptr=ref_tab; vom Compiler wegoptimiert und der Assemblercode greift ins leere. Hat jemand eine Idee, wie ich dem Compiler sagen kann, dass ich die Pointer-Zuweisungen im Assembler Teil benötige und er sie gefälligst nicht wegoptimieren soll? Testcode: void test(void) { int8_t val_pnt; int32_t cor; int8_t ref_tab[16]; static int8_t val_tab[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; register int8_t* val_ptr asm("r22"); // use r22,r23 for fast access register int8_t* ref_ptr asm("r24"); // use r24,r25 for fast access val_ptr=val_tab; // nicht wegoptimiert, da Parameter bei Übergabe ref_ptr=ref_tab; // wegoptimiert, da in C nicht benutzt... asm volatile( "mov %A1,__zero_reg__" "\n\t" "mov %B1,__zero_reg__" "\n\t" "mov %C1,__zero_reg__" "\n\t" "mov %D1,__zero_reg__" "\n\t" "mov r16,r22" "\n\t" "mov r17,r24" "\n\t" "ld r16, %a3" "\n\t" "ld r17, %a4" "\n\t" : "=&r" (val_pnt), "=r" (cor) : "0" (val_pnt), "e" (val_ptr), "e" (ref_tab) : "r16", "r17" ); }
Schreib die Funktion am besten komplett in Assembler und binde sie ein (*.S Datei). Ich hasse den Inline Assembler mit den ganzen Ersetzungen für die Register und Variablen.
Hallo Benedikt, leider handelt es sich um eine interrupt service routine mit einer zeitintensiven Berechnung - die ich in assembler schreiben muss, da C zu langsam ist - sowie einer komplexen State-Machine - die ich lieber in C schreiben möchte. Insgesamt habe ich aber nur 300 Takte, d.h. ich möchte auf Overhead für function call, Parameter Übergabe etc. verzichten. Die Statemachine in C wird relativ gut compiliert.
> leider handelt es sich um eine interrupt service routine mit einer > zeitintensiven Berechnung - die ich in assembler schreiben muss, ... Genau da greift doch aber Benedikts Tip wirklich gut: schreib sie komplett als Assemblerdatei, statt dich mit dem inline-Assembler rumzuquälen. Nur die ISR sollst du in die Assemblerdatei legen, den Rest kannst du doch gut in C belassen. Ansonsten natürlich das Übliche bei der Kommunikation zwischen verschiedenen Code-Pfaden (also Interrupt-Kontext vs. Hauptprogramm): die Variablen müssen `volatile' deklariert werden, damit der Compiler weiß, dass sie sich außerhalb des aktuellen Pfades ändern können bzw. dort abgefragt werden können. Zwar wirst du für "volatile register" eine Warnung vom Compiler bekommen, aber die kannst du ignorieren. In deinem Falle ist es wohl wirklich genau das, was du willst.
@SuperUser "... interrupt service routine mit einer zeitintensiven Berechnung ..." Da schrillen bei mir sofort die Alarmglocken. "Interrupt" und "Zeitintensiv" vertragen sich überhaupt nicht miteinander. In der Regel ist es nämlich möglich, im Interrupt nur die Parameter zu sichern und dann die eigentliche Berechnung in aller Ruhe in der Mainloop zu machen. Ich hab z.B. mal sowas verrücktes gesehen, im Multiplexinterrupt die Digits jedesmal neu aus einer float-Zahl berechnen zu lassen statt einmalig alle Digits zu berechnen, deren 7-Segment-Code im RAM zu hinterlegen und den Multiplexinterrupt einfach nur das jeweilige Byte ausgeben zu lassen. Bei ersterem schwitzt die CPU mächtig und bei letzterem gähnt sie nur ständig. Peter
Hallo Peter, das ist hier anders. Es läuft ein Filter in Realtime und burst mode. Der Filteraufwand ist abhängig vom Zustand. Worst case bleiben 300 Clocks für den Interrupt. Ich schätze im Moment das ich 200Takte für den worst case Filter brauche - wenn optimal in ASM implementiert. Das mit den volatile register probiere ich mal aus, glaube aber nicht, das das hilft. Der Compiler optimiert die Zuweisung ja weg, da der Pointer in C ja nicht benötigt wird - sollte egal sein ob volatile oder nicht oder?
> Das mit den volatile register probiere ich mal aus, glaube aber > nicht, das das hilft. Das ist ja schon wie Gotteslästerung :-)
> Der Compiler optimiert die Zuweisung ja weg, da der Pointer in C ja > nicht benötigt wird - sollte egal sein ob volatile oder nicht oder? Du hast den Sinn von volatile einfach noch nicht begriffen.
Ich freue mich, wenn's mit volatile klappt, kann es leider hier nicht ausprobieren - werde heute abend berichten. Ich stelle mir das also so vor: Da ich die Register als volatile deklariere, muss der Compiler davon ausgehen, dass die Register ausserhalb der ISR noch verändert werden und sie also anlegen, obwohl sie in der ISR - aus Sicht des Compilers - nicht verwendet werden. Richtig? (Würde ich schon fast als Trick bezeichnen :-) Nur, die Variable an sich sind eigentlich ausserhalb der ISR nicht sichtbar, es sind lokale Variablen. Daher ist obiger Rückschluss eigentlich nicht gültig - oder eine Sonderdefinition für Register?
Ich hatte gehofft, das es eine #pragma Anweisung oder ähnliches für den Compiler gibt. In der Art: Do not remove this line of code Ich muss mir nochmal die Zeit nehmen, mich durch die gcc Doku zu quälen...
Als SuperUser solltest du das doch aber wissen, oder? SCNR... Der GCC benutzt keine #pragmas (außer dort, wo sie vom C-Standard vorgeschrieben sind).
@Jörg, SuperUser sind auch nicht mehr das was sie mal waren.... Ich hab's gerade getestet: volatile register int8_t* ref_ptr asm("r24"); bringt, wie befürchtet, gar nichts. Die Zuweisung ref_ptr=ref_tab; wird weiterhin weg-optimiert :-( Ich gebe jetzt auf und akzeptiere die zusätzliche Kopiererei erstmal.
Das volatile muss sich auch auf das was wegoptimiert wird beziehen. Also ref_ptr. Grüße Andreas
Bau mal eine compilierbare Datei und klebe sie als Attachment ins Forum.
@AndreasH du meinst: register int8_t* volatile ref_ptr asm("r24"); ? habe ich natürlich auch probiert, geht auch nicht :-( -> ich habe mich aber bereits damit abgefunden und das Konzept geändert (ein pointer weniger). Ich brauche also keine Lösung mehr. Vielen Dank für die Hilfe!! (Bei Bedarf stelle ich aber trotzdem eine compilierbare Datei zur Verfügung) P.S: Ich habe auch mal testweise den assembler code in eine eigene function gelegt, allerdings ist der Overhead deutlich höher als bei inline assembler.
Dein Problem ist, daß ref_ptr und val_ptr nicht als Eingangsparameter deines asm definiert sind. Deshalb weiß der Compiler nicht, daß die dort gebraucht werden. Übrigens: Wenn ich volatile register versuche, bringt mir der Compiler immer eine Warnung, daß das nicht das tue, was ich will. Was es stattdessen tut, sagt er aber leider nicht.
Hallo Rolf, genau darum wollte ich spezielle Register für die Pointer, um mir die Eingangsparameter zu sparen. Jeder Eingangsparameter wird nämlich noch einmal kopiert (erster pointer ins Y-reg, zweiter ins Z-reg, dritter weiss ich nicht ...) Also lege ich die pointer auf bekannte Register und kann dann direkt und schnell darauf zugreifen - so die Theorie. Funktioniert auch, aber nur wenn die Pointer auch in C verwendet werden. Sonst sind sie wegoptimiert....
Pardon, habe mich vertan, natürlich nicht Y-reg. sondern erster ins Z zweiter ins X.
> genau darum wollte ich spezielle Register für die Pointer, um mir > die Eingangsparameter zu sparen. Jeder Eingangsparameter wird > nämlich noch einmal kopiert (erster pointer ins Y-reg, zweiter ins > Z-reg, dritter weiss ich nicht ...) Passiert das nicht nur, wenn du als Parametertyp "e" wählst? Aber man kann auch direkt Registernamen als Parameter nutzen. Siehe avr-libc-Dokumentation oder die von gcc, z.B.: http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Extended-Asm.html#Extended-Asm
Nur so eine Idee: Wenn du dem gcc einen Parameter -ffixed-r22 mit gibst, dann sollte er die Finger von diesem Register lassen. Dieses Register steht dann auch nicht mehr für optimierten Code zur Verfügung, das ist der Nachteil. Tom
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.