www.mikrocontroller.net

Forum: Compiler & IDEs struct auf Adresse legen


Autor: Confusius (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: anyone (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define ConfigReg (*((volatile struct config*)0x80000b00))

Autor: anyone (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, habs nich gelesn :(

Autor: Klaus Falser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Falser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Falser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.