1. Trang chủ
  2. » Kỹ Thuật - Công Nghệ

Writing optimized c code for microcontroller applications

21 443 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 21
Dung lượng 47,17 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Generally, whenprograms are written in C and compiled by a C compiler, the code efficiency decreasescompared to an Assembly language program.. If the microcontroller has dedicated addres

Trang 1

WRITING OPTIMIZED C CODE FOR MICROCONTROLLER APPLICATIONS

By Wilson ChanToshiba America Electronics Components, Inc

Email: wilson.chan@taec.toshiba.com

Trang 2

If you have a microcontroller project that requires a small program, or the

application has very limited memory resource, you may prefer to use Assembly languagefor programming Nowadays, as the performance of microcontrollers has been

improving, application systems have become larger and more complicated As a result,programs can no longer be coded in Assembly language easily To improve developmentefficiency, many microcontroller based products are programmed in C Generally, whenprograms are written in C and compiled by a C compiler, the code efficiency decreasescompared to an Assembly language program In order to improve code efficiency, most

C compilers make use of optimization techniques Often, the output code is optimizedfor size, or execution speed, or both Besides relying on the C compiler to generateefficient code, the programmer can lend a helping hand to the C compiler by adoptingcertain programming styles This paper provides an overview of common optimizingtechniques used by C compilers and recommend C programming guidelines that willresult in optimized code for microcontroller applications

PROGRAMMING MODEL

Some microcontrollers do not have hardware support for a C stack If you plan todevelop your embedded applications in C, you should select a microcontroller with astack-based architecture If the microcontroller has dedicated address-specifying/indexregisters, they will also help the C compiler to generate more efficient code

In this paper, we’ll use a C compiler for a microcontroller which has a

programming model as shown in Figure 1 to illustrate the effect of various optimizationmethods on the quality of the generated machine code The W, A, B, C, D, E, H, Lregisters are 8-bit general purpose registers They can be used in pairs as four 16-bitgeneral purpose registers: WA, BC, DE and HL The IX and IY registers are special-purpose 16-bit registers used as address-specifying registers under register indirect

addressing mode and as index registers under index addressing mode The SP register is

a 16-bit stack pointer The PC register is a 16-bit program counter The PSW is a 16-bitprogram status word register JF is the jump status flag, ZF is the zero flag, CF is thecarry flag, HF is the half carry flag, SF is the sign flag, and VF is the overflow flag

General-Purpose :

8bit X 8

Special-Purpose : 16bit (IX, IY, SP, PC) PSW = JF, ZF, CF,

HF, SF, VF

Figure 1 Programming Model

Trang 3

COMMON OPTIMIZATIONS IN C COMPILERS

This section describes common optimization techniques often found in optimizing

C compilers

Convolution and Propagation of Constants

This optimization method propagates constants in place of variables wheneverpossible and computes any constant expression at compile time rather than at run time.Consider the C program example in Figure 2 For the C statement in line 3, the C

compiler computes the addition of two constants at compile time rather than at executiontime Similarly, for C statements from lines 4 to 6, the constant in line 4 is propagated tolines 5 and 6 This optimization technique reduces program size and increases executionspeed

Without Optimization With Optimization

Figure 2 Convolution and Propagation of Constants

Trang 4

Dead-Code Elimination

This optimization method deletes unused variables at compile time Consider the

C program example in Figure 3 With dead-code elimination optimization, the C

compiler eliminates the C statement in line 3

Without Optimization With Optimization

Figure 3 Dead-Code Elimination

Trang 5

Strength Reduction

This optimization method replaces expensive operations with less expensive ones.Consider the C program example in Figure 4 The most efficient code is a left-shiftinstead of an integer multiplication Without optimization, the generated code makes acall to a multiplication function supplied by the C run-time library to compute the

multiplication which takes much longer than a left-shift operation

Without Optimization With Optimization

Figure 4 Strength Reduction

Trang 6

Common Sub-Expression Elimination

This optimization method reduces the number of operations by using the firstoperation result in subsequent statements that contain the same operation Consider the Cprogram example in Figure 5 The calculation of the sub-expression, i + 1, is reducedfrom two times to once with optimization

Without Optimization With Optimization

Figure 5 Common Sub-Expression Elimination

Trang 7

Code Motion

This optimization method is often used to optimize loops Generally speaking,most of the program execution time is spent in loops Therefore, it is important for Ccompilers to provide optimization for loops Consider the C program example in Figure

6 First, the invariant operation, b + c, is moved outside of the loop Second, arrayaddress calculations that use an induced variable (updated at each iteration) are reduced

to incrementing an accumulator The optimized code will not only be smaller in size (26bytes versus 39 bytes), but will also execute much faster

