The calling of assembler routines from C51 is not difficult, provided that you read both this and the user manual.
The example below is taken from a real application where an EEPROM was being written in a page mode. Because of a 30us timeout of this mode, the 25us run time of the C51 code was viewed as being a bit marginal. It was therefore decided to code it in assembler.
If an assembler-coded function is to receive no parameters then an ordinary assembler label at the beginning of the function is simply called like any C function. Note that an extern function prototype must be given after the style of:
C51 File:
extern void asm_func(void).
A51 File:
ASM_FUNC: MOV A,#10 ; 8051 assembler instructions
Should there be parameters to be passed, C51 will place the first few parameters into registers. Exactly how it does this is outlined in section
The complication arises when there are more parameters to be passed than can be fitted into registers.
In this case the user must declare a memory area into which the extra parameters can be placed. Thus the assembler function must have a DATA segment defined that conforms to the naming conventions expected by C51.
In the example below, the segment
?DT?_WRITE_EE_PAGE?WRITE_EE SEGMENT DATA OVERLAYABLE
does just that.
The best advice is to write the C that calls the assembler and then compile with the SRC switch to produce an assemblable equivalent. Then look at what C51 does when it calls your as yet unwritten assembler function. If you stick to the parameter passing segment name generated by C51 you will have no problems.
Example Of Assembler Function With Many Parameters
C Calling Function
Within the C program that calls this function the following lines must be added to the calling module/source file:
/* external reference to assembler routine */ extern unsigned char write_ee_page(char*,unsigned char,unsigned char) ; . dummy() . { unsigned char number, eeprom_page_buffer, ee_page_length ; char * current_ee_page ; . number = write_ee_page (current_ee_page, eeprom_page_buffer, ee_page_length) ; . } /* End dummy */
The assembler routine is:
NAME EEPROM_WRITE ; PUBLIC _WRITE_EE_PAGE ; Essential! PUBLIC ?_WRITE_EE_PAGE?END_ADDRESS ; PUBLIC ?_WRITE_EE_PAGE?END_BUFFER ; ; P6 EQU 0FAH ; Port 6 has watchdog pin ; ;**************************************************************************** ;*<<<<<<<<< Declare CODE And DATA Segments For Assembler Routine >>>>>>>>>>>* ;****************************************************************************; ?PR?_WRITE_EE_PAGE?WRITE_EE SEGMENT CODE ?DT?_WRITE_EE_PAGE?WRITE_EE SEGMENT DATA OVERLAYABLE ; ; ;**************************************************************************** ;*<<<<<< Declare Memory Area In Internal RAM For Local Variables Etc. >>>>>>* ;**************************************************************************** ; RSEG ?DT?_WRITE_EE_PAGE?WRITE; ?_WRITE_EE_PAGE?END_ADDRESS: DS 2 ; ?_WRITE_EE_PAGE?END_BUFFER: DS 1 ; ; ; ;******************************************************************************* ;*<<<<<<<<<<<<<<< EEPROM Page Write Function >>>>>>>>>>>>>>* ;******************************************************************************* ; RSEG ?PR?_WRITE_EE_PAGE?WRITE ; ; _ WRITE_EE_PAGE: CLR EA MOV DPH,R6 ; Address of EEPROM in R7/R6 MOV DPL,R7 ; ; MOV A,R3 ; Length of buffer in R3 DEC A ; ADD A,R7 ; Calculate address of last MOV ?_WRITE_EE_PAGE?END_ADDRESS+01H,A ; byte in page in XDATA. CLR A ; ADDC A,R6 ; MOV ?_WRITE_EE_PAGE?END_ADDRESS,A ; ; MOV A,R5 ; Address of buffer in IDATA in R5 MOV R0,A ; ADD A,R3 ; MOV ?_WRITE_EE_PAGE?END_BUFFER,A ; ; LOOP: MOV A,@R0 ; MOVX @DPTR,A ; INC R0 ; INC DPTR ; MOV A,R0 ; CJNE A,?_WRITE_EE_PAGE?END_BUFFER,LOOP ; ; MOV DPH,?_WRITE_EE_PAGE?END_ADDRESS ; MOV DPL,?_WRITE_EE_PAGE?END_ADDRESS+01H ; DEC R0 ; ; CHECK: XRL P6,#08 ; Refresh watchdog on MAX691 MOVX A,@DPTR ; CLR C ; SUBB A,@R0 ; JNZ CHECK ; ; SETB EA ; RET ; Return to C calling program ; END ;
In the assembler example the parameter current_ee_page was received in R6 and R7. Notice that the high byte is in the lower register, R6. The fact that the 8051 stores high bytes at the low address of any multiple byte object always causes head scratching!
The "_" prefix on the WRITE_EE_PAGE assembler function name is a convention to indicate that registers are used for parameter passing. If you are converting from C51 version <3.00, please bear this in mind.
Note that if you pass more parameters than the registers can cope with, additional space is taken in the default memory space (SMALL-data, COMPACT-pdata, LARGE-xdata).
Parameter passing is now possible via CPU registers (R0-R7). Coupled with register auto/local variables means that function calls can be made very quickly. Up to three parameters may be passed this way although when using long and/or float parameters only two may be passed, due to there being 4 bytes per variable and only 8 registers available! To maintain compatibility with 2.5x the NOREGPARMS #pragma is provided to force fixed memory locations to be used. Those calling assembler coded functions must take note of this.
Parameter Type Char Int+Spaced ptr Long/Float Generic Ptr ___________________________________________________________________________ Parameter R7 R6/R7 R4-R7 R1,R2,R3 Parameter R5 R4/R5 R4-R7 R1,R2,R3 Parameter R3 R2/R3 R1,R2,R3