Was macht der C-Compiler mit Bitfeldern?

8

Ich arbeite an einem Embedded-Projekt (PowerPC-Ziel, Freescale Metrowerks Codewarrior Compiler), wo die Register Memory-Mapped und in nice Bitfields definiert sind, um die einzelnen Bit-Flags einfach zu drehen.

Momentan verwenden wir diese Funktion, um Interrupt-Flags zu löschen und die Datenübertragung zu steuern. Obwohl ich noch keine Fehler bemerkt habe, war ich neugierig, ob das sicher ist. Gibt es eine Möglichkeit, Bitfelder sicher zu verwenden, oder muss ich jedes in DISABLE_INTERRUPTS ... ENABLE_INTERRUPTS umbrechen?

Zur Verdeutlichung: Der mit dem Mikro mitgelieferte Header hat Felder wie

%Vor%

Ich nehme an, dass das Setzen eines Bits in einem Bitfeld nicht atomar ist. Ist das eine korrekte Annahme? Welche Art von Code erzeugt der Compiler tatsächlich für Bitfelder? Wenn ich die Maske selbst mit dem Feld R (Raw) ausführe, kann es leichter sein, sich daran zu erinnern, dass die Operation nicht atomar ist (man vergisst leicht, dass eine Zuweisung wie CAN_A.IMASK1.B.BUF00M = 1 nicht atomar ist).

Ihr Rat wird geschätzt.

    
Adam Shiemke 21.07.2010, 13:46
quelle

6 Antworten

3

Die Atomarität hängt vom Ziel und vom Compiler ab. AVR-GCC versucht zum Beispiel, den Bit-Zugriff zu detektieren und bit-set- oder clear-Anweisungen auszugeben, wenn möglich. Überprüfen Sie den Assembler-Ausgang, um sicher zu sein ...

EDIT: Hier ist eine Ressource für atomare Anweisungen auf PowerPC direkt aus dem Maul des Pferdes:

Ссылка

    
Peter G. 21.07.2010, 13:49
quelle
3

Es ist richtig anzunehmen, dass das Setzen von Bitfeldern nicht atomar ist. Der C-Standard ist nicht besonders klar, wie Bitfelder implementiert werden sollten und verschiedene Compiler gehen auf verschiedene Arten auf ihnen vor.

Wenn Sie sich wirklich nur für Ihre Zielarchitektur und Ihren Compiler interessieren, zerlegen Sie einen Objektcode.

Im Allgemeinen wird Ihr Code das gewünschte Ergebnis erzielen, aber viel weniger effizient sein als Code, der Makros und Verschiebungen verwendet. Das heißt, es ist wahrscheinlich lesbarer, Ihre Bitfelder zu verwenden, wenn Sie sich hier nicht um die Leistung kümmern.

Sie könnten immer eine Setter-Wrapper-Funktion für die Bits schreiben, die atomar ist, wenn Sie Bedenken haben, dass zukünftige Programmierer (einschließlich Sie selbst) verwirrt sind.

    
nmichaels 21.07.2010 13:50
quelle
3

Ja, Ihre Annahme ist richtig, in dem Sinne, dass Sie Atomizität nicht annehmen können. Auf einer bestimmten Plattform können Sie es als Extra erhalten, aber Sie können sich in keinem Fall darauf verlassen.

Grundsätzlich führt der Compiler Maskierungen und Dinge für Sie durch. Er könnte in der Lage sein, Eckkästen oder spezielle Anweisungen zu nutzen. Wenn Sie an Effizienz interessiert sind, schauen Sie sich den Assembler an, den Ihr Compiler damit erstellt, normalerweise ist er ziemlich lehrreich. Als Faustregel würde ich sagen, dass moderne Compiler Code produzieren, der so effizient ist wie der durchschnittliche Programmieraufwand. Ein echtes Deep Bit Twiddeling für deinen spezifischen Compiler könnte dir vielleicht ein paar Zyklen einbringen.

    
Jens Gustedt 21.07.2010 13:56
quelle
3

Ich denke, dass die Verwendung von Bitfeldern zur Modellierung von Hardwareregistern keine gute Idee ist.

