This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Bitfield and struct/ union representation of registers using Code Composer Studio




Hi All,

There have been some previous posts regarding the use of a structure to reference registers. This looks very clean and allows explicit definition of bits within registers and allows bitwise operations without having to do LSR/ LSL operations. I like this approach.

The problem I have is that the code equivalents for the bit wise operations are MUCH larger. Below we have the header file and a section of code that contrast the code generation for the comparable access types.

As other people have suggested that other compilers/ development systems allow this method in various ways. I'm interested in looking at why the code generated is _SO_ different.


This is what I have at the moment. There's initialisation of PORT3 and an access to toggle PORT3.5 using old and new methods. The Code generated is inserted in italics.


I hope the community can help here.

Regards, Kirem


hardware.h file:

union uport

{         

unsigned char BYTE; 

struct

unsigned char _BIT7 :1;

unsigned char _BIT6 :1;

unsigned char _BIT5 :1;

unsigned char _BIT4 :1;

unsigned char _BIT3 :1;

unsigned char _BIT2 :1;

unsigned char _BIT1 :1;

unsigned char _BIT0 :1;

}BIT;              

}; 


#define P3_OUT (*(union uport *) &P3OUT)

#define P3_DIR (*(union uport *) &P3DIR)

 


main.c file


#include "hardware.h"

void main(void)

{

// byte access

// (option 1) byte-wise access method, code is exactly the same.

P3_DIR.BYTE |= (0x01 << 5) | (0x01 << 6);

0x085A4:   1840 D0F2 0060 0224 BISX.B  #0x00060,&Port_3_4_P3DIR


// (option 2) direct memory accress

P3DIR |= (0x01 << 5) | (0x01 << 6);

0x085AC:   1840 D0F2 0060 0224 BISX.B  #0x00060,&Port_3_4_P3DIR


// toggling bit 5 in P3OUT

// (option 1) BIT wise access method using the union

P3_OUT.BIT._BIT5 ^= (0x1<<5);

0x0764E:   008D 0222           MOVA    #0x00222,R13

0x07652:   4D6F                MOV.B   @R13,R15

0x07654:   0FCE                MOVA    R15,R14

0x07656:   C26E                BIC.B   #4,R14

0x07658:   075F                RRUM.W  #2,R15

0x0765A:   F35F                AND.B   #1,R15

0x0765C:   E07F 0020           XOR.B   #0x0020,R15

0x07660:   F35F                AND.B   #1,R15

0x07662:   1841 5F4F           RPT #2   RLAX.B  R15

0x07666:   DE4F                BIS.B   R14,R15

0x07668:   4FCD 0000           MOV.B   R15,0x0000(R13)


// (option 2) BITwise access method using the old method

P3OUT ^= (0x1<<5);

0x0766C:   1840 E0F2 0020 0222 XORX.B  #0x00020,&Port_3_4_P3OUT


 

 


 

}



 

  • It is actually quite common (possibly even "normal") that 'C' bitfields provide no  benefit in the generated code - and may even be worse than just using the "normal" bitwise operators.

    There are also very many issues with 'C' bitfields in general;  particularly portability - or, rather, the almost total lack thereof. So, though they may seem attractive at first glance, they often turn out not to be worth it.

    :-(

  • It is an endless discussion if the usage of bitfields does provide a benefit or not. If you prefer bitfields because (in your opinion) the code is better to read then do it. And what does the compiler? Nobody knows at first. Just after checking the disassembly. And the assembly code depends on the compiler settings (optimizations off? min? max?). And in most cases, if the compiler optimizations are done well, it does not matter (e.g. We use the IAR-MSP430 compiler. The compiler result is the same. Most times :-) ).

    Regards,
    Edwin krasser

  • Bitfields per se are a nice thing and make code more readable. However, in this specific case, the bitfields are volatile (since they are put over a hardware register).

    This means that the compiler is very, very limited with its optimization capabilities. It MUST do as many accesses to the register as the source code contains and MUST them do in the proper order.
    The problem is: x.y=1 is a write access. But writing a '1' bit to a bit of a volatile register requires to read it first. What shall the compiler do? In theory, it must nut read the register (as thsi would be an access that is not in the source code and can have hazardous effects), but it is necessary to do the bit write.
    It is assumed that the programmer knows that a write to a bit in a bitfield requires a read of the register (but there will definitely be people who will be surprised), so it is done. But the compiler needs to be very cautious about how it does the access, and optimization must be disabled for the whole code block that results in this action. Leading to rather inefficient code

    Sure, for a skilled coder who analyzes the app and knows about the hardware, it wouldn't be a problem to hand-optimize the code without negative effects. But it is next to impossible to write a generic optimization code that does it and still ensures that it won't break with the next MSP variant or under certain other conditions.

    So bitfields are not a good idea and definitely not an efficient way to access hardware registers.
    For own datatypes in normal ram, there should be no difference between direct access or bitfield access with a good optimizing compiler.

**Attention** This is a public forum