Without Optimization With Optimization

Figure 6 Code Motion

Trang 8

Caching Of Memory Access

This optimization method reduces the number of memory access, thus speeding

up program execution Consider the C program example in Figure 7 With optimization,the number of memory access is reduced from three to one Also, the resultant codeoccupies less memory (12 bytes versus 20 bytes)

Switch Table Optimization

Switch statements are very common in C programs This optimization calls forthe C compiler to analyze the nature of the case values in the switch statement, thendecide on the optimum way to implement the switch statement Consider the C programexamples in Figure 8 The C compiler implements the switch statement in the C program

1 as a series of compare and branch instructions For the C program 2, the C Compileruses a different coding style to improve code efficiency

Without Optimization With Optimization

Figure 7 Caching of Memory Access

Trang 10

Microcontroller Specific Optimization

Every microcontroller has a specific instruction set The types of instructionsvary according to the particular microcontroller The C compiler can generate moreefficient code by using instructions specific to a microcontroller Consider the C programexample in Figure 9 The C compiler takes advantage of the bit manipulation instructionsprovided by the microcontroller to generate efficient code

Trang 11

PROGRAMMING GUIDELINES FOR EFFICIENT C CODE

It is important to choose a good optimizing C compiler for your microcontrollerproject However, besides relying on the C compiler, you can also lend the C compiler ahelping hand in generating efficient code by observing certain programming guidelines.This section describes these programming guidelines

Use Microcontroller Specific C Language Extensions

In order to facilitate the portability of C programs, a general rule of thumb is touse ANSI C constructs as much as possible, especially function prototyping For casesthat require tighter code, use C compiler’s language extensions – to access hardware,locate variables in memory, specify interrupt service routines, etc The disadvantage isthat using language extensions renders the C program non-portable

/* Function Prototype Examples */

void void_ptr_func(); /* function returning nothing */

char *char_ptr_func(); /* function returning a pointer to char

*/

int ifunc( char B, int *DEW ); /* function returning an int,

1st parameter is a char,

2nd parameter is a pointer to int */

/* Prototype declaration for interrupt processing functions.*/

extern void int5(), inttc1(), intsio2(), int3(),

inttc4(),intsio1(), inttc3(),int2(),

inttbt(), int1(),inttc1(), int0(), intwdt(), intsw(), reset();

/* Definition of vector table */

#pragma section const interrupt near 0xffe0

/* const or code can be used for section type */

void (*intvector[])() = { int5, inttc1, intsio2,int3,

inttc4, intsio1, inttc3, int2,

inttbt, int1, inttc1, int0,

intwdt, intsw, reset };

/* Define pointer variable (or array) in vector table */

/* Initialize to set the function address (function name) */

Figure 10 Function Prototype Examples

Trang 12

Use C Compiler’s Optimization Options

The C compiler may provide multiple levels of optimization For examples,optimization levels 0, 1, 2 and 3 Usually, the higher the level, the more optimizationmethods will be used by the C compiler to generate machine code However, depending

on the coding style, it is possible that the size of generated code of level 3 is larger thanthat of level 0

