Forum: Compiler & IDEs Register reservieren in avr-gcc


von AVR-Nutzer (Gast)


Lesenswert?

Hallo,

ich möchte einzelne Register in avr-gcc fest verwenden. Dazu gibt es 
eine Syntax im Wiki-Artikel AVR-GCC-Codeoptimierung. Die habe ich 
auch schon vor Jahren erfolgreich verwendet.
1
register uint8_t more_flags asm("r2");

Nun hat Falk an diese Stelle im Wiki eine dicke Warnung plaziert, dass 
es zu Problemen kommen kann. Im AVR Libc FAQ steht, dass die Register 
r2-r7 bedenkenlos auf diese Weise genutzt werden können, wenn keine 
Quellen eingebettet werden, die unter anderen Annahmen kompiliert 
wurden.

Warum soll man sich also vor der Verwendung hüten? Welche Probleme 
können auftauchen, wenn ich das komplette Programm auf einmal übersetze?

Leider konnte ich keine weiteren Details/Hintergründe dazu finden.

: Verschoben durch Admin
von Crisduf (Gast)


Lesenswert?

>Warum soll man sich also vor der Verwendung hüten?

Liefere erst mal einen Grund, warum Du das zu brauchen meinst!

von Stefan E. (sternst)


Lesenswert?

AVR-Nutzer schrieb im Beitrag #4897528:
> Warum soll man sich also vor der Verwendung hüten? Welche Probleme
> können auftauchen, wenn ich das komplette Programm auf einmal übersetze?

Weil immer auch bereits übersetzter Code (aus Libraries) hinzukommt, der 
von deiner Reservierung nichts weiß und das Register möglicherweise 
verwendet.

von Carl D. (jcw2)


Lesenswert?

Es gibt doch ein einfaches Verfahren, um zu prüfen, ob man ein Register 
fest zuweisen kann. Erst mal ohne Zuweisung übersetzen, .lss File nach 
dem Register durchsuchen und bei Nichtfinden sicher sein.

von Stefan E. (sternst)


Lesenswert?

Carl D. schrieb:
> Es gibt doch ein einfaches Verfahren, um zu prüfen, ob man ein Register
> fest zuweisen kann. Erst mal ohne Zuweisung übersetzen, .lss File nach
> dem Register durchsuchen und bei Nichtfinden sicher sein.

Das musst du dann aber auch immer wieder machen. Schon eine kleine 
Änderung in den Sourcen kann zusätzlichen Code aus Libraries rein 
ziehen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan E. schrieb:
> Das musst du dann aber auch immer wieder machen. Schon eine kleine
> Änderung in den Sourcen kann zusätzlichen Code aus Libraries rein
> ziehen.

...oder dass der vorliegende Code anders übersetzt wird.

Eigentlich muss jedes Modul mit -ffixed-2 übersetzt werden, und zwar 
auch solche, die R2 nicht verwenden.

Ein weiteres Problem mit globalen Registern ist, dass diese nicht 
volatile sein können, diele Anwender aber gerne Kommunikation mit einer 
ISR darüber abwickeln möchten.

von Bernd K. (prof7bit)


Lesenswert?

Carl D. schrieb:
> .lss File nach
> dem Register durchsuchen und bei Nichtfinden sicher sein.

Sicher sein?

War das jetzt Satire oder irgendein aufs Programmieren transponierter 
Insider-Running-Gag den ich zufällig noch nicht kenne weil ich die 
falschen Fernsehserien sehe? Oder was?

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Denke, .lss meint das List-File (heißen bei mir .lst ?).
Dort sind unter Anderem alle Register und Deren Anzahl an Aufrufen im 
Code enthalten.

Wenn r6 0 dort steht, wird r6 nicht benutzt und kann beliebig für eigene 
Zwecke verunglimpft werden.

Allerdings muß man, wenn man weiteren Code einbindet, immer schauen, ob 
die Nutzung des eigenen Register sich nicht schlagartig geändert hat - 
dann spielt nämlich noch wer Anders mit diesem Register.

MfG

von Zagg (Gast)


Lesenswert?

Aber Register lassen sich auch indirekt adressieren. Einige 
ASM-Beispiele aus den AppNotes machen das auch - mal als Beispiel 
genannt.

von AVR-Nutzer (Gast)


Lesenswert?

@Crisduf: Das beantwortet meine Frage nicht. Der Grund steht aber schon 
da: Ich "brauche" more_flags (bitadressierbar, schneller Zugriff)

@Stefan Ernst: "immer ... code hinzukommt": Da wirst du wohl die 
erwähnte AVR Libc meinen, die ja explizit die Reservierung von r2-r7 für 
unbedenklich hält). Geht das FAQ davon aus, dass ich dafür die Libc neu 
übersetze und schreibt das nicht, oder gibt es noch eine andere Quelle, 
aus der übersetzter Code in meinem Programm landen könnte?

