Mixing C and Assembly Code with IAR Embedded WorkbenchTM for FPSLICTM Features Introduction * Passing Variables between C and This application note describes how to use C to control the program flow and main program and assembly modules to control time-critical I/O functions. The application note also describes how to set up and use the IAR C-compiler for the FPSLIC controller in projects including both C and assembly code. By mixing C and assembly, designers can c om b i ne th e p o we r fu l C l an g ua g e instructions with the effective hardwarenear assembly code instructions. Assembly Code Functions * Calling Assembly Code Functions from C * Calling C Functions from Assembly Code * Writing Interrupt Functions in Assembly Code * Accessing Global Variables in Assembly Code Mixing C and Assembly Application Note Table 1. The Pluses and Minuses of C and Assembly Assembly C + Full control of resource usage + Compact/fast code in small applications - Inefficient code in larger applications - Cryptic code - Hard to maintain - Non-portable + Efficient code in larger applications + Structured code + Easy to maintain + Portable - Limited control of resource usage - Larger/slower code in small applications Rev. 1976A-11/00 1 Passing Variables between C and Assembly Code Functions Figure 1. Segments in the Register File When the IAR C-compiler is used for the FPSLIC, the register file is segmented as shown in Figure 1. Scratch registers are not preserved across function calls. Local registers are preserved across function calls. The Y register (R28:R29) is used as a data stack pointer to SRAM. The scratch registers are used for passing parameters and return values between functions. When a function is called, the parameters to be passed to the function are placed in the register file (registers R16 - R23). When a function is returning a value, this value is placed in the register file (registers R16 - R19), depending on the size of the parameters and the returned value. Table 2 shows example placement of parameters when calling a function. Scratch Register R0 - R3 Local Register R4 - R15 Scratch Register R16 - R23 Local Register R24 - R27 Data Stack Pointers (Y) R28 - R29 Scratch Register R30 - R31 Table 2. Placement and Parameters of C Functions Function Parameter 1 Registers Parameter 2 Registers func (char, char) R16 R20 func (char, int) R16 R20, R21 func (int, long) R16, R17 R20, R21, R22, R23 func (long, long) R16, R17, R18, R19 R20, R21, R22, R23 For a complete reference of the supported data types and cor responding sizes, see the AVR (R) IAR Compiler Reference Guide from IAR Systems, Data Representation section. Example C function call: int get_port(unsigned char temp, int num) When calling this C function, the 1-byte parameter temp is placed in R16 and the 2-byte parameter num is placed in R20:R21. The function returns a 2-byte value, which is placed in R16:R17 after return from the function. 2 FPSLIC If a function is called with more than two parameters, the first two parameters are passed to the function as shown above. The remaining parameters are passed to the function on the data stack. If a function is called with a struct or union as a parameter, a pointer to the structure is passed on to the function on the data stack. If a function needs to use any local registers, it first pushes the registers on the data stack. Then the return value from the function is placed at addresses R16 - R19, depending on the size of the returned value. FPSLIC Example 1 Calling Assembly Code Functions from a C Program - with No Parameters and No Return Value Example C Code for Calling Assembly Code Function #include "ioat94k.h" extern void get_port(void);/* Function prototype for asm function */ void main(void) { DDRD = 0x00; /* Initialization of the I/O ports */ DDRE = 0xFF; while(1) /* Infinite loop */ { get_port(); /* Call the assembler function */ } } The Called Assembly Code Function NAME get_port #include "ioat94k.h" ; The #include file must be within the module PUBLIC get_port ; Declare symbols to be exported to C function RSEG CODE ; This code is relocatable, RSEG get_port; ; Label, start execution here in R16,PIND ; Read in the pind value swap R16 ; Swap the upper and lower nibble out PORTE,R16 ; Output the data to the port register ret ; Return to the main function END 3 Calling Assembly Code Functions from a C Function - Passing Parameters and Returning Values This example C function is calling an assembler function. The 1-byte mask is passed as a parameter to the assembly function; mask is placed in R16 before the function call. The assembly function is returning a value in R16 to the C variable value. #include "ioat94k.h" char get_port(char mask); /*Function prototype for asm function */ void C_task main(void) { DDRE=0xFF while(1) /* Infinite loop*/ { char value, temp; /* Decalre local variables*/ temp = 0x0F; value = get_port(temp); /* Call the assembler function */ if(value==0x01) { /* Do something if value is 0x01 */ PORTE=~(PORTE); /* Invert value on Port E */ } } } The Called Assembly Code Function NAME get_port #include "ioat94k.h" ; The #include file must be within the module PUBLIC get_port ; Symbols to be exported to C function RSEG CODE ; This code is relocatable, RSEG get_port: ; Label, start execution here in R17,PIND eor R16,R17 ; XOR value with mask(in R16) from main() swap R16 ; Swap the upper and lower nibble rol ; Rotate R16 to the left R16 brcc ret0 ldi r16,0x01 ret ret0: clr ret ; Read in the pind value ; Jump if the carry flag is cleared ; Load 1 into R16, return value ; Return R16 ; Load 0 into R16, return value ; Return END 4 FPSLIC FPSLIC Calling C Functions from Assembly Code Assuming that the assembly function calls the standard C library routine rand() to get a random number to output to the port. The rand() routine returns an integer value (16 bits). This example writes only the lower byte/8 bits to a port. NAME get_port #include "ioat94k.h" ; The #include file must be within the module EXTERN rand, max_val ; External symbols used in the function PUBLIC get_port ; Symbols to be exported to C function RSEG CODE ; This code is relocatable, RSEG get_port: ; Label, start execution here clr R16 sbis PIND,0 ; Clear R16 ; Test if PIND0 is 0 rcall rand ; Call RAND() if PIND0 = 0 out PORTE,R16 ; Output random value to PORTE lds R17,max_val ; Load the global variable max_val cp R17,R16 ; Check if number higher than max_val brlt nostore ; Skip if not sts max_val,R16 ; Store the new number if it is higher nostore: ret ; Return END 5 Writing Interrupt Functions in Assembly Interrupt functions can be written in assembly. Interrupt functions cannot have any parameters or return any value. Because an interrupt can occur anywhere in the program execution, it needs to store all used registers on the stack. Care must be taken to avoid problems with the interrupt functions in C when assembler code is placed at the interrupt vector addresses. Example Code Placed at Interrupt Vector NAME EXT_INT1 #include "ioat94k.h" extern c_int1 COMMON INTVEC(1) ; Code in interrupt vector segment ORG INT1_vect ; Place code at interrupt vector RJMP c_int1 ; Jump to assembler interrupt function ENDMOD ;The interrupt vector code performs a jump to the function c_int1: NAME c_int1 #include "ioat94k.h" PUBLIC c_int1 RSEG CODE ; Symbols to be exported to C function ; This code is relocatable, RSEG c_int1: st -Y,R16 ; Push used registers on stack in R16,SREG ; Read status register st -Y,R16 ; Push Status register in R16,PIND ; Load in value from port D com R16 ; Invert it out PORTE,R16 ; Output inverted value to port E ld R16,Y+ ; Pop status register out SREG,R16 ; Store status register ld R16,Y+ ; Pop Register R16 reti END 6 FPSLIC FPSLIC Accessing Global Variables in Assembly The main program introduces a global variable called max_val. To access this variable in assembly, the variable must be declared as EXTERN max_val. To access the variable, the assembly function uses LDS (Load Direct from SRAM) and STS (STore Direct to SRAM) instructions. #include "ioat94k.h" char max_val; void get_port(void); /* Function prototype for assembler function */ void C_task main(void) { DDRE = 0xFF; /* Set port E as output */ while(1) /* Infinite loop */ { get_port(); /* Call assembly code function */ } } NAME get_port #include "ioat94k.h" ; The #include file must be within the module EXTERN rand, max_val ; External symbols used in the function PUBLIC get_port ; Symbols to be exported to C function RSEG CODE ; This code is relocatable, RSEG get_port: ; Label, start execution here clr R16 ; Clear R16 sbis PIND,0 ; Test if PIND0 is 0 rcall rand ; Call RAND() if PIND0 = 0 out PORTE,R16 ; Output random value to PORTE lds R17,max_val ; Load the global variable max_val cp R17,R16 ; Check if number higher than max_val brlt nostore ; Skip if not sts max_val,R16 ; Store the new number if it is higher nostore: ret ; Return END References AVR(R) IAR Compiler Reference Guide from IAR Systems 7 Atmel Headquarters Atmel Operations Corporate Headquarters Atmel Colorado Springs 2325 Orchard Parkway San Jose, CA 95131 TEL (408) 441-0311 FAX (408) 487-2600 Europe 1150 E. Cheyenne Mtn. Blvd. Colorado Springs, CO 80906 TEL (719) 576-3300 FAX (719) 540-1759 Atmel Rousset Atmel SarL Route des Arsenaux 41 Casa Postale 80 CH-1705 Fribourg Switzerland TEL (41) 26-426-5555 FAX (41) 26-426-5500 Asia Atmel Asia, Ltd. Room 1219 Chinachem Golden Plaza 77 Mody Road Tsimhatsui East Kowloon Hong Kong TEL (852) 2721-9778 FAX (852) 2722-1369 Japan Zone Industrielle 13106 Rousset Cedex France TEL (33) 4-4253-6000 FAX (33) 4-4253-6001 Atmel Smart Card ICs Scottish Enterprise Technology Park East Kilbride, Scotland G75 0QR TEL (44) 1355-803-000 FAX (44) 1355-242-743 Atmel Grenoble Avenue de Rochepleine BP 123 38521 Saint-Egreve Cedex France TEL (33) 4-7658-3000 FAX (33) 4-7658-3480 Atmel Japan K.K. 9F, Tonetsu Shinkawa Bldg. 1-24-8 Shinkawa Chuo-ku, Tokyo 104-0033 Japan TEL (81) 3-3523-3551 FAX (81) 3-3523-7581 Atmel FPSLIC Hotline Fax-on-Demand 1-(408) 436-4119 North America: 1-(800) 292-8635 Atmel FPSLIC e-mail fpslic@atmel.com FAQ Available from Website International: 1-(408) 441-0732 e-mail literature@atmel.com Web Site http://www.atmel.com BBS 1-(408) 436-4309 (c) Atmel Corporation 2000. Atmel Corporation makes no warranty for the use of its products, other than those expressly contained in the Company's standard warranty which is detailed in Atmel's Terms and Conditions located on the Company's web site. The Company assumes no responsibility for any errors which may appear in this document, reserves the right to change devices or specifications detailed herein at any time without notice, and does not make any commitment to update the information contained herein. No licenses to patents or other intellectual property of Atmel are granted by the Company in connection with the sale of Atmel products, expressly or by implication. Atmel's products are not authorized for use as critical components in life suppor t devices or systems. Marks bearing (R) and/or TM are registered trademarks and trademarks of Atmel Corporation. Terms and product names in this document may be trademarks of others. Printed on recycled paper. 1976A-11/00/xM