Use the #asm and #endasm directives to delimit blocks of assembly. An assembly block can be located both inside and outside of functions. One important note about this syntax is that all # directives must be the first non white space characters on a line. Therefore #asm and #endasm directives can't be placed in the middle of statements.
C variables are directly accessible from within the assembly block. The C compiler replaces the name of the variable with its address. Whether the variable address is used as an immediate value, or as a direct or indirect address depends on the assembly instruction.
Figure 6-1. Embedded blocks of assembly asm1.c
char arr[10]; /* declare an array of 10 characters */ void main(void) { int i; i=sizeof(arr); /* assign the size of arr[] to i */ /* while(i--) arr[i]=0; */ #asm LD B,#arr ;load B to point to arr LD X,#i ;load X to point to i clear_arr LD S,#i>>8 ;select i RAM bank LD A,[X] ;load i DECA ;decrement X A,[X] ;store A to i IFEQ A,#0 ;done if i is zero JP done_clear LD S,#arr>>8 ;select arr RAM bank CLRA X A,[B+] ;clear arr[] JP clear_arr ;clear next byte done_clear #endasm }
If you need to return a value from a function written in assembly, you need to follow the same protocol that COP8C code does. If one byte is returned, it is passed though the A register. If two bytes are returned, they are passed using A and X. The most significant byte is placed in X and the least significant byte is placed in A.
Figure 6-2. Setting the function return value from assembly asm1.c
long inc_long(long l) /* increment a long variable */ { /* return(++l); */ #asm LD S,#l>>8 ; load high address of l into S LD B,#l ; load low address of l into B RC ; clear carry LD A,[B] ; load low byte of l ADC A,#1 ; add 1 X A,[B+] ; store result LD A,[B-] ; load high byte of l ADC A,#0 ; add carry to high byte X A,X ; return high byte in X LD A,[B] ; return low byte in A #endasm }
Including assembly into C is convenient when you have some assembly language code you wish to use unchanged.