G MIGRATION FROM KEIL, FRANKLIN OR ARCHIMEDES

This appendix contains the following sections:

Introduction
ANSI-C Extensions
Memory Type Qualifiers
Pointers
Absolute Variable Allocation
SFR Registers
Function Qualifiers
Assembly Interface
Built-in (intrinsic) Functions
Library Routines
Compiler Invocation
Memory Models
Libraries
Controls or Pragmas
Compiler Optimizations

1 Introduction

This appendix explains how you can migrate your C-51 application from the Keil, Franklin or Archimedes C-51 compiler to the TASKING C-51 compiler (cc51).

There are two major areas of differences between the two compilers which are the cause of most of the changes you will have to deal with. First of all the C language extensions present in both compilers to support special 8051 family features. And secondly the compiler output. The Keil compiler produces an object file as output whereas the TASKING compiler generates an assembler file. The Keil compiler uses controls to steer the behavior of the compiler. The TASKING compiler behavior is steered with the more commonly used options, making command lines both shorter and clearer.

2 ANSI-C Extensions

In the TASKING compiler all extra keywords for the 8051 extensions of ANSI-C have an underscore prefix. The most frequently occurring differences in keywords between the Keil compiler and the TASKING compiler can be resolved by using preprocessor definitions. The header file keil.h contains these definitions. This file can be 'included' for all C source files using the command line option "-Hkeil.h".

2.1 Memory Type Qualifiers

Both compilers have the same memory type qualifiers, which are used in the same place in the grammar so a simple preprocessor definition suffices. For this purpose the definitions listed below are included in keil.h.

2.2 Pointers

The TASKING compiler does not support generic (3-byte) pointers, since it is considered to be too costly both in execution time and memory usage. Therefore, pointers declared without a specification of the referred memory type will point to the default memory type (which depends on the selected memory model) being either 1 or 2 bytes. This rule is also valid for library functions using pointers. Sometimes you might want to make an exception, e.g. to keep the format strings of the printf() function and related library functions in rom. This is also supported, as is explained in section 3.10 Strings.

2.3 Absolute Variable Allocation

The way of specifying the address for an absolute variable is also different for the two compilers, as is shown below.

The TASKING way makes it easy to make a preprocessor define to convert the ANSI-C extension. This is particularly useful when you want to compile your program with a compiler for your host. Especially for this purpose the include file cc51.h has been included in the package.

2.4 SFR Registers

As with absolute variable allocation the TASKING compiler uses a different way of specifying the address of an SFR register than the Keil compiler, as is shown in the following example:

However, you will rarely need to specify an SFR register, because for most 8051 derivatives a register include file is delivered with the package.

The Keil 'sfr16' type is not supported by the TASKING compiler, because the order of the few 16-bit wide SFR registers is little endian whereas the 8051 itself is treated big endian.

2.5 Function Qualifiers

For the TASKING compiler the extra qualifiers for functions defined for the ANSI extension appear in the syntax before the function name and parameter list. This is conform the ANSI syntax for assigning type and other qualifiers to an object (variable or function). In contrast these attributes appear after the function name and parameter list in the syntax for the Keil compiler.

Note that for the TASKING compiler 'reentrant' is a separate model and not, as for the Keil compiler, a function attribute. So, for the migration from the Keil compiler to the TASKING compiler you should use the _reentrant model qualifier for every function with the reentrant qualifier. You should ignore any model qualifier you were using in combination with the reentrant qualifier:

The function qualifier used by both compilers to make parameter passing for a function according to the PL/M-51 convention is placed in both grammars before the function identifier. So, the preprocessor definition included in keil.h, as shown below, is sufficient for an easy migration on this point.

2.6 Assembly Interface

The passing of parameters to a function via registers is exactly the same in both compilers. The name and offset for parameters passed in memory is incomparable between the two compilers.

The two compilers use almost the same registers for the return value of a function, as shown in the following table.

Return Type Keil Compiler TASKING Compiler
bit Carry Carry
char /
1-byte pointer
R7 A
int /
2-byte pointer
R6-R7 R6-R7
long R4-R7 R4-R7
float R4-R7 Floating point stack
generic pointer R1-R3 -

Table G-1: Function return types

2.7 Built-in (intrinsic) Functions

Both compilers have several built-in (intrinsic) functions. However, only four of them have the same objective. For these four a preprocessor definition, which is included in the header file keil.h as listed below, will establish the migration.

For the other built-in rotate functions of the Keil compiler, namely _irol_, _lrol_, _iror_ and _lror_, there are no direct replacements.

The TASKING compiler has two other built-in functions namely _getbit and _putbit, which can be used to manipulate bits in an arbitrary bitaddressable byte without the need to declare a separate bit identifier for each bit.