static void DecSafeTicks(int nSafeTicks) {

DI; /* special function - disable interrupts */

unsigned char port0;

/* An example of I/O variable definition using _io */

unsigned char io(0x00) port0;

Figure 11 C Language Extension Examples

Level Function

0 Minimum optimization (default)

Stack release absorption Branch instruction optimization

Deletion of unnecessary instructions

1 Basic block optimization

Propagation of copying restricted ranges

Gathering of common partial expressions in restricted ranges

2 Optimization of more than basic blocks

Propagation of copying whole functions

Gathering of common partial expressions of whole functions

3 Maximum optimization

Loop optimization and other miscellaneous optimization

Figure 12 C Compiler's Optimization Options Example

Trang 13

The C compiler may have an option that minimizes program size Use it if it is available.

A possible side effect of this option is that in certain situations, the resultant code may besmaller in terms of number of bytes, but it may execute slower than the code generatedwithout specifying the option

Optimize Usage of Memory Spaces

Many microcontrollers have more than one memory space For example, amemory space may be accessible with an 8-bit offset, another memory space requires a16-bit offset, still some memory space requires an address space modifier You candecrease program size by explicitly locating the frequently used variables into the

memory space that requires the minimum number of bytes for addressing

Format

-XSFunction

Specifies the output of minimum object code size

Description

When this option is specified, part of optimization is skipped Thedefault, when this option is not specified, is the output of code with executionspeed priority

Figure 13 C Compiler Code Size Optimization Example

; 8-bit address offsetE00048 R ld WA,(_at0)F00068 R ld (_at1),WA

FA ret

Figure 14 Optimize Usage of Memory Space Example

Trang 14

Use of the const Keyword

Using a constant is more efficient than a const variable in terms of executionspeed and program size The C compiler can easily access a constant with immediateaddressing whereas it needs to use index addressing to access a const variable which isusually placed in ROM However, if a function argument is a pointer to a read-onlystring (a const data object), using the const keyword to declare the pointer argument mayhelp the C compiler, in certain cases, to generate more efficient code

Use Of Auto Variables

For temporary variables, do not declare them as global variables Rather, declarethem as auto variables

When global variables are passed as arguments in a function, use the arguments,not the global variables, in expressions within the function

For global variables that are accessed frequently in a function, make a copy of theglobal variables as auto variables and use the auto variables within the function

Consider the C program examples in Figure 16 The C program 1 produces 30 bytes ofmachine code whereas the C program 2 generates 18 bytes of machine code

A const declaration can only be used for variables defined in const

or code sections, or external variables Variables in const sections

automatically take the const attribute and no const declaration

therefore needs to be coded, if a const declaration is made for

variables in a const section The const declaration also affects

external variables

Figure 15 Use of const Keyword Example

Trang 15

ld (_j),0x0L2:

ld IY,_a

ld DE,(IY)

ld WA,(IY)inc WA

ld (IY),WA

ld (DE),0x0inc (_j)cmp (_j),0x64

j lt,L2ret

1 unsigned char *a, j;

ld DE,BCinc BC

ld (DE),0x0inc A

cmp A,0x64

j lt,L6ret

C Language Program 1

With Optimization With Optimization

1 unsigned char *a, j;

Trang 16

Use Unsigned Data Types

Use unsigned data types with the data size that matches the natural width of themicrocontroller’s registers Also, use the smallest data type that can get the job done Forexample, if you write a C program for an 8-bit microcontroller, use the unsigned chardata type in loop control operations, as subscript of arrays and as bit-field members Ifthe C compiler enforces ANSI C’s integer promotion rule by default, specify an option todisable it Otherwise, this ANSI C’s rule will enlarge the program size

Example:

struct field {unsigned char a:1;

for (i=0; i < 10; i++) { array[i].b = 5;

array[i].c = 7;

}}

Trang 17

Pass Function Arguments with Registers

If the C compiler supports register variables as auto variables and arguments of afunction, use the facility The register variables are placed in microcontroller’s registers,which will result in smaller and faster program

Example:

char a_src[41] = {"Hello"};

char a_des[41];

void testcpy(void) {

register char *p_src = a_src;

register char *p_des = a_des;

Trang 18

Function type adec1 is used to interface with assembly language functions Up

to three arguments are passed via the registers Arguments not passed via the register arepassed via the stack like cdecl type Arguments are sequentially evaluated from theleft unlike cdecl type The merit of using adecl type is that, in many cases, passingarguments via the register simplifies the coding of argument processing in assemblylanguage

Example:

int g1, g2, g3, g4, sum;

int adecl RegParm( int p1,

int p2, int p3, int p4) {

ret

Figure 19 Function Type adecl Example

Trang 19

Avoid Using Signed Variables, Long Types and Floating Points

Expressions involving these data types often result in calls to run-time libraryfunctions in the generated code For the example in Figure 20, the C compiler generates

a function call to _fld_ff in the run-time library to support floating point type

ld (SP+0x4),0x0L2:

ld A,(SP+0x4)

ld W,0x0shlca WAshlca WA

ld BC,_array4

ld HL,WAadd HL,BC

ld BC,_vf

cal _fld_ffinc (SP+0x4)cmp (SP+0x4),0xa

j lt,L2pop HLpop DEret

Figure 20 Support Function in Run-Time Library Example

Trang 20

Avoid Operations Involving Different Data Types

The C compiler follows the ANSI C data type promotion rules to process

expression that involve different data types, resulting in extra object code and executiontime In expressions that contain char and int, char gets promoted to int In expressionsthat contain both signed and unsigned integers, signed integers are promoted to unsignedinteger In expressions that contain floating point types, float gets promoted to double

In expressions that contain only char, if the C compiler enforces ANSI C’s integerpromotion rule by default, specify an option to disable it Otherwise, this ANSI C’s rulewill enlarge the program size

Avoid Operations that Overloads the Stack

Avoid using recursive functions with many arguments and auto variables, andfunctions with variable length argument lists If a structure or an array is used as

argument in a function, pass a pointer to the data instead of passing the data on the stack

Ngày đăng: 08/03/2016, 11:39

TỪ KHÓA LIÊN QUAN