Forum: Compiler & IDEs Kompatibilitaet von structs an absoluten Positionen


von Olaf (Gast)


Lesenswert?

Ich habe hier den C-Compiler von Renesas fuer SH. Fuer den liefert 
Renesas ein File fuer die Registerdefinitionen der CPUs mit.

Das sieht in etwa so aus:

struct st_iic3 {                                /* struct IIC3  */
       union {                                  /* ICCR1        */
             _UBYTE BYTE;                       /*  Byte Access */
             struct {                           /*  Bit Access  */
                    _UBYTE ICE:1;               /*   ICE        */
                    _UBYTE RCVD:1;              /*   RCVD       */
                    _UBYTE MST:1;               /*   MST        */
                    _UBYTE TRS:1;               /*   TRS        */
                    _UBYTE CKS:4;               /*   CKS        */
                    } BIT;                      /*              */
             } ICCR1;                           /*              */
[einiges gekuerzt]
      union {                                  /* NF2CYC       */
             _UBYTE BYTE;                       /*  Byte Access */
             struct {                           /*  Bit Access  */
                    _UBYTE :6;                  /*              */
                    _UBYTE PRS:1;               /*   PRS        */
                    _UBYTE NF2CYC:1;            /*   NF2CYC     */
                    } BIT;                      /*              */
             } NF2CYC;                          /*              */
};                                              /*              */

#define IIC3_1 (  *(volatile struct st_iic3 *) 0xFFFEE400 ) /* IIC3_1 
Address */

Ein Zugriff auf ein Bit ist dann zum Beispiel einfach so moeglich:

IIC3_1.ICCR1.BIT.ICE = 1;

Ich wuerde gerne dieses File auch unter dem gcc nutzen. Der Prozessor 
hat eine ganze Menge Register und das File ist 600kbyte gross. Das 
schreibt man nicht mal eben so neu.

Es ist auch kein Problem das einzubinden und ich habe damit auch schon 
einiges programmiert. Es sollte also funktionieren. Allerdings habe ich 
hier auch einen relativ schlichten Programmteil (i2c-bus) der mit dem 
Compiler von Renesas funktioniert, mit dem gcc aber nicht.

Daher meine Frage ob soetwas portabel ist, oder ob es sein kann das der 
gcc die Reihenfolge der Bits oder anderer Elemente umsortiert?

Olaf

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

die Anordnung der Bits in einem Bitfeld ist vom C Standard nicht 
vorgeschrieben -> "Implementation defined". Du kannst dich also nicht 
darauf verlassen wir der Compiler die Bits anordnet.

Matthias

von Olaf (Gast)


Lesenswert?

>  Du kannst dich also nicht
> darauf verlassen wir der Compiler die Bits anordnet.

Hm..gut, oder auch schlimm.

Allerdings habe ich mittlerweile herausgefunden das auch soetwas
nicht funktioniert:

   pointer = (void*) 0xfffee402;  //Adress of ICMR_1
   vari1 = *pointer;

Ich lese hier ein Register indem laut Datenblatt des Controllers 
bestimmte Bits immer 1 sein muessen, aber bekomme trotzdem null raus. 
Woran es auch immer liegt, der vom gcc erzeugten Assemblercode sieht 
unauffaellig aus, es liegt jedenfalls erstmal nicht an den structs.

Der zugriff ueber structs:

   vari1 = IIC3_1.ICMR.BYTE;

fuehrt zum selben falschen Ergebnis. Die structs sind also unschuldig.

Olaf

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

>...
>pointer = (void*) 0xfffee402;  //Adress of ICMR_1
>vari1 = *pointer;
>...
Typ von pointer und vari1? Adresse impliziert 
"16-bit"-Zugriffsmöglichkeit. So etwas ausprobiert?:
1
#define TESTREG (*((volatile unsigned short*) 0xfffee402))
2
volatile unsigned short val;
3
int main(void) { val = TESTREG; while(1) {;} return 0;}
val sollte so im Debugger "watchbar" sein, zumindest sollte ein 
Core-Register den Wert von TESTREG enthalten.

Aktuelle Version der KPIT GNU tools im Einsatz? Falls nicht, könnte sich 
ein Update lohnen. Denn wenn richtig erinnert, ist im mitgelieferten GNU 
Compiler die Funktionalität von -fstrict-volatile-bitfields enthalten 
und per default aktiviert. Damit sind die Aussichten auf Funktion des 
"struct/union/Bitfelder über Hardwareregistern"-Ansatzes besser.

von Olaf (Gast)


Lesenswert?

> Typ von pointer und vari1? Adresse impliziert
> "16-bit"-Zugriffsmöglichkeit. So etwas ausprobiert?

Daran lag es nicht. Das Register ICMR soll zwar immer 0x38 liefern,
aber macht das wohl erst wenn das gesamte I2C-Modul eingeschaltet ist.

Allerdings hatte ich I2C eingeschaltet. Und zwar so:

 CPG.STBCR5.BIT.MSTP56 =       0;

Das funktioniert aber nicht. Schalte ich es dagegen so
ein:

  pointer = (void*) 0xfffe0410;  //STBCR5 Register
  *pointer &= ~0x40;             //MSTP56 ist Bit6

Dann bekomme ich meine 0x38.

Schaue mir jetzt mal an was der Compiler aus

   CPG.STBCR5.BIT.MSTP56 =       0;

macht:
  37                            .loc 1 37 0
  38 0004 02E00010              movi20  #-131056,r2  //0xfffe0010
  39 0008 01000400              movi20  #1024,r1     //0x00000400
  40 000c 312C                  add     r2,r1        //r1=STBCR5
  41 000e 6311                  mov.w   @r1,r3       //Inhalt holen
  42 0010 02F0BFFF              movi20  #-16385,r2   //0xbfff ARGH!
  43 0014 2239                  and     r3,r2
  44 0016 2121                  mov.w   r2,@r1