2.8 Library Routines

The prototypes of the library routines of the TASKING compiler package are conform to the ANSI standard. This is not the case for the libraries included in the Keil compiler package. However, in most of these cases the Keil library uses character parameters where the TASKING library uses integers, but due to automatic type conversions generated by the compiler this will usually not create problems.

Both compiler packages allow you to change the I/O mechanism for all I/O functions by changing one function for input and one for output. For the Keil libraries these are getkey() and putchar() and for the TASKING libraries these are _ioread() and _iowrite() respectively. The latter two get a parameter with a stream number passed, thus allowing you to support several independent I/O streams, each with its own mechanism.

3 Compiler Invocation

3.1 Memory Models

The Keil compiler has three memory models, namely small, compact and large. The TASKING compiler has four models, the first three namely small, aux and large respectively are equivalent to the Keil models. The fourth TASKING model is reentrant.

The TASKING compiler always keeps the large virtual stack required for reentrancy in external memory, whereas the Keil compiler keeps it in the default memory determined by the used memory model.

Since the TASKING compiler has a reentrant model, it also has a library to go with it. The parameter passing to the functions included in this library use the reentrant convention, that is via the virtual stack if there are not enough registers.

3.2 Libraries

Both compiler packages contain a library for each memory model. They both use the same naming conventions, thus the following shows the names of equivalent libraries.

Compiler Model Keil
Compiler
TASKING
Compiler
Small c51s.lib c51s.lib
Compact/Auxpage c51c.lib c51a.lib
Large c51l.lib c51l.lib
Reentrant - c51r.lib

Table G-2: Libraries

The Keil compiler package also contains a floating point library for all three memory models. In contrast the TASKING package contains two floating point libraries, which can be used independent of the selected memory model. The most commonly used floating point library (called float.lib) keeps the floating point stack in external ram (XDATA), whereas the other one (called floats.lib) keeps it in internal ram (IDATA). The IDATA version contains only the most basic floating point operations. In general, the smaller one, with respect to data memory usage, is comparable with the small model version of the Keil package (c51fps.lib), and the other one is comparable with the large model version of the Keil package (c51fpl.lib).

3.3 Controls or Pragmas

For the Keil compiler all compiler controls can also be used as a pragma within the C source code. The TASKING compiler has some equivalent notation for most of these directives, either as a compiler command line option or a C source pragma or both, or as an assembler directive. The table below shows how to convert Keil directives to an equivalent TASKING notation.

Keil TASKING Comment
aregs
noaregs
no translation
asm
endasm
asm
endasm
compiler pragma
compiler pragma
code assembly is always generated, use -s for mixing with source code
compact -Ma compiler option
debug
nodebug
-g compiler option
define -D compiler option
disable no translation
eject eject assembler directive
interval use assembly
intpromote
nointpromote
handled automatically by compiler
intvector use assembly
large -Ml compiler option
listinclude -li
listinc
compiler option or
compiler pragma
maxarg -a
arglist
compiler option or
compiler pragma
noamake no translation
nocond no translation
noextend -U_CC51
-Hcc51.h
compiler options
object
noobject
object
noobject
assembler directive
assembler directive
objectextend default behavior
optimize -O
optimize
compiler option or
compiler pragma
see following paragraph
order -Ot compiler option
pagelength pagelength assembler directive
pagewidth pagewidth assembler directive
preprint -E compiler option
print print assembler directive
regfile -C compiler option
registerbank registerbank assembler directive
regparms -Or compiler option
rom small
rom compact
rom large
-rs
-rm
-rl
compiler option
compiler option
compiler option
save save assembler directive
restore restore assembler directive
small -Ms compiler option
src -o compiler option
symbols use linker map file

Table G-3: Controls, pragmas and options

3.4 Compiler Optimizations

Both C compilers allow you to customize the compiler optimizations. The Keil compiler uses the optimize control or pragma and the TASKING compiler uses the -O option or the optimize pragma.

The TASKING compiler allows you to switch on or off most optimization mechanisms independent of other optimizations. This in contrast with the Keil compiler which only allows you to select a certain level of optimization except for optimization seperatly on speed or size.

The following table shows which TASKING optimizations options are comparable to the extra optimizations introduced for each Keil optimize level. Some of the Keil optimizations, however, cannot be switched off in the TASKING compiler, for example, constant folding (Keil level 0), data overlaying (Keil level 2), etc.

Keil
Compiler
TASKING
Compiler
size F
speed f
0 p
1 p
2
3 h
4 w
// and a #pragma see 4.4 Pragmas for switch statements
5 c, s
6 l

Table G-4: Optimization

The TASKING compiler offers you many more optimizations. Refer to the description of the -O option for a detailed description.


Copyright © 2002 Altium BV