Forum: Compiler & IDEs struct auf Adresse legen


von Confusius (Gast)


Lesenswert?

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!

von anyone (Gast)


Lesenswert?

#define ConfigReg (*((volatile struct config*)0x80000b00))

von anyone (Gast)


Lesenswert?

sorry, habs nich gelesn :(

von Klaus Falser (Gast)


Lesenswert?

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

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


Lesenswert?

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.

von Klaus Falser (Gast)


Lesenswert?

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.

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


Lesenswert?

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.

von Klaus Falser (Gast)


Lesenswert?

> 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

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


Lesenswert?

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