|
3
Gordon Drive, P.O.Box 1347 Rockland, Maine 04841 U.S.A.
|
|
© 2004 Avocet Systems, Inc.
|
Call
Us Today at 207-596-0080
|
|
Avocet Systems, Inc. : The Complete Solution for Embedded Systems
Development Tools
|
|
|
Tech
Tips
Use of Pointers with the 8051XA Compiler
Introduction
Customers using this compiler have posed various questions to Avocet's technical
support department concerning error messages given by the compiler relating
to declarations, especially those in respect of pointers. This article aims
to provide help on this subject, providing information that was not available
in the first edition of the manual and augmenting that provided in the second
(which latter is available in electronic format to users registered with Avocet
Systems).
Some General Points
Simple pointer declarations follow that described in any text on the C language;
as for example in the declaration:
long* pl;
which declares pl as a pointer to a long integer and can be assigned a value
typically by an statement such as: long longvar;
pl = &longvar;
However,for many compilers written for embedded controllers additional keywords
are provided to facilitate building code for a ROM based application. Let us
review the use of these keywords when employed in pointer declarations. For
example, if we use the keyword near, then this means that the object so qualified
is located in internal RAM below 400H. The declaration:
near int* pni;
declares pni to be a pointer to an integer located in internal RAM below 400H.
Note that near refers to the object pointed to, not the pointer itself. If we
wished to place the pointer in internal RAM, then we would write the declaration:
int* near npi;
Thus qualifiers placed to the left of the asterisk apply to the object pointed
to and those to the right of it, to the pointer itself. Other qualifiers to
which this applies are far, code, huge. and persistent. The sample declarations
below exemplify their use.
near int* far fpni; /* Far pointer to near integer */
In the above, the use of the far keyword means that pointer may reside in any
bank (64K block).
far int * near npfi /* Near pointer to far integer */
Code generated for the use of a far pointer will involve loading a segment register
(ES) register, to access the far data object.
far code int * far fpfi; /* Far pointer to far int */
For the above declaration, both the pointer and the integer pointed to can reside
in banks other than those currently selected.
far code int * near npfci; /* Near ptr to int in far code space */
Memory Models
Some clarification of pointer characteristics as they relate to the memory model
used will be helpful.
Small Model
In small model pointers are 16 bits and have the following characteristics.
If the object pointed to lies in the address range of the internal RAM, 00 to
3FF, then the pointer will behave as a pointer to internal RAM. If the address
of the object lies above this, then the pointer will act as a pointer to code.
The reason for this is that any statically allocated initialized data object
is placed in ROM, as opposed to RAM to save data space. You would only use the
near qualifier to cause an initalized object to be placed in internal RAM. Other
than that, you don't have to use the near and code keywords.
Medium Model
In medium model, pointers access data and address the concatenation of internal
RAM and RAM in the current bank; a total of 64K. The far qualifier is used to
access objects outside the current bank and can be used in conjunction with
the code qualifier. The near qualifier is used to address internal RAM explicitly.
Large Model
Large model is the same as medium model except that code up to 16Mbytes is allowed.
The use of pointers is the same as medium model except that the huge qualifier
can be applied to pointers to access objects in any bank. Huge pointers are
32 bits. The least signifigant 24 bits are used for the address and the most
signifigant bit is set (by the compiler) for access to code and cleared for
access to data.
Huge Model
Huge model is the same as large model except that pointers are 32 bits by default.
More Complex Declarations
Some customers' questions on declarations arise concerning more complex declarations,
say initializing arrays of pointers to functions etc. As a general rule you
can simplify your declarations by using typedefs. As an example, consider the
following:
typedef struct { int si; long sl; char* pcc; int
(*pvfil)(int, long); } STRUCTYPE;
You can then make declarations of the form:
far STRUCTYPE * near npfs; STRUCTYPE * far fps;
Additional example material is given below
int fn1(int, long); int fn2(int, long);
typedef struct { int si; long sl; code char* pcc; int (*pvfil)(int, long); }
CODESTRUCTYPE;
#pragma strings code
code CODESTRUCTYPE cst[] = {{934, 9345689, "string1", fn1}, {8822, 12345689,
"string2", fn2}}; #pragma strings
Notice the use of "#pragma strings code" to place the string constants in ROM.
|
|
|