In addition to the ANSI storage classes SDCC allows the following MCS51 specific storage classes:
This is the default storage class for the Small Memory model (data and near or the more ANSI-C compliant forms __data and __near can be used synonymously). Variables declared with this storage class 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 declared with this storage class will be placed in the external RAM. This is the default storage class 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 declared with this storage class 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.
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 4.1). This is the default storage class 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' declared with this storage class 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 a storage class specifier. 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 storage class, 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 Storage Class extensions 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 it is possible to write header files which can be shared among different compilers (see section 6.1).
SDCC allows (via language extensions) pointers to explicitly point
to any of the memory 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 3.12 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.