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.

How to ensure 32-bit access to CAN control and status registers?

Since the CAN control and status registers have to be accessed 32-bit-wise I need to make sure that the compiler generates only 32-bit accesses to the CAN registers.

I know the examples where shadow structures of the CAN registers are used, but unless really necessary, I don't want to rewrite all our existing code using shadow structures.

My old code does stuff like this:

    if (*CANMC & (1L<<11))
      boffcnt = 200;

where CANMC is defined as

#define CANMC                (volatile long *)0x006014

From the above C code the compiler generates

        MOVL      XAR4,#2048
        MOVL      XAR5,#24596
        MOVL      ACC,XAR4
        AND       AL,*+XAR5[0]
        AND       AH,*+XAR5[1]
        TEST      ACC
        MOVB      @_boffcnt,#200,NEQ

where the two AND instructions are 16-bit accesses.

I could achieve what I want using

    if (*CANMC>>11 & 1)
      boffcnt = 200;

which translates to

        MOVL      XAR4,#24596
        SETC      SXM
        MOVL      ACC,*+XAR4[0]
        SFR       ACC,11
        ANDB      AL,#0x01
        MOVB      AH,#0
        TEST      ACC
        MOVB      @_boffcnt,#200,NEQ

Here, the "MOVL ACC,*+XAR4[0]" is a 32-bit access, but I don't want to rely on such things unless someone can point me to the documentation, where it is stated that 32-bit accesses are guaranteed that way.

Therefore, I'd like to know whether there is a way to make sure that certain locations in memory are accessed only 32-bit-wise.

Apparently, this works too:

    unsigned long tmp = *CANMC;
    if (tmp & 1L<<11)
      boffcnt = 200;

which translates to

        MOVL      ACC,*+XAR4[0]
        MOVL      *-SP[26],ACC
        MOVL      XAR4,#2048
        MOVL      ACC,XAR4
        AND       AL,*-SP[26]
        AND       AH,*-SP[25]
        TEST      ACC
        MOVB      @_boffcnt,#200,NEQ

Here, *CANMC is read in one 32-bit read instruction and stored on the stack. Is it guaranteed that this is the case for all versions of the compiler and all combinations of optimization options? (Currently I'm using version 5.2.3 of the code  generation tools.)

Thanks in advance

Johannes

 

  • Johannes,

    what you could do and what should work all the time (beacuse it is standard ANSI - C) is to define a long pointer variable, for example:

    unsigned long * CANMC = (void *) 0x6014;

    *CANMC = 4;

    or :

    if ( *CANMC >> 11 ....) etc.

    All accesses based on such a long pointer should be translated in 32-bit accesses.

    Regards

     

  • Hi Frank,

    thank you for your reply.

    Frank Bormann said:

    what you could do and what should work all the time (beacuse it is standard ANSI - C) is to define a long pointer variable, for example:

    unsigned long * CANMC = (void *) 0x6014;

    *CANMC = 4;

    or :

    if ( *CANMC >> 11 ....) etc.

    All accesses based on such a long pointer should be translated in 32-bit accesses.

    I'm afraid what you write is not true. Just look at what the compiler makes out of

      unsigned long *lptr = (void *) 0x6014;
      if (*lptr >> 11) *lptr &= ~(1L<<16);

    namely:

            MOVL      XAR4,#24596
            MOVL      *-SP[4],XAR4
            MOVL      XAR4,*-SP[4]
            CLRC      SXM
            MOVL      ACC,*+XAR4[0]
            SFR       ACC,11
            BF        $C$L1,EQ
            MOVL      XAR4,*-SP[4]
            AND       *+XAR4[1],#65534

    As you can see, the condition (*lptr >> 11) is fine (one 32-bit read).

    But the last instruction which implements the statement

    *lptr &= ~(1L<<16);

    is a 16-bit read-modify-write instruction on the high word of *lptr.

    I don't believe the C standard requires 32-bit quantities to be read or written in one instruction. Just think of processors that don't have 32-bit read and write instructions...

     

    Regards

    Johannes

     

  • Johannes,

    good point. However, since the 28x is able to perform 32-bit accesses, we should not see these 16 bit accesses here. The problem seems also to be related to the way the compiler translates the AND operation in your example. I made an even simpler test and compared the follwing code (see also attachment)

    unsigned long * CANMD = (void *)0x6014;

    *CANMD = *CANMD & 0x11112222;     // AND is done in two AND operations internally in AL and AH. A 3rd instruction writes ACC to 32-bit memory. OK.

    *CANMD &= 0x11112222;  // AND is done in two sequential 16-bit instructions  directly in memory. Not OK.

    I would think that there should be no difference between the two lines.

    Eventually somebody from TI can help us here.

    Regards

    32bit-access.pdf