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.

Comparison of division and right-shifting

I would like to know the differences generated by the MSP430 compiler when doing division vs. right-shifting.

For instance, with a signed 16-bit number containing a 12-bit left-adjusted value, is it useful to perform the division by 16 and what are the results vs. shifting right by 4 bits? I'd like to know the comparison of clock cycles, and resource requirements for both, how the compiler generates the resulting ASM, etc. Does the MSP430 have a native right shift opcode? I didn't see one in the instruction set.

Is there a way for me to execute a comparison in the code with both and calculate empirically the clock cycles? I've never had to do this before.

  • I have use right and left shifts without a problem. I don't have any experience as far as speed but, assuming you are only planning on dividing with 2^x I think it would be faster.

  • One warning.  If you just do this:

       result = var / 16;

    then the compiler may generate right-shift code.  But you could do this:

       volatile int divisor = 16;
       result = var / divisor;

    to force the compiler to use the math-library division code.  The code is long and laborious (think of long division from elementary school) when the MCU doesn't have native integer division.

    To see the difference in execution time of the different approaches, set an output bit before the operation and clear it afterwards.  Then watch the output on a scope.  You will see a huge difference between long division code from the math library and the shift code.  Yes, the MSP430 has a native shift-right operation.  It is RRA (for the most-significant word) and RRC (for the other words).

    Jeff

  • Scott Wohler said:
    ...  the differences generated by the MSP430 compiler ...

    I don't know if there is a the MSP430 compiler. It depends on which compiler, which version, and what level of optimization. It could conclude that your c-statement is useless and ignore what you put in your source code. It could do your division or shift at compile-time and not at run-time. It will do what it will do, you are wasting your time trying to find it out.

    --OCY

  • Scott Wohler said:
    Does the MSP430 have a native right shift opcode? I didn't see one in the instruction set.

    The original instruction set doesn't. It uses an RRC instruction (rotate 1 bit right through carry) and requires the carry to be cleared first.
    However, the extended instruction set (5x family and up and parts of 2x family) have a right shift operation for up to 4 bits (RRUM or RRUX). Same for left shifts. However, the RLA instruction can be used for single left shifts, as it doesn't require clearing the carry (the arithmetic right shift RRA would do sign expansion)

    Scott Wohler said:
    Is there a way for me to execute a comparison in the code with both and calculate empirically the clock cycles? I've never had to do this before.

    You can set up a timer with MCLK speed, Start it before doing the math, stop it after and look at the count. Of course you'll have to subtract the overhead for starting and stopping.

  • Jens-Michael Gross said:
    Does the MSP430 have a native right shift opcode? I didn't see one in the instruction set.

    The original instruction set doesn't.[/quote]

    JMG, remember that Scott is talking about signed integers.  RRA works for the most-significant word (or only word) of a signed integer.

    Your description of using CLRC then RRC works only for the most-significant word of an unsigned integer. 

    For other words of both signed and unsigned multi-word integers, RRC helps the shift span multiple words (without any use of CLRC or SETC).

    Jeff

  • Jeff Tenney said:
    JMG, remember that Scott is talking about signed integers. 

    You're right, I forgot the 'signed'.

    Indeed, for arithmetic shift, the RRA instruction does it fine. (Shifting right into the carry, while keeping the MSP and therefore keeping the sign). For 32 bit shifts, first the MSW is shifted with RRA, then RRC for the LSW.

    The multi-bit shift in the extended set (RRAM) of course won't work for >16 bit values, since it produces only one carry bit.

    From MSPGCC, I remember the processor generates a chain of shift instructions that has several entry points. It generates a function call to one of these entry points  and this 'function' returns after doing the required number of shifts. Of course for only one or two shifts, it isn't used.
    This can save a lot of code space.

  • Thank you for the informed response. I'll be testing this later today, though it may not be necessary, I was curious.

    For reference, here are the two assignments:

    77: xTest = xInt / 16;
    78: xInt = xInt >> 4;

    And here is the resulting ASM for both:

    .dwpsn file "../main.c",line 77,column 5,is_stmt
    MOV.W 0(SP),r12 ; [] |77|
    MOV.W #16,r13 ; [] |77|
    $C$DW$70 .dwtag DW_TAG_TI_branch
    .dwattr $C$DW$70, DW_AT_low_pc(0x00)
    .dwattr $C$DW$70, DW_AT_name("__divi")
    .dwattr $C$DW$70, DW_AT_TI_call
    CALL #__divi ; [] |77|
    ; [] |77|
    MOV.W r12,6(SP) ; [] |77|
    .dwpsn file "../main.c",line 78,column 5,is_stmt
    MOV.W 0(SP),r12 ; [] |78|
    $C$DW$71 .dwtag DW_TAG_TI_branch
    .dwattr $C$DW$71, DW_AT_low_pc(0x00)
    .dwattr $C$DW$71, DW_AT_name("I_ASR_4")
    .dwattr $C$DW$71, DW_AT_TI_call
    CALL #I_ASR_4 ; [] |78|
    ; [] |78|
    MOV.W r12,0(SP) ; [] |78|

    I can't determine where I_ASR_4 is located or what it does, but I assume it's a shift function. So they do produce different results.

  • The experiment you did shows that the compiler you used is not very efficient. Try a different compiler, or a different revision, or a different optimization level, etc.

**Attention** This is a public forum