Es sieht also so aus als wenn der Compiler das Register wirklich
an der falschen Stelle im Struct verortet. Oder er macht einen 16Bit 
Zugriff obwohl er nur 8Bit darf. Muss ich noch weiter pruefen.

> Aktuelle Version der KPIT GNU tools im Einsatz?

Aber aber, mein gcc stammt aus eigenem Ansatz:
/home/olaf/sources/SH2A/test1: sh2a-gcc --version
sh2a-gcc (GCC) 4.5.1

> val sollte so im Debugger "watchbar" sein, zumindest sollte ein
> Core-Register den Wert von TESTREG enthalten.

Waer schoen, dafuer muesste ich aber erstmal den gdb-stub vollstaendig 
laufen haben. Soweit bin ich noch nicht.

> ist im mitgelieferten GNU
> Compiler die Funktionalität von -fstrict-volatile-bitfields enthalten
> und per default aktiviert.

Hm..interessant. Werde ich gleich mal testen ob mein original gcc das 
auch kann und ob es das Problem loest.

BTW: Wenn ich mal den Code vergleich den der gcc erzeugt und den der 
Renesas compiler erzeugt dann schneidet gcc aber ziemlich schlecht ab. 
Ich glaub der gcc erzeugt etwa Faktor 2-3 mehr code. Ausserdem 
verschachtelt der Renesas-Compiler Instruktionen von verschiedenen 
C-Befehlen lustig ineinander. Das macht zwar das debuggen etwas nervig, 
aber ich nehme mal an das macht er nicht ohne Grund. Ich vermute er 
sortiert den Code so um damit der Prozessor wirklich zwei Befehle 
gleichzeitig ausfuehren kann.

Olaf

von Olaf (Gast)


Lesenswert?

Hm..interessant...

Ich nutze auch ein RS232 Modul und schalte das so ein:

CPG.STBCR4.BIT.MSTP44 = 0;

  63                            .loc 1 66 0
  64 000c 02E00010              movi20  #-131056,r2
  65 0010 010003FC              movi20  #1020,r1
  66 0014 312C                  add     r2,r1
  67 0016 6311                  mov.w   @r1,r3
  68 0018 02F0EFFF              movi20  #-4097,r2
  69 001c 2239                  and     r3,r2
  70 001e 2121                  mov.w   r2,@r1

Das sieht identisch aus zu obigen Problem, aber es funktioniert!

Ich vermute mal das Problem ist der 16Bit-Zugriff auf das Register. Im 
Datenblatt steht naemlich nur was von 8Bit-Zugriff. Das geht vielleicht 
bei manchen Registern gut und bei manchen nicht.

Allerdings frage ich mich wieso der Compiler auf die Idee kommt 16bit 
weise zuzugreifen. Definiert ist das struct naemlich so:

       union {                                  /* STBCR5       */
             _UBYTE BYTE;                       /*  Byte Access */
             struct {                           /*  Bit Access  */
                    _UBYTE MSTP57:1;            /*   MSTP57     */
                    _UBYTE MSTP56:1;            /*   MSTP56     */
                    _UBYTE MSTP55:1;            /*   MSTP55     */
                    _UBYTE :1;                  /*              */
                    _UBYTE MSTP53:1;            /*   MSTP53     */
                    _UBYTE MSTP52:1;            /*   MSTP52     */
                    _UBYTE MSTP51:1;            /*   MSTP51     */
                    _UBYTE MSTP50:1;            /*   MSTP50     */
                    } BIT;                      /*              */
             } STBCR5;                          /*              */
       _UBYTE wk7[3];                           /*              */

Olaf

von Olaf (Gast)


Lesenswert?

So, das hier funktioniert:

 37:i2c.c         ****   CPG.STBCR5.BYTE &= ~0x40;
  37                            .loc 1 38 0
  38 0004 01E00010              movi20  #-131056,r1
  39 0008 02E00010              movi20  #-131056,r2
  40 000c 32214400              mov.b   @(1024,r2),r2
  41 0010 632C                  extu.b  r2,r3
  42 0012 E2BF                  mov     #-65,r2
  43 0014 2239                  and     r3,r2
  44 0016 622C                  extu.b  r2,r2
  45 0018 31210400              mov.b   r2,@(1024,r1)

Wie man sieht liegt es wohl wirklich am verbotenem wordweisen Zugriff.

Olaf

von Olaf (Gast)


Lesenswert?

> Denn wenn richtig erinnert, ist im mitgelieferten GNU
> Compiler die Funktionalität von -fstrict-volatile-bitfields enthalten
> und per default aktiviert.

djdelorie hat mir gerade dasselbe erzaehlt. Dieser switch ist aber erst 
im neuen 4.6er enthalten. Das hat man davon wenn man einmal einen total 
modernen und voll coolen Controller verwendet. :-)
Da werde ich wohl mal updaten muessen...

Olaf

von Entwickler (Gast)


Lesenswert?

>Das hat man davon wenn man einmal einen total
>modernen und voll coolen Controller verwendet. :-)

... und kein Geld für einen modernen und voll coolen Compiler ausgeben 
möchte. Mit falschem Code läuft da nichts :-)

von Olaf (Gast)


Lesenswert?

> ... und kein Geld für einen modernen und voll coolen Compiler ausgeben
> möchte. Mit falschem Code läuft da nichts :-)

Ich verwende diesen voll coolen Compiler ja auch. Aber leider laeuft der 
nicht unter meinem voll coolen Betriebssystemen und das nervt etwas wenn 
ich jedesmal um was zu testen erstmal ein voll uncooles Windows booten 
muss. .-)

Olaf

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.