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.

MSP430 compiler ignores __even_in_range ?



Hi all,

I'm trying to find why the TI compiler ignores __even_in_range build-in function. I prepared simple example which does not work for me. The version of compiler I use is 4.1.2, I have tested with and without optimization -O3. MCU: MSP430F543A.

#include <msp430.h>
volatile int test = 23;
 int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

return 0;
}
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void)
{
switch(__even_in_range(TA0IV,14))
{
case 0: test = 234; break;
case 2: test = 42; break;
case 4: test = 75; break; // CCR2 not used
case 6: test = 324; break; // Reserved not used
case 8: test = 23; break; // Reserved not used
case 10: test = 64; break; // Reserved not used
case 12: test = 62; break; // Reserved not used
case 14: test = 12; break; // Overflow not used
default: break;
}
}

For switch statement the compiler produces unoptimized code like this:

PUSHM.A #1,R15
MOV.W &Timer0_A5_TA0IV,R15
TST.W R15
JEQ ($C$L7)
DECD.W R15
JEQ ($C$L6)
DECD.W R15
JEQ ($C$L5)
DECD.W R15
JEQ ($C$L4)
DECD.W R15
JEQ ($C$L3)
...

How can I turn on this optimization ? Am I doing something wrong in source code? Does __even_in_range work in non-ISR functions with ordinary variables (other than xxxIV flags) ?

Thanks for help,

Matthew

  • I do not use CCS.

    IAR does compile your code and uses " add.w &switch_var,PC " independent of optimization setting.

  • Hi,

    thank you for answer. From here I know that this is supported in CCS as well. Could someone tell me how can I force such optimization? I have updated the compiler to v4.1.5, still does not work.

    Regards,

    Matthew

  • Matthew Maciag said:
    How can I turn on this optimization ?

    I don't know. If the compiler accfepts the intrinsic without error, it should do the proper code generation.
    It is possible (but doesn't make any sense) that optimization needs to be switched on.

    Matthew Maciag said:
    Am I doing something wrong in source code?

    I don't see any problem. Perhaps ypu should ask in teh compiler forum.

    Matthew Maciag said:
    Does __even_in_range work in non-ISR functions with ordinary variables

    I don't see why not. I'd be surprised if the IV registers were known as a special type of register to the compiler. IMHO it is just a volatile unsigned int to the compiler, like any other 16 bit register or global volatile variable. And there is no reason why it shouldn't work outside an ISR too. If so, this would IMHO be a stupid and superfluous separation.

    Just an idea: the usage of the PUSHM.A#1, R15 instead of a PUSH,R15 seems to indicate that you use large data model. Maybe the __even_in_range has problems with large data model (even though I don't know why).

  • It seems to work with small memory model. Besides I needed to turn on optimization (I have tested -O3) and add _never_executed() intrinsic in the default case.

    005cb6: 5210 036E ADD.W &Timer0_A5_TA0IV,PC
    $C$SW1:
    005cba: 3C23 JMP ($C$L9)
    005cbc: 3C1E JMP ($C$L8)
    005cbe: 3C19 JMP ($C$L7)
    005cc0: 3C14 JMP ($C$L6)
    005cc2: 3C0F JMP ($C$L5)
    005cc4: 3C0A JMP ($C$L4)
    005cc6: 3C05 JMP ($C$L3)
    005cc8: 3C00 JMP ($C$L2)

  • Matthew Maciag said:
    I needed to turn on optimization (I have tested -O3) and add _never_executed() intrinsic in the default case.

    Strange. Neither one should be required. if all possible cases are defined, there is no default case necessary. And if not, all undefined cases go to the default case. Both cases should be no problem for the compiler. And optimization or not shouldn't change anything.

    Matthew Maciag said:
    It seems to work with small memory model.

    In large code model, PC is 20 bit, but TA0IV is 16 bit only. There is no instruction to add a 16 bit memory location to a 20 bit register. Either a 20/32 bit value is added, or the PC would be truncated to 16 bit.

    Now this isn't really a problem if the intrinsic is used inside an ISR, since ISRs need to be in lower 64k anyway, so PC the upper 4 bits of PC are already clear, but probably the compiler manufacturers were unable to detect whether the intrinsic is really used inside an ISR (so the code ends up in lower 64k). Because if not, this will crash.

    The workaround would be loading TA0IV into a register, then adding it to PC using ADDA instruction. But this would clobber a register. Which also should be avoided inside ISRs (all registers must be preserved)

  • "It seems to work with small memory model"

    Does anyone know how to force __even_in_range intrinsic for large code memory model in the TI compiler? I was try to copy *IV register into variable (ui16, ui32 and register ui 16) but as a result I only get non-optimized code (without jump table).

    Best regards,
    Mateusz
  • As I said, there is no instruction to add a 16 bit memory location to a 20 bit register. Therefore even_in_range() will only work in the lower 64k (where the upper 4 bit of PC are zero anyway). Which is okay, since even_in_range was designed to speed-up ISRs in conjunction with the IV registers. And ISRs have to reside in lower 64k, even on projects using large code model.

    If you really need this mechanism to speed-up your main code above 64k, then you can manually simulate this by using inline assembly. With a 32bit variable.
  • In my case it's not working in ISR if I compile project with large code memory model enabled. 

  • Mateusz Gzella said:
    In my case it's not working in ISR if I compile project with large code memory model enabled. 

    Strange. In the ISR itself or in a function called from inside the ISR function? The latter is a normal function for the compiler and can end up anywhere in memory space, so it surely won't work (just like the _.ON_EXIT intrinsics)

    I'm pretty sure it once worked, as I believe I was discussing it some time ago when the large memory model was still quite new (2012 or 2013). But this was some compiler versions ago.

    Does the compiler manual say something about it in the sections about large memory model or the EVEN_IN_RANGE intrinsic?

    Well, if it doesn't work, it doesn't work.

    Something you might try: Generate the switch statement with a case for every even value from 0 to max, then generate a default case and stuff it with the _never_executed(); intrinsic. According to the CCS4.2 compiler manual (the newest I have, as I don't use CCS), this will generate a jumptable like the _even_in_range(). It does not state whether it is working in large memory model or not. But might. In any case, a jumptable is impossible above 64k, so the compiler must be smart enough to know that this specific code willend-up below 64k (which it only can know for ISRs with a proper vector pragma), or it must refuse generating one.

**Attention** This is a public forum