26 Chapter 2.Microcontroller Architectures Code Comparison The following short but representative code examples show the impressive individual strengths of the different microcontroller architectures. I/O Port Access Comparison Source Code Description if (IO PIN =1){ Increment a value when an I/O pin is set. i++: 8051 devices provide bit-addressable I/O Ports and instructions to access fixed memory locations directly C166,XE166,XC2000 devices provide bit-addressable I/O Ports and instructions to access fixed memory locations directly ARM7 and ARM9 devices provide indirect memory access instructions only.However,there are no bit operations. Cortex-Mx devices provide indirect memory access instructions only,but allow atomic bit operations 8051 C166/XE166 and ARM7 and ARM9 Cortex-Mx Code XC2000 Code Thumb Code Thumb2 Code sfr P0=0x80; sEr POL=0xFY00: Wdefine IOP *(int*)) sbit PO 0=P0*01 sbit PO 0=POL0; unsigned char i unsigned int i: unsigned int it unsigned int it void main(void【 void main (void) void main (void){ void main (void){ if (PO 0) if (PO_0) if (IOP 1)( if (GPIOA->ODR){ ,JwBE00,?C0002 :JwBP00,?c0001 :1DRR0,=0xE0028000 :STR RO,[RI,Oxe] 1DRR0,[R0,#0x0] :LDR R0,IR2,0] ;oWR1,#0x1 CBZ R0,111.2421 :TST RO,RI BEQ L 1 i++订 i++ i++: i++ INC i :SUB i,ONES LDR R0,=ii MOVS RO,2 LDRR1,[R0,0x0]:i ADD RI, 220u,0xe1 :STR STR RI,[RO,0x0]:i RET RET :BX LR BX LR 6 Bytes 10 Bytes 24 Bytes 12 Bytes
26 Chapter 2. Microcontroller Architectures Code Comparison The following short but representative code examples show the impressive individual strengths of the different microcontroller architectures. I/O Port Access Comparison Source Code Description if (IO_PIN == 1) { i++; } Increment a value when an I/O pin is set. 8051 devices provide bit-addressable I/O Ports and instructions to access fixed memory locations directly C166, XE166, XC2000 devices provide bit-addressable I/O Ports and instructions to access fixed memory locations directly ARM7 and ARM9 devices provide indirect memory access instructions only. However, there are no bit operations. Cortex-Mx devices provide indirect memory access instructions only, but allow atomic bit operations 8051 Code C166/XE166 and XC2000 Code ARM7 and ARM9 Thumb Code Cortex-Mx Thumb2 Code sfr P0=0x80; sbit P0_0=P0^0; unsigned char i; void main (void) { if (P0_0) { ; JNB P0_0,?C0002 i++; ; INC i } ; RET } sfr P0L=0xFF00; sbit P0_0=P0L^0; unsigned int i; void main (void) { if (P0_0) { ; JNB P0_0,?C0001 i++; ; SUB i,ONES } ; RET } #define IOP *(int*)) unsigned int i; void main (void) { if (IOP & 1) { ; LDR R0,=0xE0028000 ; LDR R0,[R0,#0x0] ; MOV R1,#0x1 ; TST R0,R1 ; BEQ L_1 i++; ; LDR R0,=i ; i ; LDR R1,[R0,#0x0];i ; ADD R1,#0x1 ; STR R1,[R0,#0x0];i } ; BX LR } unsigned int i; void main (void) { if (GPIOA->ODR) { ; STR R0,[R1,#0xc] ; LDR R0,[R2,#0] ; CBZ R0,|L1.242| i++; ; MOVS R0,#2 ; STR R0,[R1,#0xc] ; |L1.242| } ; BX LR } 6 Bytes 10 Bytes 24 Bytes 12 Bytes
Getting Started:Creating Applications with uVision 27 Pointer Access Comparison Source Code Description typedef struct int x:int arr[10];sx Retumn a value that is part of a struct and int f (sx xdata tsp,int i)( indirectly accessed via pointer. return sp->arr【i]F 8051 devices provide byte arithmetic requiring several microcontroller instructions for address calculation C166,XE166,XC2000 devices provide efficient address arithmetic with direct support of a large 16 MByte address space ARM devices are extremely efficient with regard to pointer addressing and always use the 32-bit addressing mode In Cortex-Mx devices,any register can be used as a pointer to data structures and arrays 8051 C166,XE166, ARM 7 and ARM9 Cortex-Mx Code XC2000 Code Thumb Code Thumb2 Code MOV DPL,R7 MOV R4,R10 LSL R0,R1,#0x2 ADD RO,RO,RI,LSL #2 MOV DP且,R6 SHL R4,001且 ADD R0,R2,R0 LDR RO,[RO,4] MOV A,R5 ADD R4,RB LDR R0,[R0,M0x4] ADD A,ACC EXTS R9,01H MOV R7,A MOV R4,【R4+W2] MOV ARA RLC A MOV R6A INC DPTR INC DPTR MOV A,DPL ADD A,R7 MOV DPL,A MOV A.DPH ADDC A,R6 MOV DPEA MOVX A,DPTR MOV R6,A INC DPTR MOVX A,&DPTR MOV R7,A 25 Bytes 14 Bytes 6 Bytes 6-Bytes
Getting Started: Creating Applications with µVision 27 Pointer Access Comparison Source Code Description typedef struct { int x; int arr[10]; } sx; int f (sx xdata *sp, int i) { return sp->arr[i]; } Return a value that is part of a struct and indirectly accessed via pointer. 8051 devices provide byte arithmetic requiring several microcontroller instructions for address calculation C166, XE166, XC2000 devices provide efficient address arithmetic with direct support of a large 16 MByte address space ARM devices are extremely efficient with regard to pointer addressing and always use the 32-bit addressing mode In Cortex-Mx devices, any register can be used as a pointer to data structures and arrays 8051 Code C166, XE166, XC2000 Code ARM 7 and ARM9 Thumb Code Cortex-Mx Thumb2 Code MOV DPL,R7 MOV DPH,R6 MOV A,R5 ADD A,ACC MOV R7,A MOV A,R4 RLC A MOV R6,A INC DPTR INC DPTR MOV A,DPL ADD A,R7 MOV DPL,A MOV A,DPH ADDC A,R6 MOV DPH,A MOVX A,@DPTR MOV R6,A INC DPTR MOVX A,@DPTR MOV R7,A MOV R4,R10 SHL R4,#01H ADD R4,R8 EXTS R9,#01H MOV R4,[R4+#2] LSL R0,R1,#0x2 ADD R0,R2,R0 LDR R0,[R0,#0x4] ADD R0,R0,R1,LSL #2 LDR R0,[R0,#4] 25 Bytes 14 Bytes 6 Bytes 6-Bytes
28 Chapter 2.Microcontroller Architectures Generating Optimum Code The C/C++compilers provided by Keil are leaders in code generation and produce highly efficient code.However,code generation and translation is influenced by the way the application software is written.The following hints will help you optimize your application performance. Coding Hints for All Architectures Hint Description Keep interrupt functions short. Well-structured interrupt functions only perform data collection and/or time-keeping.Data processing is done in the main function or by RTOS task functions.This reduces overhead involved with context save/restore of interrupt functions. Check the requirement for Atomic code is required for accessing data while using multiple atomic operations. RTOS threads or interrupt routines that access the memory used by the main function.Carefully check the application to determine if atomic operations are needed and verify the generated code.The various architectures have different pitfalls.For example,incrementing a variable on the 8051 and C166/XE166/XC2000 device is a single,atomic instruction, since it cannot be interrupted.whereas multiple instructions are required for an increment on ARM devices.In contrast,the 8051 requires multiple instructions to access the memory of an int variable. Apply the volatile attribute on The volatile attribute prevents the C/C++compiler from variables that are modified by an optimizing variable access.By default,a C/C++Compiler may interrupt,hardware peripherals. assume that a variable value will remain unchanged between or other RTOS tasks. several memory-read operations.This may yield incorrect application behavior in real-time applications. When possible,use automatic As part of the optimization process,the Keil C/C++compiler variables for loops and other attempts to maintain local variables(defined at function level)in temporary calculations. CPU registers.Register access is the fastest type of memory access and requires the least program code
28 Chapter 2. Microcontroller Architectures Generating Optimum Code The C/C++ compilers provided by Keil are leaders in code generation and produce highly efficient code. However, code generation and translation is influenced by the way the application software is written. The following hints will help you optimize your application performance. Coding Hints for All Architectures Hint Description Keep interrupt functions short. Well-structured interrupt functions only perform data collection and/or time-keeping. Data processing is done in the main function or by RTOS task functions. This reduces overhead involved with context save/restore of interrupt functions. Check the requirement for atomic operations. Atomic code is required for accessing data while using multiple RTOS threads or interrupt routines that access the memory used by the main function. Carefully check the application to determine if atomic operations are needed and verify the generated code. The various architectures have different pitfalls. For example, incrementing a variable on the 8051 and C166/XE166/XC2000 device is a single, atomic instruction, since it cannot be interrupted, whereas multiple instructions are required for an increment on ARM devices. In contrast, the 8051 requires multiple instructions to access the memory of an int variable. Apply the volatile attribute on variables that are modified by an interrupt, hardware peripherals, or other RTOS tasks. The volatile attribute prevents the C/C++ compiler from optimizing variable access. By default, a C/C++ Compiler may assume that a variable value will remain unchanged between several memory-read operations. This may yield incorrect application behavior in real-time applications. When possible, use automatic variables for loops and other temporary calculations. As part of the optimization process, the Keil C/C++ compiler attempts to maintain local variables (defined at function level) in CPU registers. Register access is the fastest type of memory access and requires the least program code
Getting Started:Creating Applications with uVision 29 Coding Hints for the 8051 Architecture Hint Description Use the smallest possible data The 8051 uses an 8-bit CPU with extensive bit support.Most type for variables.Favor instructions operate on 8-bit values or bits.Consequently,small unsigned char and bit. data types generate code that is more efficient. Use unsigned data types The 8051 has no direct support for signed data types.Signed whenever possible. operations require additional instructions whereas unsigned data types are directly supported by the architecture. Favor the SMALL memory Most applications may be written using the SMALL memory model. model.You can locate large objects,as arrays or structures, into xdata or pdata memory using explicit memory types.Note, the Keil C51 run-time library uses generic pointers and can work with any memory type. When using other memory Variables in the data address space are directly accessed by an models,apply the memory type 8-bit address that is encoded into the 8051 instruction set.This data to frequently used memory type generates the most efficient code. variables. Learn how to use pdata memory The pdata memory provides efficient access to 256 bytes using type on your device. MOVX @Ri instructions with 8-bit addressing.However,pdata behaves differently on the various 8051 devices,since it may require setting up a paging register.The xdata memory type is generic and accesses large memory spaces(up to 64KB). Use memory-typed pointers By default,the Keil C51 Compiler uses generic pointers that when possible. may access any memory type.Memory-typed pointers can access only a fixed memory space,but generate faster and smaller code. Reduce the usage of Reentrant The 8051 lacks support for stack variables.Reentrant functions Functions. are implemented by the Keil C51 Compiler using a compile-time stack with data overlaying for maximum memory utilization. Reentrant functions on the 8051 require simulation of the stack architecture.Since reentrant code is rarely needed in embedded applications,you should minimize the usage of the reentrant attributes. Use the LX51 Linker/Locater The extended LX51 Linker/Locator(available only in the PK51 and Linker Code Packing to Professional Developer's Kit)analyzes and optimizes your reduce program size. entire program.Code is reordered in memory to maximize 2- byte AJMP and ACALL instructions (instead of 3-byte LJMP and LCALL).Linker Code Packing(enabled in C51 OPTIMIZE level 8 and above)generates subroutines for common code blocks
Getting Started: Creating Applications with µVision 29 Coding Hints for the 8051 Architecture Hint Description Use the smallest possible data type for variables. Favor unsigned char and bit. The 8051 uses an 8-bit CPU with extensive bit support. Most instructions operate on 8-bit values or bits. Consequently, small data types generate code that is more efficient. Use unsigned data types whenever possible. The 8051 has no direct support for signed data types. Signed operations require additional instructions whereas unsigned data types are directly supported by the architecture. Favor the SMALL memory model. Most applications may be written using the SMALL memory model. You can locate large objects, as arrays or structures, into xdata or pdata memory using explicit memory types. Note, the Keil C51 run-time library uses generic pointers and can work with any memory type. When using other memory models, apply the memory type data to frequently used variables. Variables in the data address space are directly accessed by an 8-bit address that is encoded into the 8051 instruction set. This memory type generates the most efficient code. Learn how to use pdata memory type on your device. The pdata memory provides efficient access to 256 bytes using MOVX @Ri instructions with 8-bit addressing. However, pdata behaves differently on the various 8051 devices, since it may require setting up a paging register. The xdata memory type is generic and accesses large memory spaces (up to 64KB). Use memory-typed pointers when possible. By default, the Keil C51 Compiler uses generic pointers that may access any memory type. Memory-typed pointers can access only a fixed memory space, but generate faster and smaller code. Reduce the usage of Reentrant Functions. The 8051 lacks support for stack variables. Reentrant functions are implemented by the Keil C51 Compiler using a compile-time stack with data overlaying for maximum memory utilization. Reentrant functions on the 8051 require simulation of the stack architecture. Since reentrant code is rarely needed in embedded applications, you should minimize the usage of the reentrant attributes. Use the LX51 Linker/Locater and Linker Code Packing to reduce program size. The extended LX51 Linker/Locator (available only in the PK51 Professional Developer’s Kit) analyzes and optimizes your entire program. Code is reordered in memory to maximize 2- byte AJMP and ACALL instructions (instead of 3-byte LJMP and LCALL). Linker Code Packing (enabled in C51 OPTIMIZE level 8 and above) generates subroutines for common code blocks
30 Chapter 2.Microcontroller Architectures Coding Hints for C166,XE166,XC2000 Architectures Hint Description When possible,use 16-bit data Parameter passing is performed in 16-bit CPU registers(many types for automatic and 16-bit registers are available for automatic variables).More 16- parameter variables. bit variables(signed/unsigned int/short)can be assigned to CPU registers.This generates code that is more efficient. Replace long with int data types Operations that use 16-bit types(like int and unsigned int)are when possible. much more efficient than operations using long types. Use the bit data type for boolean These CPUs have efficient bit instructions that are fully variables. supported by the Keil C166 Compiler with the bit data type. Use the SMALL or MEDIUM In these memory models,the default location of a variable is in memory model when possible. near memory,accessible through16-bit direct addresses encoded in the CPU instructions.You can locate large objects (array or struct)into huge or xhuge using explicit memory types. When using other memory Variables in the near,idata,or sdata address space are models,apply the near,idata,or accessed through a 16-bit address that is encoded directly into sdata memory type to frequently a single C166/XE166/XC2000 instruction.These memory types used variables. generate the most efficient code. Use the memory model The memory models COMPACT and LARGE use the obsolete HCOMPACT/HLARGE instead far memory type and have an object size limit of 16KB.The of COMPACT/LARGE. memory models HCOMACT and HLARGE use the huge memory type that feature a 64KB object size limit.Even cast operations from near to huge pointers are more optimal. Use near pointers when Check if a near pointer is sufficient for accessing the memory, possible. since near pointers can access variables in the near,idata,or sdata address space.Near pointers generate faster and smaller code
30 Chapter 2. Microcontroller Architectures Coding Hints for C166, XE166, XC2000 Architectures Hint Description When possible, use 16-bit data types for automatic and parameter variables. Parameter passing is performed in 16-bit CPU registers (many 16-bit registers are available for automatic variables). More 16- bit variables (signed/unsigned int/short) can be assigned to CPU registers. This generates code that is more efficient. Replace long with int data types when possible. Operations that use 16-bit types (like int and unsigned int) are much more efficient than operations using long types. Use the bit data type for boolean variables. These CPUs have efficient bit instructions that are fully supported by the Keil C166 Compiler with the bit data type. Use the SMALL or MEDIUM memory model when possible. In these memory models, the default location of a variable is in near memory, accessible through16-bit direct addresses encoded in the CPU instructions. You can locate large objects (array or struct) into huge or xhuge using explicit memory types. When using other memory models, apply the near, idata, or sdata memory type to frequently used variables. Variables in the near, idata, or sdata address space are accessed through a 16-bit address that is encoded directly into a single C166/XE166/XC2000 instruction. These memory types generate the most efficient code. Use the memory model HCOMPACT/HLARGE instead of COMPACT/LARGE. The memory models COMPACT and LARGE use the obsolete far memory type and have an object size limit of 16KB. The memory models HCOMACT and HLARGE use the huge memory type that feature a 64KB object size limit. Even cast operations from near to huge pointers are more optimal. Use near pointers when possible. Check if a near pointer is sufficient for accessing the memory, since near pointers can access variables in the near, idata, or sdata address space. Near pointers generate faster and smaller code