von Stefan E. (sternst)


Lesenswert?

AVR-Nutzer schrieb im Beitrag #4898207:
> oder gibt es noch eine andere Quelle,
> aus der übersetzter Code in meinem Programm landen könnte?

Ja, die Libraries des Compilers. Wenn du z.B. den Divisions- oder 
Modulo-Operator verwendest, landen dafür Funktionen aus diesen Libraries 
in deinem Code (außer natürlich es lässt sich zu was anderem optimieren, 
wie Shiften).
Oder auch (noch weniger offensichtlich) bei einem switch, wenn der 
Compiler dieses über eine Sprungtabelle realisiert.
Um nur mal zwei Beispiele zu nennen.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan E. schrieb:
> AVR-Nutzer schrieb im Beitrag #4898207:
>> oder gibt es noch eine andere Quelle,
>> aus der übersetzter Code in meinem Programm landen könnte?
>
> Ja, die Libraries des Compilers.

Die avr-libgcc verwendet R2-R7 nicht — mit einer Ausnahme:  Die 
Funktionen, die für -mcall-prologues verwendet werden.  Bei diesen ist 
es vom Caller abhängig, welche Register verwendet werden.

Die Strategie zur Verwendung globaler Register ist also:

0. Überprüfen, ob diese wirklich notwendig / hilfreich sind :-)

1. Alle eigenen Module mit -ffixed-2 etc. übersetzen.

2. Verifizieren, dass keine Fremdmodule (libc, libm, libgcc, Vendor-
   spezifische Module / Bibliotheken) die entsprechenden Register
   verwenden.  Mit Ausnahme von 3. verwendet libgcc R2-R7 nicht.

3. Falls __prologue_saves / __epilogue_restores der libgcc gelinkt
   werden, sind alle Caller zu überprüfen, wie diese die genannten
   Funktionen verwenden.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Die Register R2 bis R17 werden von aufgerufenen Funktionen, die sie
benutzen, hinterher wieder auf ihren alten Wert zurückgesetzt. Das gilt
selbstverständlich auch für Bibliotheksfunktionen. Deswegen kann man
alle diese Register als globale Variablen verwenden, wenn man folgende
Dinge beachtet:

1. Wenn aus einer Interruptroutine auf globale Registervariablen
   zugegriffen wird, müssen alle Funktionen, die von dem Interrupt
   unterbrochen werden können (also i.Allg. der komplette Code
   einschließlich aller Bibliotheken), mit der Registerdeklaration oder
   der -ffixed-Option neu kompiliert werden.

2. Wenn aus einer Callback-Funktion auf globale Registervariablen
   zugegriffen wird, müssen mindestens alle direkten und indirekten
   Aufrufer dieser Funktion mit der Registerdeklaration oder der
   -ffixed-Option neu kompiliert werden.

3. Da die Register R8 bis R17 beim Aufruf von Funktionen, deren
   Argumentlisten größer als 8 Bytes sind, für die Übergabe von
   Funktionsargumenten genutzt werden, kann es zu einem Konflikt kommen,
   wenn eines dieser Register als globale Registervariable verwendet
   wird. Der Compiler gibt dann aber die Warnung

     fixed register r<i> used to pass parameter to function

   aus.

Diese Liste habe ich mir eben ausgedacht und ist deswegen möglicherweise
unvollständig. Wenn jemand noch weitere Fallstricke in Verbindung mit
globalen Registervariablen kennt, möge er sie nennen.


Johann L. schrieb:
> Die avr-libgcc verwendet R2-R7 nicht — mit einer Ausnahme:  Die
> Funktionen, die für -mcall-prologues verwendet werden.

Ist das garantiert? Auch für die Zukunft? Der GCC an sich verwendet
diese Register ja schon.

von AVR-Nutzer (Gast)


Lesenswert?

Danke, insbesondere an die letzten drei Beiträge. Damit weiß ich jetzt 
besser, woran ich bin und was zu tun ist.

Ich werde weiterhin versuchen diese Register möglichst nicht reservieren 
zu müssen. Allerdings war es etwas unbefriedigend keinen konkreten Grund 
für den Verzicht zu kennen.

Ich habe diese Diskussion im Warnhinweis verlinkt, falls mal wieder 
jemand an der Begründung hängen bleibt und lieber Hintergründe anstelle 
Best-Practice-Ratschläge erfahren möchte.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

AVR-Nutzer schrieb im Beitrag #4898207:
> bitadressierbar, schneller Zugriff

Falls dein verwendeter Controller es unterstützt, könntest du über
ein GPIOx-Register stattdessen nachdenken.  Auch beliebige andere,
gerade nicht benutzte IO-Register kleiner 0x20 sind dafür geeignet.

Der Vorteil ist, dass dir hier garantiert niemand anders in die Suppe
spucken kann. ;)

