Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

RE: [lpc2000] Re: Example of C and inline ASM in a file?

2006-04-11 by Paul Curtis

Hi Stephen, 

> > Why not do them in assembly rather than inline?  I don't 
> expect either 
> > of us to change the others mind but I am curious as to the 
> reasoning.
> 
> Here's my standard response to this question. Just to confuse 
> you, the example is not in C, and it's not for an ARM, but 
> the principles apply. The example is for a very simple UART 
> driver with interrupts enabled on receive.
> 
> : key0		\ -- char
> \ *G Wait for character from USART0 and return it.
>   begin
>     di  rx0-avail c@ 0=
>    while
>     [asm  bis # _cpuoff _gie + sr  asm]	\ cpu to sleep, GIE set
>   repeat
>   rx0-char c@  0 rx0-avail c!
>   ei
> ;
> 
> The compiler 'knows' about DI and EI to disable/enable 
> interrupts. The ways to the put an MSP430 to sleep are myriad. 
> The objective is to minimise the time for which interrupts 
> are disabled. Putting in a single assembler instruction 
> achieves that objective and documents everything the user 
> needs to know.
> 
> Doing it this way gives faster code, better interrupt 
> latency, shorter source, and keeps everything together. Yes, 
> I could have tweaked the compiler to do this, but I prefer to 
> do that only when the required functionality is itself 
> portable across CPUs. 

In C, if I remember Forth control words well enough:

#include <inmsp.h>
#include <msp430x14x.h>

unsigned char rx0_avail;
unsigned char rx0_char;

unsigned key0(void)
{
  unsigned char ch;
  for (;;)
    {
      __disable_interrupts();
      if (rx0_avail)
        {
          ch = rx0_char;
          rx0_avail = 0;
          __enable_interrupts();
          return ch;
        }
      __bis_SR_register(CPUOFF + GIE);
    }
}

Generates:

       __disable_interrupt();

1100  32c2                      DINT

        if (rx0_avail)

1102  c2930102                  CMP.B   #0, &_rx0_avail
1106  0624                      JZ      0x1114

            ch = rx0_char;

1108  5f420002                  MOV.B   &_rx0_char, R15

            rx0_avail = 0;

110c  c2430102                  MOV.B   #0, &_rx0_avail

            __enable_interrupt();

1110  32d2                      EINT

            return ch;

1112  3041                      RET

        __bis_SR_register(CPUOFF + GIE);

1114  32d01800                  BIS.W   #0x18, SR
1118  f33f                      JMP     0x1100


I believe this is pretty good code from our CrossWorks MSP430 compiler.
:-)  No assembly inserts in sight.

Ok, this is an MSP430 example, but for each architectural feature of the
MSP430 I believe I have provided an intrinsic which means that inline
assembly code is not required.  It's done in such a way that it is also
compatible with the IAR MSP430 compiler, which means you can take code
written for ours and recompile on a competing compiler without resorting
the recoding any assembly language items.  Of course, we find the tide
is in the opposite direction... ;-)

--
Paul Curtis, Rowley Associates Ltd   http://www.rowley.co.uk 
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.