Hallo! Ich programmiere einen LEON 3 SPARC 32bit-Microproc obwohl ich keine Ahnung davon habe. Ich will eine Adresse bitweise ansprechen koennen und habe mir diesen Source Code einfallen lassen: typedef struct { unsigned int divider : 12; clk_divider unsigned int test : 4; unsigned int rest : 16; } config ; volatile config * ConfigReg = (config *) 0x80000b00; // 80000b00 ist //die Adresse in die ich schreiben moechte main() { ConfigReg->divider = 0xeae; ConfigReg->test = 0xF; ConfigReg->rest = 0x1234; } Wenn ich das laufen lasse steht nachher das an der Adresse: 0x80000b00 I/O data register 0x12341234 Rest wird zweimal reingeschrieben, das andere is weg. Wenn ich den Struct aber so deklariere: typedef struct { unsigned int divider : 12; unsigned int test : 20; } config ; volatile config * ConfigReg = (config *) 0x80000b00; main() { ConfigReg->divider = 0xeae; ConfigReg->test = 0xF1234; } kommt korrekterweise dies raus: 0x80000b00 I/O data register 0xeaef1234 Kann mir jemand vielleicht den Unterschied erklaeren? Muss/ kann ich mein struct so deklarieren, dass der Compiler 32-bit dafuer reserviert? Was mache ich falsch? Compiler is sparc-elf-gcc. Fuer Hinweise bin ich sehr dankbar!
Obwohl mir beide Beispiele eigenlich richtig erscheinen, und das selbe Ergebnis liefern sollten, würde ich generell davon abraten ein Cofigurationsregister so anzusprechen, wie Du es gemacht hast. Das Problem ist, daß Du keine richtige Kontrolle darüber hast, welchen Kode der Compiler generiert. Im Prinzip könnte der Compiler die 3 Anweisungen ConfigReg->divider = 0xeae; ConfigReg->test = 0xF; ConfigReg->rest = 0x1234; zu einer zusammenfassen und mit einer Schreiboperation 0xeaef1234 schreiben. Der Compiler kann aber nicht wissen, ob das gewünscht ist, schließlich hast Du das Register sogar als volatile deklariert. Der Compiler wird also möglicherweise zuerst immer das Register lesen, den Wert hineinmaskieren und das Register schreiben. Es ergeben sich somit wahrscheinlich 3 Leseoperationen und 3 Schreiboperation, wo eine Schreiboperation wahrscheinlich genügt hätte. Wenn die Leseoperationen des Config-Registers dann in Hardware sogar irgendwelche Aktionen auslösen, um so schlimmer. Du sollest deshalb das Config-Register als unsigned int deklarieren und deine Bits selbst zusammenstellen. Grüße Klaus
Klaus Falser wrote: > Du sollest deshalb das Config-Register als unsigned int deklarieren und > deine Bits selbst zusammenstellen. Es genügt vollkommen, die einzelnen Bitfelder selbst als volatile zu deklarieren. Was allerdings in der Tat compilerabhängig ist, ist die Zählrichtung der Bits innerhalb des Bitfeldes.
Man sollte Bitfelder nicht verwenden, das ist meine Meinung. Bei der systemnahen Programmierung braucht es die Kontrolle über jeden Registerzugriff, bei der Verwendung von hat man diese Kontrolle nicht mehr.
Klaus Falser wrote: > Man sollte Bitfelder nicht verwenden, das ist meine Meinung. Die Meinung sei dir unbenommen, aber... > Bei der systemnahen Programmierung braucht es die Kontrolle über jeden > Registerzugriff, bei der Verwendung von hat man diese Kontrolle nicht > mehr. ...das ist einfach Quatsch bzw. ein Vorurteil. Die Kontrolle hast du dort ganz genauso. Die Wahlfreiheit des Compilers beschränkt sich auf die Sortierrichtung der Bits, sonst nichts.
> Die Kontrolle hast du dort ganz genauso.
Das dürfte nicht stimmen.
Nimm das Beispiel aus dem Quellcode oben:
ConfigReg->divider = 0xeae;
ConfigReg->test = 0xF;
ConfigReg->rest = 0x1234;
Diese ändern alle das selbe Register. Wie kann der Compiler wissen, ob 3
Schreibzugriffe gewünscht und notwendig sind, oder ob ein einziger
Zugriff genügt, der alle Bits gleichzeitig ändern?
Wenn hinter dem ConfigReg Register Hardware steckt (was anzunehmen ist),
dann kann dies einen großen Unterschied machen.
Oder du möchtest nur die Bits von test ändern :
ConfigReg->test = 0xA;
Wie soll wiederum der Compiler wissen, welche Bits ins restliche Word
geschrieben werden sollen? Nachdem er wahrscheinlich anmimmt, daß diese
gleich bleiben sollen, wird er das Register vorher lesen, die Bits von
"test" ändern und das Word wieder zurückschreiben.
Diese Lesezugriff muß nicht notwendig sein, weil der Programmierer
meistens weiss, wie die restlichen Bits gesetzt werden sollen.
Im schlimmsten Fall kann der Lesezugriff irgendeine Hardware-Aktion
auslösen, die gar nicht gewüscht ist.
Die Verwendung von volatile verschlimmert die Situation meiner Meinung
nach sogar, weil sie dem Compiler mitteilt, daß er keine Annahme über
den Inhalt des Registers treffen darf. Der Compiler muß also Code
erzeugen, der das Register ausliest, dem Wert ändert und wieder
zurückschreibt.
Grüße
Klaus
Klaus Falser wrote: > Diese ändern alle das selbe Register. Wie kann der Compiler wissen, ob 3 > Schreibzugriffe gewünscht und notwendig sind, oder ob ein einziger > Zugriff genügt, der alle Bits gleichzeitig ändern? Schrieb ich doch: indem man die einzelnen Subregister "volatile" deklariert, statt des kompletten Registers. Andere Sprachen (Ada) haben sowas auch, und es funktioniert dort. Ich würdes es auch nicht so machen, aber das ist ne andere Frage. Es ging um deine Behauptung, dass man nicht die Kontrolle darüber hätte. Übrigens gibt's auch für den AVR Leute, die die Registerdefinitionen als Bitfelder umgebogen haben. All die Optimierungen, die sonst bereits funktionieren, funktionieren dort genauso, also bis zur Generierung von SBI- und CBI-Befehlen. Es gibt wirklich keinen Unterschied im erzeugten Code zur manuellen Manipulation der Bits.
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.