von AVR-Nutzer (Gast)


Lesenswert?

Hallo Jörg,
ich verwende bereits das GPIOR0. Die Register GPIOR1 und GPIOR2 sind 
oberhalb von 0x1F. Meine Hoffnung war, dass es nicht notwendig ist DDRx- 
oder PORTx-Bits ungenutzter Ausgänge zu toggeln. Die Register der 
Interrupt-Flags sind in diesem Zusammenhang auch nicht hilfreich. Ich 
werde jetzt vorerst mal meine Flags an solchen Orten unterbringen. 
Sobald ich die Zeit finde, versuche ich evtl. das mit den reservierten 
Registern sauber umzusetzen.

Ich kann aktuell aber auch noch nicht genau sagen, ob ich nicht doch mit 
langsameren Zugriffen auskomme, oder ob ich sogar darauf angewiesen bin 
Einzelheiten in anderer Hardware (z.B. diskret) zu realisieren.
Aktuell bin ich nicht am optimieren der Performance, sondern an der 
Implementierung des Proof-Of-Concept.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

AVR-Nutzer schrieb im Beitrag #4900318:
> ich verwende bereits das GPIOR0

OK, dann bist du natürlich schon in einem Bereich, wo es den Aufwand
lohnen kann, auch mal Register zu reservieren.  Die Hinweise, auf was
man dabei achten sollte, sind ja im Thread ausreichend vorhanden.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Johann L. schrieb:
>> Die avr-libgcc verwendet R2-R7 nicht — mit einer Ausnahme:  Die
>> Funktionen, die für -mcall-prologues verwendet werden.
>
> Ist das garantiert?

Momentan ist es gegeben durch die Codebasis der libgcc, die zum Großteil 
in Assembler steht.  Es gibt zwar noch Funktionen, die in C 
implementiert sind, aber die wirst Du fleißig suchen müssen und in wenig 
verwendeten Ecken wie Fixedpoint auch finden.

> Auch für die Zukunft?

Dokumentiert ist das Verhalten nicht, und die Generierung erfolgt ohne 
-ffixed o.ä.  Was den asm-Code angeht, ist die Frage also, ob es andere 
Leute gibt, die zur libgcc beitragen.  In den letzten Jahren war das 
nicht der Fall — bis auf den Code von Sean D'Epagnier, der allerdings 
nicht von ihm selbst integriert wurde.

von Markus F. (mfro)


Lesenswert?

Müsste nicht - wenn man die gesamte Toolchain mit -ffixed-xx neu baut - 
bei Erfolg "weitgehende Problemfreiheit" garantiert sein?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Müsste nicht - wenn man die gesamte Toolchain mit -ffixed-xx neu baut -
> bei Erfolg "weitgehende Problemfreiheit" garantiert sein?

Die Tools neu zu generieren hilft nix, es geht um die 
Target-Bibliotheken.

Wie auch immer, bisher war es niemandem wichtig genug, das zu ändern. 
Und ob das in Bezug auf die AVR-Libc hilft wäre abzuklären, denn auch 
diese implementiert viele Funktionen in handverlesenem Assembler.

Mir ist auch noch nicht zu Ohren gekommen, dass jemand tatsächlich 
Probleme mit solchen Kollisionen hatte.  Das mag daran liegen, dass 
globale Register nicht oft eingesetzt werden, wohl auch weil die 
Realität hinter den Erwartungen zurückbleibt.

Neben Problemen der Anwendung wie o.g dass globale Register nicht 
volatile sind und daher asynchrone Verwendung nicht ohne zusätzlichen 
Inline-Asm funktioniert, sowie potentielle Kollisionen mit Verwendung in 
Libs, sind die folgende Punkte zu berücksichtigen:

o Weil globale Register keine ABI-Register sein dürfen, sind es
  untere Register R2...R9, die weniger Instruktionen zulassen;
  insbesondere keine mit Konstanten wie LDI, SUBI, CPI, ANDI, ...
  Der Compiler wird dann obere Regs verwenden und MOVs etc. erzeugen.

o Ein Register global zu machen, sagt dem Compiler: "Verwende
  dieses Register nicht zum Allokieren für einen Wert" was
  bedeutet, dass manche Optimierungen nicht auf globalen Registern
  ausgeführt werden und die Codequalität hinter "normalen" Registern
  zurückbleibt.

Da Verwendung globaler Regs ausschließlich durch (Spekulation über) 
bessere Codeerzeugung motiviert ist, sind diese beiden Punkte auch 
relevant und sollten in die Entscheidung eingehen.  I.d.R. geht es dabei 
um kleine ISRs, wo der robuste und erfolgversprechende Ansatz ist, diese 
in Assembler zu schreiben (Portabilität ist eh schon futsch).

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
Noch kein Account? Hier anmelden.