So viel darüber, wie Bitfelder von einem Compiler gehandhabt werden, ist implementationsdefiniert (einschließlich, wie Felder behandelt werden, die Byte- oder Wortgrenzen umfassen, Endianess-Probleme und genau, wie das Holen, Setzen und Löschen von Bits implementiert wird). Siehe C / C ++: Bitfeldreihenfolge und Ausrichtung erzwingen

Um zu überprüfen, ob die Registerzugriffe so gehandhabt werden, wie Sie erwarten oder behandelt werden müssen, müssten Sie die Compiler-Dokumente sorgfältig untersuchen und / oder den ausgegebenen Code betrachten. Ich nehme an, dass, wenn die mit dem Mikroprozessor-Toolset gelieferten Header sie verwenden, Sie davon ausgehen können, dass die meisten meiner Sorgen erledigt sind. Ich vermute jedoch, dass atomarer Zugriff nicht unbedingt ...

ist

Ich denke, es ist am besten, diese Art von Bit-Level-Zugriffen von Hardware-Registern mit Funktionen (oder Makros, wenn Sie müssen), die explizite Lese- / Modifizierungs- / Schreiboperationen mit der Bitmaske durchführen, die Sie brauchen, zu handhaben Prozessor benötigt.

Diese Funktionen könnten für Architekturen modifiziert werden, die atomare Bit-Level-Zugriffe unterstützen (wie etwa die "Bit-Banding" -Adressierung des ARM Cortex M3). Ich weiß nicht, ob der PowerPC so etwas unterstützt - der M3 ist der einzige Prozessor, mit dem ich es zu tun habe, der es allgemein unterstützt. Und selbst das M3-Bit-Banding unterstützt 1-Bit-Zugriffe; Wenn Sie mit einem 6 Bit breiten Feld zu tun haben, müssen Sie zum Szenario Lesen / Ändern / Schreiben zurückkehren.

    
Michael Burr 21.07.2010 17:21
quelle
0

Es hängt vollständig von der Architektur und dem Compiler ab, ob die Bitfeldoperationen atomar sind oder nicht. Meine persönliche Erfahrung sagt: Verwenden Sie keine Bitfelder, wenn Sie nicht müssen.

    
kmalmur 21.07.2010 13:51
quelle
0

Ich bin mir ziemlich sicher, dass dies bei PowerPC nicht atomar ist, aber wenn Ihr Ziel ein Single-Core-System ist, dann können Sie einfach:

%Vor%

Ich erinnere mich nicht, ob Powerpc's Interrupt-Handler unterbrechbar sind, aber wenn sie dann sind, sollten Sie immer die zweite Version verwenden.

Wenn Ihr Ziel ein Multiprozessorsystem ist, sollten Sie Sperren (Spinlocks, die Interrupts auf dem lokalen Prozessor deaktivieren und dann darauf warten, dass alle anderen Prozessoren mit der Sperre fertig sind), die den Zugriff auf Dinge wie Hardwareregister schützen und die benötigte Sperren, bevor Sie auf das Register zugreifen, und geben Sie dann die Sperren sofort nach dem Aktualisieren des Registers (oder der Register) frei.

Ich habe einmal gelesen, wie Sperren in PowerPC implementiert werden - es bedeutete, dass der Prozessor den Speicherbus nach einer bestimmten Adresse beobachtete, während Sie einige Operationen durchführten, und dann am Ende dieser Operationen nachprüfte, ob die Watch-Adresse vorhanden war wurde von einem anderen Kern geschrieben. Wenn es nicht so war, war Ihre Operation erfolgreich; wenn es dann war, musste man die Operation wiederholen. Dies war in einem Dokument für Compiler, Bibliothek und OS-Entwickler geschrieben. Ich kann mich nicht erinnern, wo ich es gefunden habe (wahrscheinlich irgendwo auf IBM.com), aber ein wenig Jagd sollte es aufdrehen. Es hat wahrscheinlich auch Informationen darüber, wie man atomare Bit-Drehungen durchführt.

    
nategoose 21.07.2010 14:32
quelle

Tags und Links