This chapter contains the following sections:
Startup Code
Register Usage
Stack
Heap
Floating Point Arithmetic
Special Floating Point Values
Trapping Floating Point Exceptions
Floating Point Trap Handling API
When linking your C modules with the library, you automatically link the object module, containing the C startup code. This module is called cstart.obj and is present in every C library.
Because this module specifies the run-time environment of your TriCore C application, you might want to edit it to match your needs. Therefore, this module is delivered in source in the file cstart.asm in the src subdirectory of the lib directory. Typically, you will copy the template startup file to your own directory and edit it. The startup code contains equates to tune the startup code. The invocation (using the cctri control program) is:
cctri -c cstart.asm
In the C startup code an absolute code section is defined for setting up the power on vector and the TriCore C environment. The power-on vector contains a definition of the the _START label. This global label should not be removed, since the C compiler referres to it. It is also used as the default start address of the application.
In the file cstart.asm the actual location of several special function registers is required. These addresses are specified in the regcpu_name.def SFR system include files. You can include such a file with the assembler option -Ccpu_name. In EDE the appropriate file is included when you have selected a CPU type. If you do not specify an SFR file, the default SFR regtc10gp.def file is included.
The stack size is defined in the locator control file (tri.i in directory etc) with the macros USTACK and ISTACK which results in sections called ustack and istack. See Stack for detailed information on the stack.
The heap is defined in the description file with the keyword heap, which results in as section called heap. See section 7.4 Heap for detailed information on heap management.
The startup code takes care of clearing global variables and initializing C variables residing in RAM. The startup code copies the initial values of initialized C variables from ROM to RAM, using a locator generated table (also known as the 'copy table') and a run-time library function _c_init.
When everything described above has been executed, your C application is called, using the global label main, which has been generated by ctri for the C function main().
When the C application 'returns', which is not likely to happen in an embedded environment, the program ends with a DEBUG16 instruction, at the assembly label _exit. When using a debugger, it can be useful to set a breakpoint on this label to indicate that the program has reached the end, or that the library function exit() has been called.
To control cstart.asm from within EDE, you first have to add cstart.asm to your project:
Select the Project | Configure Selected CPU... menu item and activate the Cstart tab. Enable the Automatically Add cstart.asm check box and click OK.
The file cstart.asm is added to your project. Now you can specify all your startup settings in the Startup Code tab of the Configure Selected CPU dialog:
Select the Project | Configure Selected CPU... menu item.
You can specify CPU settings in the same dialog:
Select the Project | Configure Bus... menu and select the appropriate bus configuration settings. EDE automatically defines macros according to the selected settings.
A number of other macro preprocessor symbols are used. These can be enabled or disabled using the assembler command line option -D with the following syntax:
In the startup file the following macro preprocessor symbols are used:
Define | Description |
External Boot Memory Configuration (BOOTCFG) | |
_BOOTCFG_ADDRC | Address generation value |
_BOOTCFG_AGEN | Read access wait-states value |
_BOOTCFG_BCGEN | Address Cycles value |
_BOOTCFG_CFG | Variable wait-state insertion value |
_BOOTCFG_CMULT | Extended address setup value |
_BOOTCFG_SETUP | Active /WAIT level value |
_BOOTCFG_WAIT | Byte control signal timing mode value |
_BOOTCFG_WAITINV | Wait cycle multiplier value |
_BOOTCFG_WAITRDC | Boot Memory Data Width value |
Memory Control (PMUCON0/DMUCON) | |
_PMUCON0_CCBYP | Code cache bypass value |
_PMUCON0_CCSIZ | Code cache size value |
_DMUCON_DCAON | If defined, Enable data cache |
Startup | |
_NO_BTV_INIT | If define, Base Address of Trap Vector Table is not initialized with trap table start address (trap_tab). |
_NO_BIV_INIT | If defined, Base Address of Interrupt Vector Table is not initialized with interrupt table start address (_lc_u_int_tab). |
_NO_ISP_INIT | If defined, Interrupt Stack Pointer is not initialized with end address of interrupt stack (_lc_ue_istack). |
_NO_USP_INIT | If defined, User Stack Pointer is not initialized with end address of user stack (_lc_ue_istack). |
_NO_PCX_RESET | If defined, the Previous Context is not explicitly cleared. |
_NO_PSW_RESET | If defined, the Call Depth Counter is not explicitly cleared. |
_NO_A0A1_ADDRESSING | If defined, global address register A0/A1 is not initialized with start address of the _a0/_a1 addressable area (_lc_gb_a0/1). |
_NO_A8A9_ADDRESSING | If defined, global address register A8/A9 is not initialized with start address of the _a8/_a9 addressable area (_lc_gb_a8/9). |
_NO_CSA_INIT | If defined, Context Save Area lists are not initialized. |
_NO_WATCHDOG_INIT | If defined, Watchdog timer disabled. |
_NO_BUS_CONF | If defined, bus configuration registers are not initialized. |
_NO_C_INIT | If defined, C variables are not initialized. |
_NO_ARG_INIT | If defined, disable initialization of argc and argv[]. |
_NO_EXIT | If defined, C library function exit() or abort() not supported. |
Miscellaneous | |
_CALL_INIT | Can be set to a function to be called before main. This function cannot have a return or arguments. This function can be used, for example, to initialize the serial port before main is called. This is useful for building programs without making any modifications to the original source. |
_CALL_ENDINIT | Can be set to a function to be called before the ENDINIT instruction is executed. Like the CALLINIT function, it cannot not have a return value or arguments. |
CPU functional bypasses | |
_TC112_XXX | If defined, TC112 CPU functional defect XXX is bypassed and/or checked. |
_TC113_XXX | If defined, TC113 CPU functional defect XXX is bypassed and/or checked. See appendix C CPU functional Problems CPU Functional Problems for a complete list of these macros. |
Table 7-1: Defines used in cstart.src
The following table shows the locator labels used in the startup code.
Define | Description |
_START | start label, mentioned in description file (tri.dsc) |
_c_init | label copy table init function |
main | start label user C program |
exit | start label of exit() function |
_exit | exit() function jumps to this place |
_CALL_ENDINIT | label called before ENDINIT |
_CALL_INIT | _CALL_INIT label called before main() |
_lc_gb_a0 | locator label start of A0 addressable area |
_lc_gb_a1 | locator label start of A1 addressable area |
_lc_gb_a8 | locator label start of A8 addressable area |
_lc_gb_a9 | locator label start of A9 addressable area |
_lc_u_int_tab | locator label interrupt table |
_lc_ub_csa | locator label context save area begin |
_lc_ue_csa | locator label context save area end |
_lc_ue_istack | locator label interrupt stack end |
_lc_ue_ustack | locator label user stack end |
Table 7-2: Locator labels used in startup code
ctri will try to use the available registers as efficient as possible. The compiler uses a flexible register allocation scheme, which implies that any change to the C code may result in a different register usage.
The TriCore register file consists of 16 data registers and 16 address registers, which are 32 bits wide. The contents of registers D8-D15 and A10-A15 are saved by the CALL instruction and restored by the RET instruction. As a result, these registers (with the exception of the link register A11) can be used in a function without the need to save and restore their original contents. The registers D0-D7 and A2-A7 are considered "scratch": their contents is undefined after a function call. The "global registers" A0-A1 and A8-A9 are not changed by a function call or context switch.
For C function return types, the following registers are used:
Return type | Register | Description |
char | D2 | return register |
short | D2 | |
int/ long / float | D2 | |
double | D2/D3 | (most significant part in D3) |
pointer | A2 | return register |
Table 7-3: C function return types
Structures and unions of up to 8 bytes in size are returned in registers D2/D3. Larger structures or unions are returned on the stack. The address of this return area is passed as an implicit first argument in A4.
The following table summarize the register usage conventions used by ctri:
Register | Usage | Register | Usage |
D0 | scratch | A0 | global |
D1 | scratch | A1 | global |
D2 | return register for arithmetic types | A2 | return register for pointers |
D3 | most significant part of 64 bit result | A3 | scratch |
D4 | parameter | A4 | parameter |
D5 | parameter | A5 | parameter |
D6 | parameter | A6 | parameter |
D7 | parameter | A7 | parameter |
D8 | saved register | A8 | global |
D9 | saved register | A9 | global |
D10 | saved register | A10 | stack pointer |
D11 | saved register | A11 | link register |
D12 | saved register | A12 | saved register |
D13 | saved register | A13 | saved register |
D14 | saved register | A14 | saved register |
D15 | saved register, implicit register | A15 | saved register, implicit pointer |
Table 7-4: Register usage
The stack is used for local automatic variables, function parameters and saved registers.
The following diagram show the structure of a stack frame.
Figure 7-1: Stack diagram
The stack size is defined in the locator control file (tri.i in directory etc) with the macro USTACK and istack, which results in sections called ustack and istack.
The locator defined label _lc_ue_ustack refers to the top of the user stack area and is used in the file cstart.asm to initialize the user stack pointer register (SP). The locator defined label _lc_ue_istack refers to the top of the interrupt stack area and is used in the file cstart.asm to initialize the interrupt stack pointer register (ISP)
As long as the user program does not change the IS bit in the program status word (PSW), only the user stack is used. Refer to the TriCore Architecture (v1.3) Manual for the implications of an IS bit change.
The heap is only needed when dynamic memory management library functions are used: malloc(), calloc(), free() and realloc(). The heap is a reserved area in memory. Only if you use one of the memory allocation functions listed above, the locator automatically allocates a heap, as specified in the locator description file with the keyword heap.
A special section called heap is used for the allocation of the heap area. The size of the heap is defined in the locator control file (tri.i in directory etc) with the macro HEAP, which results in a section called heap. The locator defined labels _lc_bh and _lc_eh (begin and end of heap) are used by the library function sbrk(), which is called by malloc() when memory is needed from the heap.
The special heap section is only allocated when its locator labels are used in the program.
Floating point arithmetic support for the compiler ctri is included in the software as a separate set of libraries or in the hardware when available (only single precision). During linking you have to specify the desired floating point library after the C library. The libraries are reentrant, and only use temporary program stack memory.
To ensure portability of floating point arithmetic, floating point arithmetic for the compiler ctri has been implemented complying to the IEEE-754 standard for floating point arithmetic. See the IEEE Standard Binary for Floating-Point Arithmetic document [IEEE Computer Society, 1985] for more details on the floating point arithmetic definitions. This document is referred to as IEEE-754 in this manual.
The compiler ctri supports both single and double precision floating point operations using the ANSI C types float and double respectively. To optimize for speed, also a non-trapping library is included. For the library names, see section 6.3, C Libraries.
It is possible to intercept floating point exceptional cases and, if desired, handle them with an application defined exception handler. The intercepting of floating point exceptions is referred to as 'trapping'. Examples of how to install a trap handler are included.
The level to which the floating point implementation complies to the IEEE-754 standard, depends on the choosen configuration.
All floating point calculations are executed using the 'round to nearest (even)' rounding mode, since this is required by ANSI-C 89. This is conform IEEE-754. Because there are no double precision floating point hardware instructions, an emulating library is always needed for double precision calculation.
When the use of hardware FPU instructions is choosen (-FPU), the available hardware instructions for single precision floating point will be used either in the compiler or in one of the libraries. For double precision floating point calculations the choosen floating point emulaton library will be used. When no hardware FPU instructions are allowed, all floating point operations will be used from the choosen floating point emulaton library.
In EDE you can specify to use the single precision floating point hardware: Select the Project | C Compiler Options | Project Options... menu item and enable the
Use hardware single precision floating point instructions check box
in the Misc tab.
This option is only available (and relevant) when you
enable the FPU present (on user defined CPU) check box on the CPU tab in the Project | Processor options... menu item.
-FPU
in Chapter 4,
Compiler Use.
The following implementation issues for the single precision hardware instructions (optionally implemented on the TriCore chip), are important:
The following implementation issues for the trapping floating point library are important:
The following implementation issues for the non-trapping floating point library are important:
Below is a list of special, IEEE-754 defined, floating point values as they can occur during run-time.
Special value | Sign | Exponent | Mantissa |
+0.0 (Positive Zero) | 0 | all zeros | all zeros |
-0.0 (Negative Zero) | 1 | all zeros | all zeros |
+INF (Positive Infinite) | 0 | all ones | all zeros |
-INF (Negative Infinite) | 1 | all ones | all zeros |
NaN (Not a number) | 0 | all ones | not all zeros |
Table 7-5: Special floating point values
Four floating point run-time libraries are delivered for every memory model:
By specifying the -fptrap option to the control program cctri, the trapping type floating point library is linked into your application. By specifying the -FPU option to the control program cctri, a floating point library with single precision FPU instructions is linked into your application. If these options are not specified, the floating point library without trapping mechanism and without FPU instructions is used.
In EDE you can specify to use the trapping type floating point library as follows: Select the Project | Linker/Locator Options... menu and enable the Use trapping floating point library check box in the Linker tab.
In the IEEE-754 standard a trap handler is defined, which is invoked on (specified) exceptional events, passing along much information about the event. To install your own trap handler, use the library call _fp_install_trap_handler. When installing your own exception handler, you must select on which types of exceptions you want to have your handler invoked, using the function call _fp_set_exception_mask. See below for more details on the floating point library exception handling function interface.
In ANSI-C the regular approach of dealing with floating point exceptions is by installing a so-called signal handler by means of the ANSI-C library call signal. If such a handler is installed, floating point exceptions cause this handler to be invoked. To have the signal handler for the SIGFPE signal actually become operational with the provided floating point libraries, a (very) basic version of the IEEE-754 exception handler must be installed (see example below) which will raise the desired signal by means of the ANSI-C library function call raise. For this to be achieved, the function call _fp_install_trap_handler is present. When installing your own exception handler, you will have to select on which types of exceptions you want to receive a signal, using the function call _fp_set_exception_mask. See further below for more details on the floating point library exception handling function interface.
There is no way to specify any information about the context or nature of the exception to the signal handler. Just that a floating point exception occurred can be detected. See therefor the IEEE-754 trap handler discussion above if you want more control over floating point results.
Example:
#include <float.h> #include <signal.h> static void pass_fp_exception_to_signal( _fp_exception_info_t *info ) { info; /* suppress parameter not used warning */ /* cause SIGFPE signal to be raised */ raise( SIGFPE ); /* * now continue the program * with the unaltered result */ }
For purposes of dealing with floating point arithmetic exceptions, the following library calls are available:
#include <float.h> int _fp_get_exception_mask( void ); void _fp_set_exception_mask( int );
A pair of functions to get or set the mask which controls which type of floating point arithmetic exceptions are either ignored or passed on to the trap handler. The types of possible exception flag bits are defined as:
EFINVOP EFDIVZ EFOVFL EFUNFL EFINEXCT
while,
EFALL
is the OR of all possible flags. See below for an explanation of each flag.
#include <float.h> int _fp_get_exception_status( void ); void _fp_set_exception_status( int );
A pair of functions for examining or presetting the status word containing the accumulation of all floating point exception types which occurred so far. See the possible exception type flags above.
#include <float.h> void _fp_install_trap_handler( void (*) (_fp_exception_info_t * ) );
This function call expects a pointer to a function, which in turn expects a pointer to a structure of type _fp_exception_info_t. The members of _fp_exception_info_t are:
exception
EFINVOP EFDIVZ EFOVFL EFUNFL EFINEXCT
operation
_OP_ADDITION _OP_SUBTRACTION _OP_COMPARISON _OP_EQUALITY _OP_LESS_THAN _OP_LARGER_THAN _OP_MULTIPLICATION _OP_DIVISION _OP_CONVERSION
source_format destination_format
_TYPE_SIGNED_CHARACTER _TYPE_UNSIGNED_CHARACTER _TYPE_SIGNED_SHORT_INTEGER _TYPE_UNSIGNED_SHORT_INTEGER _TYPE_SIGNED_INTEGER _TYPE_UNSIGNED_INTEGER _TYPE_SIGNED_LONG_INTEGER _TYPE_UNSIGNED_LONG_INTEGER _TYPE_FLOAT _TYPE_DOUBLE
operand1 /* left side of binary or */ /* right side of unary */ operand2 /* right side for binary */ result
typedef union _fp_value_union_t { char c; unsigned char uc; short s; unsigned short us; int i; unsigned int ui; long l; unsigned long ul; float f; #if ! _SINGLE_FP double d; #endif } _fp_value_union_t;
The member d is not present when specifying the -F
option to the C compiler.
The following table lists all the exception code flags, the corresponding error description and result:
Error Description | Exception Flag | Default Result with Trapping |
Invalid Operation | EFINVOP | NaN |
Division by zero | EFDIVZ | +INF or -INF |
Overflow | EFOVFL | +INF or -INF |
Underflow | EFUNFL | zero |
Inexact | EFINEXT | undefined |
INF Infinite which is the largest absolute floating point number, which is always: -INF < every finite number < +INF NAN Not a Number, a symbolic entity encoded in floating point format. |
Table 7-6: Exception Type Flag Codes
To ensure all exception types are specified, you can specify EFALL to a function, which is the binary OR of all above enlisted flags.