SDCC supports the following MCS51-specific intrinsic address spaces:
This is the default (generic) address space for the Small Memory model. Variables in this address space will be allocated in the directly addressable portion of the internal RAM of a 8051, e.g.:
__data unsigned char test_data;Writing 0x01 to this variable generates the assembly code:
75*00 01 mov _test_data,#0x01
Variables in this address space will be placed in the external RAM. This is the default (generic) address space for the Large Memory model, e.g.:
__xdata unsigned char test_xdata;Writing 0x01 to this variable generates the assembly code:
90s00r00 mov dptr,#_test_xdata
74 01 mov a,#0x01
F0 movx @dptr,a
Variables in this address space will be allocated into the indirectly addressable portion of the internal ram of a 8051, e.g.:
__idata unsigned char test_idata;Writing 0x01 to this variable generates the assembly code:
78r00 mov r0,#_test_idataPlease note, the first 128 byte of idata physically access the same RAM as the data memory. The original 8051 had 128 byte idata memory, nowadays most devices have 256 byte idata memory. The stack is located in idata memory (unless -xstack is specified).
76 01 mov @r0,#0x01
Paged xdata access is just as straightforward as using the other addressing
modes of a 8051. It is typically located at the start of xdata and
has a maximum size of 256 bytes. The following example writes 0x01
to the pdata variable. Please note, pdata access physically accesses
xdata memory. The high byte of the address is determined by port P2
(or in case of some 8051 variants by a separate
Special Function Register, see section ).
This is the default (generic) address space for the Medium
Memory model, e.g.:
__pdata unsigned char test_pdata;Writing 0x01 to this variable generates the assembly code:
78r00 mov r0,#_test_pdataIf the --xstack option is used the pdata memory area is followed by the xstack memory area and the sum of their sizes is limited to 256 bytes.
74 01 mov a,#0x01
F2 movx @r0,a
'Variables' in this address space will be placed in the code memory:
__code unsigned char test_code;Read access to this variable generates the assembly code:
90s00r6F mov dptr,#_test_codechar indexed arrays of characters in code memory can be accessed efficiently:
E4 clr a
93 movc a,@a+dptr
__code char test_array[] = {'c','h','e','a','p'};Read access to this array using an 8-bit unsigned index generates the assembly code:
E5*00 mov a,_index
90s00r41 mov dptr,#_test_array
93 movc a,@a+dptr
This is a data-type and an address space. When a variable is declared as a bit, it is allocated into the bit addressable memory of 8051, e.g.:
__bit test_bit;Writing 1 to this variable generates the assembly code:
D2*00 setb _test_bitThe bit addressable memory consists of 128 bits which are located from 0x20 to 0x2f in data memory.
Like the __bit keyword, __sfr / __sfr16 / __sfr32 / __sbit signify both a data-type and named address space, they are used to describe the special function registers and special __bit variables of a 8051, eg:
__sfr __at (0x80) P0; /* special function register P0 at location 0x80 */Special function registers which are located on an address dividable by 8 are bit-addressable, an __sbit addresses a specific bit within these sfr.
/* 16 bit special function register combination for timer 0
with the high byte at location 0x8C and the low byte at location 0x8A */
__sfr16 __at (0x8C8A) TMR0;
__sbit __at (0xd7) CY; /* CY (Carry Flag) */
Please note, if you use a header file which was written for another
compiler then the __sfr / __sfr16 / __sfr32 / __sbit intrinsic
named address spaces will most likely be not compatible. Specifically
the syntax sfr P0 = 0x80; is compiled without warning
by SDCC to an assignment of 0x80 to a variable called P0.
Nevertheless with the file compiler.h
it is possible to write header files
which can be shared among different compilers (see section ).
SDCC allows (via language extensions) pointers to explicitly point
to any of the named address spaces of the 8051.
In addition to the explicit pointers, the compiler uses (by default)
generic pointers which can be used to point to any of the memory spaces.
Pointer declaration examples:
/* pointer physically in internal ram pointing to object in external ram */Well you get the idea.
__xdata unsigned char * __data p;
/* pointer physically in external ram pointing to object in internal ram */
__data unsigned char * __xdata p;
/* pointer physically in code rom pointing to data in xdata space */
__xdata unsigned char * __code p;
/* pointer physically in code space pointing to data in code space */
__code unsigned char * __code p;
/* generic pointer physically located in xdata space */
unsigned char * __xdata p;
/* generic pointer physically located in default memory space */
unsigned char * p;
/* the following is a function pointer physically located in data space */
char (* __data fp)(void);
The 8051 family of microcontrollers have a minimum of 128 bytes of
internal RAM memory which is structured as follows:
- Bytes 00-1F - 32 bytes to hold up to 4 banks of the registers R0
to R7,
- Bytes 20-2F - 16 bytes to hold 128 bit variables and,
- Bytes 30-7F - 80 bytes for general purpose use.
Additionally some members of the MCS51 family may have up to 128 bytes
of additional, indirectly addressable, internal RAM memory (__idata).
Furthermore, some chips may have some built in external memory (__xdata)
which should not be confused with the internal, directly addressable
RAM memory (__data).
Sometimes this built in __xdata memory has to be activated
before using it (you can probably find this information on the datasheet
of the microcontroller your are using, see also section Startup-Code).
Normally SDCC will only use the first bank
of registers (register bank 0), but it is possible to specify that
other banks of registers (keyword __using )
should be used for example in interrupt
routines. By default, the compiler will place the stack after the
last byte of allocated memory for variables. For example, if the first
2 banks of registers are used, and only four bytes are used for data
variables, it will position the base of the internal stack at address
20 (0x14). This implies that as the stack grows, it
will use up the remaining register banks, and the 16 bytes used by
the 128 bit variables, and 80 bytes for general purpose use. If any
bit variables are used, the data variables will be placed in unused
register banks and after the byte holding the last bit variable. For
example, if register banks 0 and 1 are used, and there are 9 bit variables
(two bytes used), data variables will be placed starting from
address 0x10 to 0x20 and continue at address 0x22. You can also use
--data-loc to specify
the start address of the data and --iram-size
to specify the size of the total internal RAM (data+idata).
By default the 8051 linker will place the stack after the last byte of (i)data variables. Option --stack-loc allows you to specify the start of the stack, i.e. you could start it after any data in the general purpose area. If your microcontroller has additional indirectly addressable internal RAM (idata) you can place the stack on it. You may also need to use --xdata-loc to set the start address of the external RAM (xdata) and --xram-size to specify its size. Same goes for the code memory, using --code-loc and --code-size. If in doubt, don't specify any options and see if the resulting memory layout is appropriate, then you can adjust it.
The linker generates two files with memory allocation information. The first, with extension .map shows all the variables and segments. The second with extension .mem shows the final memory layout. The linker will complain either if memory segments overlap, there is not enough memory, or there is not enough space for stack. If you get any linking warnings and/or errors related to stack or segments allocation, take a look at either the .map or .mem files to find out what the problem is. The .mem file may even suggest a solution to the problem.