Jump to content

gcc asm output for rrc absolute mode

Recommended Posts

I'm puzzled as to why gcc is producing code for rrc as follows:


    f97e: 1f 42 02 02 mov &0x0202,r15
    f982: 12 c3       clrc
    f984: 0f 10       rrc r15
    f986: 82 4f 02 02 mov r15, &0x0202
whereas bit set is:
    f96c: b2 d0 80 00 bis #128, &0x0164 ;#0x0080
    f970: 64 01 
slau144 seems to indicate that rrc supports absolute mode; am I missing something here (besides possible lost clock cycles). Why the extra mov instructions?
(note: for the variable at 0x202, I have tried with and without the volatile keyword and get the same result)
Link to post
Share on other sites

Here are the CFLAGS I used


CFLAGS   = -mmcu=$(MCU) -std=c99 -g -Os -Wall -Wunused -mnoint-hwmul -DF_CPU=16000000


I also tried adding -O2 -O1 with no effect. -O0 produces horrendous code.


My gcc version:

gcc version 4.6.3 20120301 (mspgcc LTS 20120406 unpatched) (Gentoo 4.6.3_p20120406 p1.0)

Link to post
Share on other sites
static uint16_t tx_char;


static void Test2(void){
    TA0CCR1 += rx_ticks_per_bit;       // setup next time to send a bit, OUT will be set then
    TA0CCTL1 |= OUTMOD2;            // reset OUT (set to 0) OUTMOD2|OUTMOD0 (0b101)
    if ( tx_char & 0x01 ) {      // look at LSB if 1 then set OUT high
       TA0CCTL1 &= ~OUTMOD2;        // set OUT (set to 1) OUTMOD0 (0b001)
/* The bit shift is producing extra movs? */
    if (!(tx_char >>= 1)) {      // All bits transmitted ?
        TA0CCTL1 &= ~CCIE;          // disable interrupt, indicates we are done

It's adapted from the TimerSerial code from Energia (which I think was yours actually).

Context (you can skip if you want): Didn't like TA0CCTL1 being written twice; was looking to optimize and noticed the bit shift....

Link to post
Share on other sites

What I've noticed is that if you use global variables in ISR routines, you often end up with it using a register as a temporary.


The best way to get it to do exactly what you want in 4.6.3 is to use inline asm.


FWIW, the new msp430-elf-gcc seems to do a good job with using memory to memory move instructions. However, you have to replace the startup routine if you want to make it work on the smaller g series chips.

Link to post
Share on other sites

Dunno why it'd do that. Same behavior in my internal 4.7.2 version. I no longer maintain mspgcc unless contracted to do so, and am transitioning to msp430-elf for my own work.


msp430-elf-gcc (4.9.0-based and TI msp430-130423-371) generates a call to a rotate subroutine.


Somebody should probably document the msp430-elf issue and submit it to RH/TI to be fixed; I don't expect to be doing anything with msp430 in the next month or two or I'd do it myself.


[FWIW, with mspgcc the fact a function is an ISR should have no impact on code generation except in the function prolog and epilog.]

Edited by pabigot
Link to post
Share on other sites

OK parting thought:


1) The movs cost 3 cycles each. The register RRC costs 1.

2) RRC costs 4 cycles. (edit: with an absolute destination)


For 3 bit shifts, method 1 costs 9 cycles while method 2 costs 12. So gcc is doing the correct thing for shifts >= 3 bits.

For 2 bit shifts, it is break even at 8 cycles.

It is 1 bit shifts that are getting shafted (unfortunately I tend to use 1 bit shifts precisely because shifts are expensive...)

Link to post
Share on other sites

__attribute__ ((interrupt(TIMER0_A0_VECTOR)))

void putch_bit_isr(void)


#if 0

TA0CCR0 += TICKS_PER_BIT; /* setup next time to send next bit, OUT is set then */


TA0CCTL0 |= OUTMOD2; /* reset OUT (set to 0) OUTMOD2|OUTMOD0 (0b101) */

if (TX_BUF & 0x01) { /* look at LSB, if 1 */

TA0CCTL0 &= ~OUTMOD2; /* then set OUT (set to 1) OUTMOD0 (0b001) */



if (!(TX_BUF >>= 1)) { /* if all bits transmitted ? */

TA0CCTL0 &= ~CCIE; /* then disable interrupt, send no more bits */

/* NOTE: this indicates byte transmit complete */



__asm__ (

" add %[TICKS],%[ccr0]\n"

" bis %2,%[cctl0]\n"

" bit #1, %[tx_buf]\n"

" jz 1f\n"

" and %5,%[cctl0]\n"


" clrc\n"

" rrc %[tx_buf], %[tx_buf]\n"

" jnz 2f\n"

" and %6,%[cctl0]\n"




[TICKS] "i" (TICKS_PER_BIT), /* 0 */

[ccr0] "m" (TA0CCR0), /* 1 */

[mod2] "i" (OUTMOD2), /* 2 */

[cctl0] "m" (TA0CCTL0), /* 3 */

[tx_buf] "m" (TX_BUF), /* 4 */

"i" (~OUTMOD2), /* 5 */

"i" (~CCIE) /* 6 */








Edited by Rickta59
add "cc" flag clobber and whitespace fixes
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...