hsk-libs-dev
270
High Speed Karlsruhe XC878 library collection
|
The Infineon/XC878.h header defines some unsigned data types:
Signed types should only be used when necessary, floating point arithmetic should be avoided if in any way possible.
The correct place to store a variable depends on four factors:
Size, and frequency are the most obvious, considering Memory Limitations. It is desireable to use fast memory for frequently accessed variables. Large data structures like buffers, arrays and structs simply use too much of the precious memory space to put them anywhere but xdata
.
Both the C51 and SDCC compilers use a technique called overlay to fit all variables into memory. A stack is only used in reentrant functions. Only data/idata
variables can be stacked with push/pop
instructions. Stacking xdata
is emulated in software and thus very slow.
The overlay approach is to build a call graph and thus decide which variables are never used at the same time. These variables are mapped to the same fixed memory addresses.
Variables with a long lifetime are locals in the main() function, static variables and global variables. These variables have to keep their state during the entire runtime. Thus they use memory space that cannot be shared with other variables.
ISRs and functions called by ISRs also cannot share memory, because there is no sensible way to make sure that a given function is not running when an interrupt occurs. In technical terms, each ISR is the root node of its own call graph.
The following table lists recommended memory types:
Context | Size | Critical | Memory |
---|---|---|---|
* | bool | * | bit |
parameter | * | * | data |
const | * | * | code |
local | byte, word | * | data, idata |
>= long | no | xdata | |
ISR/blocking | pdata, xdata | ||
static/global | * | no | xdata |
ISR/blocking | pdata, xdata |
ISR/blocking
refers to memory accessed by ISRs, functions called back by ISRs and sections of code that block an interrupt.
First and foremost, Overlaying is only performed for the default memory. This project is built around the small memory model, i.e. only data
memory is overlaid by SDCC and C51.
The data
memory is only 128 bytes minus the used register banks large. With three register banks that means only 104 bytes of data
memory are available. Thus non-overlayable variables should be placed in idata
in order to use data
memory for well overlayable variables.
Furthermore SDCC does not build a complete call tree, so it cannot eliminate unused functions like C51/LX51 and only overlays leaf functions. I.e. only functions that call no other functions are overlaid.
For SDCC overlaying ISRs is not possible, that is why locals of ISRs should in most cases be placed in idata
, despite the performance impact.
A limitation of C51/LX51 is that it ignores explicit memory assignments in function parameters and always places them in the default memory, if they cannot be passed in registers. This limitation does not appear to be documented, but it was reported by an ARM support employee in case #530915.
SDCC does not share this limitation, it can place function parameters in all kinds of memory. Because such assignments are ignored by C51/LX51, parameter memory type should be optimised for SDCC. Explicit memory assignments prevent parameters from being passed in registers. SDCC only passes the first non-bool
parameter in registers, so optimizations should be performed on the non-overlayable arguments following it.
For single use functions like init
and enable
functions, it might make sense to pass parameters in xdata
. In such cases the SDCC memory assignment style should be used, to give the C51 preprocessor the chance to remove the assignments.
If an application runs out of data
space locals should be put into idata
memory. Variables accessed by ISRs/ISR callbacks should be placed in pdata
or idata
. If that suffices the code should be checked for frequently accessed variables. The most frequent ones should be assigned to the default memory type if possible.
Both SDCC and C51 provide detailed information about memory use. The effects of relocating variables are often counter-intuitive, because it may interfere with several compiler and linker optimizations. This it is necessary to make use of this information in order to make sure that changes have the desired effect.
For SDCC check the assembler output for the DSEG
area (search regex /\\\.area DSEG/
):
The .map
file lists the complete memory layout produced by the linker (search regex /^DSEG/
):
In µVision the .map
file can be accessed by double clicking the project in the project tree view (search string "D A T A"
):