next up previous contents index
Next: 3.13.2 Naked Functions Up: 3.13 Inline Assembler Code Previous: 3.13 Inline Assembler Code   Contents   Index


3.13.1 A Step by Step Introduction

Starting from a small snippet of c-code this example shows for the MCS51 how to use inline assembly, access variables, a function parameter and an array in xdata memory. The example uses an MCS51 here but is easily adapted for other architectures. This is a buffer routine which should be optimized:

unsigned char __far __at(0x7f00) buf[0x100]; 
unsigned char head, tail;                 /* if interrupts are involved see 
                                             section 3.9.1.1 about volatile */ 
 
void to_buffer( unsigned char c )  
{ 
    if( head != (unsigned char)(tail-1) ) /* cast needed to avoid promotion to integer */ 
        buf[ head++ ] = c;                /* access to a 256 byte aligned array */ 
}

If the code snippet (assume it is saved in buffer.c) is compiled with SDCC then a corresponding buffer.asm file is generated. We define a new function to_buffer_asm() in file buffer.c in which we cut and paste the generated code, removing unwanted comments and some ':'. Then add ''_asm'' and ''_endasm;''3.5 to the beginning and the end of the function body:

/* With a cut and paste from the .asm file, we have something to start with. 
   The function is not yet OK! (registers aren't saved) */  
void to_buffer_asm( unsigned char c )  
{  
    _asm 
    mov  r2,dpl  
;buffer.c if( head != (unsigned char)(tail-1) ) /* cast needed to avoid promotion to integer */ 
    mov  a,_tail  
    dec  a  
    mov  r3,a  
    mov  a,_head  
    cjne a,ar3,00106$  
    ret 
00106$:  
;buffer.c buf[ head++ ] = c; /* access to a 256 byte aligned array */ 
    mov  r3,_head  
    inc  _head  
    mov  dpl,r3  
    mov  dph,#(_buf >> 8)  
    mov  a,r2  
    movx @dptr,a  
00103$:  
    ret 
    _endasm; 
}

The new file buffer.c should compile with only one warning about the unreferenced function argument 'c'. Now we hand-optimize the assembly code and insert an #define USE_ASSEMBLY (1) and finally have:

unsigned char __far __at(0x7f00) buf[0x100]; 
unsigned char head, tail; 
#define USE_ASSEMBLY (1) 
 
#if !USE_ASSEMBLY 
 
void to_buffer( unsigned char c ) 
{ 
    if( head != (unsigned char)(tail-1) ) 
        buf[ head++ ] = c; 
} 
 
#else 
 
void to_buffer( unsigned char c ) 
{ 
    c; // to avoid warning: unreferenced function argument 
    _asm 
        ; save used registers here.  
        ; If we were still using r2,r3 we would have to push them here.  
; if( head != (unsigned char)(tail-1) ) 
        mov  a,_tail 
        dec  a 
        xrl  a,_head 
        ; we could do an ANL a,#0x0f here to use a smaller buffer (see below) 
        jz   t_b_end$ 
        ; 
; buf[ head++ ] = c; 
        mov  a,dpl       ; dpl holds lower byte of function argument 
        mov  dpl,_head   ; buf is 0x100 byte aligned so head can be used directly 
        mov  dph,#(_buf>>8) 
        movx @dptr,a 
        inc _head 
        ; we could do an ANL _head,#0x0f here to use a smaller buffer (see above) 
t_b_end$: 
        ; restore used registers here  
    _endasm; 
} 
#endif

The inline assembler code can contain any valid code understood by the assembler, this includes any assembler directives and comment lines. The assembler does not like some characters like ':' or ''' in comments. You'll find an 100+ pages assembler manual in sdcc/as/doc/asxhtm.html or online at http://sdcc.svn.sourceforge.net/viewvc/*checkout*/sdcc/trunk/sdcc/as/doc/asxhtm.html .

The compiler does not do any validation of the code within the _asm ... _endasm; keyword pair. Specifically it will not know which registers are used and thus register pushing/popping has to be done manually.

It is recommended that each assembly instruction (including labels) be placed in a separate line (as the example shows). When the --peep-asm command line option is used, the inline assembler code will be passed through the peephole optimizer. There are only a few (if any) cases where this option makes sense, it might cause some unexpected changes in the inline assembler code. Please go through the peephole optimizer rules defined in file SDCCpeeph.def before using this option.


next up previous contents index
Next: 3.13.2 Naked Functions Up: 3.13 Inline Assembler Code Previous: 3.13 Inline Assembler Code   Contents   Index
2008-12-05