7/23 C Programming in Embedded Systems Computer Science & Engineering Department Arizona State University Tempe, AZ Dr. Yann-Hang Lee (480)
set C Programming in Embedded Systems Assembly language dependent of processor architecture cache control, registers, program status, interrupt High-level language memory model independent of processor architecture (partially true) Advantages and disadvantages performance code size software development and life cycle
set Manage IO Operations Using C Access memory-mapped IO – pointers Example #define REG_READ (a, val) ((val) = *(volatile unsigned char *)(a)) #define REG_WRITE (a, val) (*(volatile unsigned char *)(a) = (val)) #define UART_USR00x4000_0204 #define UART_CR 0x4000_0208 #define UART_RX_EN 1 #define UART_TX_EN (1<<2) char CR_word=0; CR_word |= UART_RX_EN | UART_TX_EN; REG_WRITE (UART_CR, CR_word);
set Platform.h for MXL #ifndef __MCF5213_UART_H__ #define __MCF5213_UART_H__ /* Register read/write macros */ #define MCF_UART0_UMR (*(vuint8 *)(&__IPSBAR[0x000200])) #define MCF_UART0_USR (*(vuint8 *)(&__IPSBAR[0x000204])) #define MCF_UART0_UCSR (*(vuint8 *)(&__IPSBAR[0x000204])) #define MCF_UART0_UCR(*(vuint8 *)(&__IPSBAR[0x000208])) According to Linux C/C++ coding style: “_” Variable not intended to be exposed externally to the user. Internal workings only. Most often used by compiler and library authors. Sometimes used (not preferred) as a suffix to represent a class member variable. “__”Marks an use as extension to ANSI C++. Often not compiler independent. Usually reserved for use by compiler writers.
set Bit Manipulation Boolean operation operate on 1 (true) and 0 (false) (2 || !6 ) && 7 ?? Bitwise operation operate on individual bit positions within the operands (2 | ~6 ) & 7 = (0x0002 OR 0xFFF1) AND 0x0007 if (bits & 0x0040) if (bits & (1 <<6)) bits |= (1 <<7)bits &= ~(1<<7) long integer: bits &= ~(1L << 7) OperationBoolean op.Bitwise op. AND&&& OR||| XORunsupported^ NOT!~
set Interface C and Assembly Language Why combine C and assembly language performance C doesn’t handle most architecture features, such as registers, program status, etc. Develop C and assembly programs and then link them together at source level – in-line assembly code in C program at object level – procedure call mwccmcf mwasmcf mwldmcf
set Calling Convention GCC calling convention arguments passed in registers and in stack registers saved by caller and callee (including frame pointer and returning PC) frame pointer points just below the last argument passed on the stack (the bottom of the frame) stack pointer points to the first word after the frame saved registers (by callee) dynamic area local variables argument x argument y frame pointer stack pointer saved registers (by caller)
set Coldfire Calling Convention Passes all parameters on the stack in reverse order. Push the last argument first Compact — Passes on even sized boundary for parameters smaller than int (2 for short and char). Standard — Like compact, but always padded to 4 bytes. Register — Passes in scratch registers D0 — D2 for integers, A0— A1 for pointers. Returning returns an integer value in register D0. returns a pointer value in register A0. If it returns a value of any other type, the caller reserves temporary storage area for that type in the caller's stack and passes a pointer to that area as the last argument. the called function returns its value in the temporary storage area.
set Register Usage by Coldfire C Compiler Save code pointer (the value of pc) allows the function corresponding to a stack backtrace structure to be located Save frame and stack pointers to locate stack frame Register usage A0-A1, D0-D2 – scratch registers A2 through A5 — for pointers D3 through D7 — for integers and pointers. A6 – frame pointer A7 – stack pointer Caller needs to save D0-D2 and A0-A2 before calling if the values must be preserved Callee needs to save D3-D7 and A3-A5 if they are used in the procedure
set Stack Usage by Coldfire C Compiler Allocation of local variable in stack Save frame and stack pointers to locate stack frame Entry code link a6, #-framesize ; save and set up fp and sp, movem.l….., -(sp); save registers move.l(.., a6), d0; retrieve parameters ; link instruction: SP – 4 → SP; Ay → (SP); ; SP → Ay; SP + dn → SP On function exit move.l …., d0; return value movem.l (sp)+,….; restore registers unlka6; restore sp and fp ; unlk instruction -- Ax → SP; (SP) → Ax; ;SP + 4 → SP rts
set Calling Assembly Routine from C In C program char *srcstr = "First string - source "; char *dststr = "Second string - destination "; strcopy(dststr,srcstr); Assembly routine.global strcopy strcopy:move.l (4,sp), a0; a0 points to destination string. move.l(8,sp), a1; a1 points to source string. next:move.b (a1)+, d0; Load byte and update address. move.b d0, (a0)+ ; Store byte and update address bne.bnext; Check for zero terminator. rts ; Return..end
set Inline Assembly Code in C Program A feature provided by C compiler to specify that a block of code in your file as assembly language use the “asm” keyword. compiler will do the insertion and knows the variables and the registers Example: function level long int b; struct mystruct { long int a; } ; static asm long f(void) // Legal asm qualifier { move.l struct(mystruct.a)(A0),D0 // Accessing a struct. add.l b,D0 // Using a global variable, put // return value in D0. rts // Return from the function: // result = mystruct.a + b }
set Inline Assembly and Access Control Registers Statement level long square(short a) { long result=0; asm { move.w a,d0 // fetch function argument ‘a’ mulu.w d0,d0 // multiply move.l d0,result // store in local ‘result’ variable } return result; } Access local and global variables and inline assembly directives Write to the special purpose registers _mcf5xxx_wr_sr: move.l 4(SP),D0 move.w D0,SR rts _mcf5xxx_wr_vbr: move.l 4(SP),D0.long 0x4e7b0801 /* movec d0,VBR */ nop rts
set Example sumsq int *sum, array[5]; void sumsq (int *sum, int size, int array[]) { int total=0; int i; for ( i = size-1; i < 0; i--) total= total + array[i]^2; *sum=total; } int main() { sumsq(sum, 5, array); while(1);// Idle }
set Example sumsq -- main int *sum, array[5]; ; 19: int main() ; 20: { ; 21: 0x _main: ; main: 0x x4E link a6,#0 0x x4FEFFFF4 lea -12(a7),a7 ; ; 22: sumsq(sum, 5, array); ; 23: ; 0x x41F lea _array,a0 0x E 0x2F move.l a0,8(a7) 0x x7005 moveq #5,d0 0x x2F move.l d0,4(a7) 0x x41F lea _sum,a0 0x E 0x2010 move.l (a0),d0 0x x2E80 move.l d0,(a7) 0x x4EB jsr _sumsq
set Example sumsq -- main ; ; 24: while(1);// Idle ; 25: ; 0x x60FE bra.s *+0 ; 0x x A 0x4E71 nop ; 10: ; 11: void sumsq (int *sum, int size, int array[]) ; 12: { ; 0x _sumsq: ; sumsq: 0x x4E link a6,#0 0x x4FEFFFF4 lea -12(a7),a7 ; 13: int total=0; ; 14: int i; 0x x7000 moveq #0,d0 0x A 0x2D40FFF8 move.l d0,-8(a6)
set Example sumsq ; ; 15: for ( i = size-1; i < 0; i--) ; 0x E 0x202E000C move.l 12(a6),d0 0x x5380 subq.l #1,d0 0x x2D40FFF4 move.l d0,-12(a6) 0x x6030 bra.s *+50 ; 0x a ; ; 16: total= total + array[i]^2; ; 0x A 0x202EFFF4 move.l -12(a6),d0 0x E 0x2D40FFFC move.l d0,-4(a6) 0x x202EFFFC move.l -4(a6),d0 0x x206E0010 movea.l 16(a6),a0 0x A 0x222EFFFC move.l -4(a6),d1 0x E 0x202EFFF8 move.l -8(a6),d0 0x xD0B01C00 add.l (a0,d1.l*4),d0 0x x0A eori.l #0x2,d0 ; '....'
set Example sumsq 0x C 0x2D40FFF8 move.l d0,-8(a6) 0x x202EFFF4 move.l -12(a6),d0 0x x5380 subq.l #1,d0 0x x2D40FFF4 move.l d0,-12(a6) 0x A 0x202EFFF4 move.l -12(a6),d0 0x E 0x4A80 tst.l d0 0x x6DC8 blt.s *-54 ; 0x a ; ; 17: *sum=total; ; 0x x206E0008 movea.l 8(a6),a0 0x x202EFFF8 move.l -8(a6),d0 0x A 0x2080 move.l d0,(a0) ; ; 18: } 0x C 0x4E5E unlk a6 0x E 0x4E75 rts