Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
59
Добавлен:
14.04.2015
Размер:
1.37 Mб
Скачать

Keil Software — Cx51 Compiler User’s Guide

367

 

 

Appendix C. Writing Optimum Code

This section lists a number of ways you can improve the efficiency (i.e., smaller code and faster execution) of the 8051 code generated by the Cx51 compiler. The following is by no means a complete list of things to try. These suggestions in most cases, however, improve the speed and code size of your program.

Memory Model

The most significant impact on code size and execution speed is memory model.

Compiling in the small model always generates the smallest, fastest code C possible. The SMALL directive instructs the Cx51 compiler to use the small

memory model. In the small model, all variables, unless declared otherwise, reside in the internal memory of the 8051. Memory access to internal data memory is fast (typically performed in 1 or 2 clock cycles), and the generated code is much smaller than that generated with the compact or large models. For example, the following loop:

for (i = 0; i < 100; i++) { do_nothing ();

}

is compiled in both the small and large models to demonstrate the difference in generated code. The following is the small model translation:

stmt level source

1 #pragma small

2

3 void do_nothing (void);

4

5

6void func (void)

7{

81 unsigned char i;

91

101 for (i = 0; i < 100; i++)

11

1

{

12

2

do_nothing ();

13

2

}

14

1

}

; FUNCTION func (BEGIN)

 

 

 

 

; SOURCE LINE # 10

0000

E4

 

CLR

A

0001

F500

R

MOV

i,A

0003

 

 

?C0001:

 

0003

E500

R

MOV

A,i

0005

C3

 

CLR

C

0006

9464

 

SUBB

A,#064H

 

 

368

 

 

 

 

Appendix C. Writing Optimum Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0008

5007

 

JNC

?C0004

 

 

 

 

 

 

 

 

; SOURCE LINE # 12

 

 

 

 

000A

120000

E

LCALL do_nothing

 

 

 

 

 

 

 

 

; SOURCE LINE # 13

 

 

 

 

000D

0500

R

INC

i

 

 

 

 

000F

80F2

 

SJMP

?C0001

 

 

 

 

 

 

 

 

; SOURCE LINE # 14

 

 

 

 

0011

 

?C0004:

 

 

 

 

 

 

0011

22

 

RET

 

 

 

 

 

 

; FUNCTION func (END)

 

 

 

 

 

In the small model, the variable

i is maintained in internal data memory. The

 

 

 

instructions to access i,

MOV A,i and INC i, require only two bytes each of

 

 

 

code space. In addition, each of these instructions executes in only one clock

 

 

 

cycle. The total size for the main function when compiled in small model is 11h

C

 

 

 

or 17 bytes.

 

 

 

 

 

 

The following is the same code compiled using the large model:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

; FUNCTION func (BEGIN)

 

 

 

 

 

 

 

 

; SOURCE LINE # 10

 

 

 

 

0000

E4

 

CLR

A

 

 

 

 

0001

900000

R

MOV

DPTR,#i

 

 

 

 

0004

F0

 

MOVX

@DPTR,A

 

 

 

 

0005

 

?C0001:

 

 

 

 

 

 

0005

900000

R

MOV

DPTR,#i

 

 

 

 

0008

E0

 

MOVX

A,@DPTR

 

 

 

 

0009

C3

 

CLR

C

 

 

 

 

000A

9464

 

SUBB

A,#064H

 

 

 

 

000C

500B

 

JNC

?C0004

 

 

 

 

 

 

 

 

; SOURCE LINE # 12

 

 

 

 

000E

120000

E

LCALL do_nothing

 

 

 

 

 

 

 

 

; SOURCE LINE # 13

 

 

 

 

0011

900000

R

MOV

DPTR,#i

 

 

 

 

0014

E0

 

MOVX

A,@DPTR

 

 

 

 

0015

04

 

INC

A

 

 

 

 

0016

F0

 

MOVX

@DPTR,A

 

 

 

 

0017

80EC

 

SJMP

?C0001

 

 

 

 

 

 

 

 

; SOURCE LINE # 14

 

 

 

 

0019

 

?C0004:

 

 

 

 

 

 

0019

22

 

RET

 

 

 

 

 

 

; FUNCTION func

(END)

 

 

In the large model, the variable i is maintained in external data memory. To access i, the compiler must first load the data pointer and then perform an external memory access (see offset 0001h through 0004h in the above listing). These two instructions alone take 4 clock cycles. The code to increment i is found from offset 0011h to offset 0016h. This operation consumes 6 bytes of code space and takes 7 clock cycles to execute. The total size for the main function when compiled in the small model is 19h or 25 bytes.

Keil Software — Cx51 Compiler User’s Guide

369

 

 

Variable Location

Frequently accessed data objects should be located in the internal data memory of the 8051. Accessing the internal data memory is much more efficient than accessing the external data memory. The internal data memory is shared among register banks, the bit data area, the stack, and other user defined variables with the memory type data.

Because of the limited amount of internal data memory (128 to 256 bytes), all your program variables may not fit into this memory area. In this case, you must locate some variables in other memory areas. There are two ways to do this.

One way is to change the memory model and let the compiler do all the work.

C

This is the simplest method, but it is also the most costly in terms of the amount

of generated code and system performance. Refer to “Memory Model” on page

 

367 for more information.

 

Another way to locate variables in other memory areas is to manually select the

 

variables that can be moved into external data memory and declare them using

 

the xdata memory specifier. Usually, string buffers and other large arrays can

 

be declared with the xdata memory type without a significant degradation in

 

performance or increase in code size.

 

Variable Size

 

Members of the 8051 family are all 8-bit CPUs. Operations that use 8-bit types

 

(like char and unsigned char) are much more efficient than operations that use

 

int or long types. For this reason, always use the smallest data type possible.

 

The Cx51 compiler directly supports all byte operations. Byte types are not

 

promoted to integers unless required. See the INTPROMOTE directive for

 

more information.

 

An example can be illustrated by examining a multiplication operation. The

 

multiplication of two char objects is done inline with the 8051 instruction

 

MUL AB. To accomplish the same operation with int or long types would require

 

a call to a compiler library function.

 

370

Appendix C. Writing Optimum Code

 

 

Unsigned Types

The 8051 family of processors does not specifically support operations with signed numbers. The compiler must generate additional code to deal with sign extensions. Far less code is produced if unsigned objects are used wherever possible.

Local Variables

When possible, use local variables for loops and other temporary calculations. C As part of the optimization process, the compiler attempts to maintain local

variables in registers. Register access is the fastest type of memory access. The best effect is normally achieved with unsigned char and unsigned int variable types.

Other Sources

The quality of the compiler-generated code is more often than not directly influenced by the algorithms implemented in the program. Sometimes, you can improve the performance or reduce the code size simply by using a different algorithm. For example, a heap sort algorithm always outperforms a bubble sort algorithm.

For more information on how to write efficient programs, refer to the following books:

The Elements of Programming Style, Second Edition

Kernighan & Plauger

McGraw-Hill

ISBN 0-07-034207-5

Writing Efficient Programs

Jon Louis Bentley

Prentice-Hall Software Series

ISBN 0-13-970244-X

Efficient C

Plum & Brodie

Plum Hall, Inc.

ISBN 0-911537-05-8

Соседние файлы в папке HLP