SDCC startup code clears P2 to 0x00 and does not clear all used xdata.
SDCC start-up uses a movx @r1,a instruction to clear xdata and assumes that the value written to P2 will determine high byte of xdata address. The value written to P2 does not determine the high byte of the xdata address on Silicon Labs C8051 MCUs.
The value written to the P2 port latch is not readable until the crossbar is initialized. So the value or P2 may change unexpectedly when enabling the crossbar. Any code that depends on the reset value of P2 may get unexpected results.
Solution
There are two possible solutions to solve this problem.
1. Disable xdata initialization in SDCC start-up. Add the following command line build option to the compiler AND linker tab of the 'Tool Chain Integration' panel in the Silicon Labs IDE.
--no-xinit-opt
Using this option, the start-up code will not clear any global variables in xdata that are not explicitly initialized.
2. Overload crtpagesfr.asm
If you want SDCC to clear all xdata variables, this can be accomplished by overloading the crtpagesfr.asm file.
Copy the crlpagesfr.asm from the SDCC directory to your project folder.
Crogram FilesSDCClibsrcmcs51crtpagesfr.asm
Add the local crtpagesfr.asm file to your project and add to the build.
Modify the local crtpagesfr.asm to use the appropriate EMI0CN sfr address for __XPAGE. The address of the EMI0CN sfr is device dependent for Silicon Labs C8051 MCUs.
__XPAGE == 0xaa ; EMI0CN address is 0xaa for C8051F930
__XPAGE == 0xa2 ; EMI0CN address is 0xa2 for C8051F120
Note that the --no-xinit-opt command line option should not be used when overloading crtpagesfr.asm.
Only MCUs with more than 256 bytes of RAM have xdata and an EMI0CN sfr.
The first solution is really not the way to proceed. It will inhibit all initializations of variables in xdata.
And the second is a pretty hard way to do the right thing.
All that is required is to declare an _XPAGE sfr at the address of EMI0CN as explaind in the SDCC manual.
__sfr __at(0xAA) _XPAGE; // EMI0CN for C8015F930
Replace the address with the value from the datasheet of your MCU.
The reason behind this is that the original 8051 used P2 to output the MSB of the address when a MOVX @Ri is used. And this instruction is used for copying initializations from code memory to xdata at startup. SDCC sets _XPAGE which is overlayed on P2 in the library, but when _XPAGE is already specified in the project, that overrules whatever is in the library. We chose the name _XPAGE as there is no common name used for this register among all 8051 derivative manufacturers.
SDCC startup code clears P2 to 0x00
The first solution is really not the way to proceed. It will inhibit all initializations of variables in xdata.
And the second is a pretty hard way to do the right thing.
All that is required is to declare an _XPAGE sfr at the address of EMI0CN as explaind in the SDCC manual.
Replace the address with the value from the datasheet of your MCU.
The reason behind this is that the original 8051 used P2 to output the MSB of the address when a MOVX @Ri is used. And this instruction is used for copying initializations from code memory to xdata at startup. SDCC sets _XPAGE which is overlayed on P2 in the library, but when _XPAGE is already specified in the project, that overrules whatever is in the library. We chose the name _XPAGE as there is no common name used for this register among all 8051 derivative manufacturers.
Maarten Brock
SDCC Developer