Topic: RL-51 linker
Q : When linking my project I obtain a message error 107 'ADDRESS SPACE OVERFLOW - Segment: ?C_XSTACK': Why?
A : First you must realise that this segment contains the external stack and all the 'pdata' qualified varaibles. This segment is limited up to 256 bytes in external RAM (xdata). Therefore you have to check that the size of 'pdata' variables plus the external stack size (if you are using some) is less than 256 bytes.
__________________________________________________________________________________________________
Q : The microcontroller we are using has 20 Kbytes internal code memory, 256 bytes RAM. My problen is that I have an error message when linking: ERROR 107: ADDRESS SPACE OVERFLOW - SEGMENT: ?DT?...
I do not understand this, because my total program code is only xxx bytes, so I still have free code memory. What is going wrong?
A : The address space overflow occurs on a DATA segment (?DT?...). You have more than 128 bytes of direct addressable variables or more than 256 bytes of indirect addressable variables. There are several solutions:
1. If you are using the SMALL memory model for the RC-51, try the LARGE memory model if your board has external data memory. This puts the variables in xdata space by default.
2. Otherwise try to decrease the number of varaibles addressable in Data space.
3. You can use a space qualified variable definition in idata memory space such as 'char idata var_name;' to define a variable in a specific memory space.
4. Have you put all your constant variables in code space, if possible?
__________________________________________________________________________________________________
Q: What does the linker error 121 'IMPROPER FIXUP' mean?
A : The linker error 121 'IMPROPER FIXUP' means that a reference cannot be resolved by the linker. In most cases, this error occurs when an AJMP (ACALL) to an external symbol cannot be reached because the symbol is farther away than 2kb. The solution is to convert the AJMP or ACALL into a LJMP or LCALL.
This would typically happen when you program in assembler, but can also happen when programming in C in the TINY memory model.
The same message, can be output for a SJMP NOT_REACHABLE_SYMBOL and may occur when a bit of a bdata byte is accessed that will not be relocated into BDATA (bit addressable space).
__________________________________________________________________________________________________
Q : Where is the stack located in my project?
A : Firstly, for the internal stack:
You can find the exact location of the internal stack in the Map Report of the LX51 linker (accessible via menu 'View | Map Report from Linker'). In this file, you will find the details about '* * * * * * * DATA MEMORY * * * * * * *'. At the end of this section, you will encounter a segment _STACK with the relocation "* * STACK * *". On this line you have first the physical memory space 'TYPE' (DATA or IDATA), then the absolute base address (under 'BASE'), and always a length 'LENGTH' of 1. In fact the length is limited to the amount of internal memory in your microcontroller. In the start-up routine of your program, SP is initialized to this absolute base address.
Secondly, for the external stack if your application uses this feature (selected in the RC-51 compiler options 'Options | Project | RC51 | Memory Model | Use External Stack') :
The segment name 'SEGMENT NAME' for this stack is '?C_XSTACK'. It is always located at the beginning of a 256 byte 'page' of XDATA memory. So to find it you have to locate the details of '* * * * * * * XDATA MEMORY * * * * * * *". At any time, this 256 byte 'page' of XDATA is pointed to by P2. SPX is a DATA MEMORY byte reserved by the compiler and managed as SP in the internal memory for the internal stack.
__________________________________________________________________________________________________
Q : How can I occupy fixed positions in memory?
A :
1. For a variable declaration, use the keyword AT to specify the position in data space, e.g.:
AT 0x500 data char variable_name;
2. If you have to put more variables at fixed positions, in the same context, maybe it is better to use a structure:
AT 0x500 structname struct {
int variable1;
int variable 2;
char variable2;
};
3. If you want to have direct access to a specific memory location, use a pointer:
*(char xdata *) (0x500) = 10;
4. If you want to know exactly where the variables of a whole file are in memory, do the following:
Via 'Options | Project | Lx51 | More' put: 'xdata(?xd?filename(0x1000))'. Then, all the relocateable variables in the filename will be positioned after the address 0x1000 in the xdata space.
__________________________________________________________________________________________________
Q : How do I relocate some functions to an absolute address?
A : Relocating ONE function is easy (using the "at" attribute in the source).
Relocating ALL functions is still easy, using the FRelocation fields under Options|Project|Linker|Relocation.
Relocating a set of functions however is tricky and requires using the "more" field under Options|Project|Linker with a syntax that you can see in the picture. Note that you must take the module/function names from the map file (View|Map report from the linker), because they are different from what you call the same function in your source, and that those names might change if you change important parameters for the fucntion (example reentrant/not reentrant).
__________________________________________________________________________________________________
Q : What does the startup code do? Do I need it? How can I modify it?
A : This note will tell you everything there is to know about 8051 startup code for Raisonance tools.
What is the startup code?
*********************
From the RC51 manual: The Startup Code contains initializations needed to make your C program work correctly. It is executed at power-up and, when finished, it jumps to the “main” function of your application. An appropriate version of the startup code (depending on some parameters like memory model and others) is linked with the rest of the application when the “main” symbol is found by the compiler and performs a variety of initialization tasks including:
* Initialize the internal memory to 0
* Initialize Static variables, as required by ANSI
* Initialize the timer0 to obtain a UART frequency of 9600 with typical quartz.
* Initialize the stack pointer
The Startup Code is written in assembler and can be found in the file ride\inc\sources\8051\rc51\startup.a51. It is recommended not to modify this file; if you need a specific initialization for your project we suggest you perform it at the beginning of the “main” function.
Do I need it?
**********
If you are programming in C you definitely need the startup code in 99% of the cases (there could be exceptions, for example for modules that are not executed at power up, but rather called by other modules)
The standard startup code is included by the linker when the main() symbol is found (therefore, an easy way to avoid the startup code is to write a program without main() function), and works well for most cases (different chips, different HW configurations, different tools options), but, in some cases, you might want to extend or modify the startup code as explained below.
How is the startup code managed in RIDE?
**********************************
Starting around BN729 (second half of 2002), RIDE offers 3 different possibilities to manage the startup code, as shown in the picture (note that the Starup Opions are part of the Linker options, even if there is also 1 option in the compiler that can affet startup code)
The "Default Startup" Option
The default option is "Default Startup" (shown in the picture above). When you check this option, the linker will do the following:
* Look in the libraries for the correct startup file (which is determined by a number of parameters, including the memory model, the source code, the derivative chosen and the debug target)
* Replace some constant values that are in the object file with the value of fields like "Initialized RAM size" and "Initial Value for Timer 1"
* Link the resulting object with the rest of your application, without leaving any trace in the project tree (the only way to check that the initialization code has actually been included is to check the map report from the linker, where you will find a segment called ?PR?C51_STARTUP?)
This approach is the safest and is also pretty well optimized, but, in some cases, you might need extended startup functionality: in this case you can use one of the two options below.
The "User Defined Startup" Option
Use this option when the startup code you need is totally different from what is provided by default with RIDE. When you use this option, the linker will simply not include any startup code (exactly the same as if your application contains no main() function): it's up to you to manually add a node in the project tree that contains some startup code. Note that, if you just take whatever C program and try out this option without adding a properly working startup code of your own, you will not even be able to start the debug session, as there will be no reset vector (a random part of your code will be put at address 0 and the stack will not be initialized -> unpredictable behavior).
If you program in C, your specific startup code will need to do most of the things that are done by the standard startup anyway, so we suggest you use the method described below instead, but this option is left for cases where no startup altogther is needed (for example, as already mentioned, to compile a set of routines that will be launched by some other program)
The "Micro-Specific Startup" Option
Use this option when the startup code you need is basically the standard one, plus some micro-specific initialization (typically for HW features, such as buses, configuration bytes or peripherals).
When you use this option, RIDE will do the following:
* Take the standard startup file that is under RIDE\INC\SOURCES\8051\RC51\startup.a51 (you can see the version as of BN730 here)
* Take the code that you have entered in the "Micro-specific Initialization code" text field (note that this field is pre-filled with the appropriate code for some derivatives) and insert it in the startup.a51 file (between markers; it's line 201 in the file linked above)
* Create a new file called startup.a51 in the project directory and insert a new node in the project for this file (after asking confirmation)
You can now customize the startup file that is in the project tree by edtiting it (be careful to follow the guidelines provided in the comments).
Note that, some of the startup customizations that are done via the RIDE interface (example: Initialized RAM size) or automatically (example: way used to address >256 bytes of XDATA) are not taken into account here: you need to do everything manually by editing the startup.a51 file.
Micro dependencies: initialized Xdata variables of more than 256 bytes.
The startup code is usually not too dependent on the particular 8051 derivative choosen, in that most of the micro specific features (usually peripherals) can be initialized in the main application, but there are some exceptions to this rule, including some SFRs initialization that must be done before accessing memory (example of the uPSD, this is managed by RIDE by automatically prefilling the "Micro-specific Initialization code" field) and accessing XDATA variables over the first 256 bytes.
Note first that the startup code only needs to access XDATA over 256 bytes if you have more than 256 bytes of initialized XDATA variables in your application: this is quite rare, but in case it happens you need to read the following.
Different 8051 derivatives implement different ways of accessing XDATA memory over 256 bytes: typically this is accomplished by using P2 as the high byte of the address, but some derivatives (especially those with internal XRAM) use different SFRs for this. The startup code is written to be as compact as possible, and will therefore try to intialize the XRAM memory using the MOVX @Ri instruction, but this does not work over 256 bytes when P2 is not used: in this last case the XRAM must be initialized using the MOVX @DPTR instruction.
When using the "Default Startup" option, the linker will choose which addressing mode to use according to the value of the option "Component with XRAM".
When using the "Micro-Specific Startup" option, you must edit the startup file if you need to initialize XDATA variable >256 bytes (look for INTERNAL_XRAM_LIKE_8xC592 in the startup.a51).
RAISONANCE - 17, avenue Jean Kuntzmann - F-38330 Montbonnot St Martin - FRANCE
There are 10 types of people in the world: Those who understand binary, and those who don't.