This chapter contains the following sections:
Introduction
Intrinsic Functions
Minimum and Maximum of (Short) Integers
Fractional Data Type Support
Packed Data Type Support
Interrupt Handling
Insert Single Assembly Instruction
Register Handling
Insert / Extract Bitfields and Bits
Miscellaneous Intrinsic Functions
The TASKING TriCore C compiler fully supports the ANSI C standard but adds possibilities to program the special functions of the TriCore.
This chapter contains complete overviews of the following C language extensions of the TASKING TriCore C compiler:
The TASKING TriCore C compiler ctc supports the following data types:
Type | Keyword |
Size (bit) | Align (bit) | Ranges |
Bit | __bit | 8 | 8 | 0 or 1 |
Boolean | _Bool | 8 | 8 | 0 or 1 |
Character | char signed char | 8 | 8 | -27 .. 27-1 |
unsigned char | 8 | 8 | 0 .. 28-1 | |
Integral | short signed short | 16 | 16 | -215 .. 215-1 |
unsigned short | 16 | 16 | 0 .. 216-1 | |
int signed int long signed long | 32 | 16 | -231 .. 231-1 | |
unsigned int unsigned long | 32 | 16 | 0 .. 232-1 | |
enum |
8 16 32 |
8 16 |
-27 .. 27-1 -215 .. 215-1 -231 .. 231-1 | |
long long
signed long long | 64 | 32 | -263 .. -263-1 | |
unsigned long long | 64 | 32 | 0 .. 264-1 | |
Pointer | pointer to data pointer to func | 32 | 32 | 0 .. 232-1 |
Floating Point | float | 32 | 16 |
-3.402e38 .. -1.175e-38 1.175e-38 .. 3.402e38 |
double long double | 64 | 32 |
-1.797e308 .. -2.225e-308 2.225e-308 .. 1.797e308 | |
Fract | __sfract | 16 | 16 | [-1, 1> |
__fract | 32 | 32 | [-1, 1> | |
Accum | __laccum | 64 | 64 | [-131072,131072> |
Packed | __packb signed __packb | 32 | 16 | 4x: -27 .. 27-1 |
unsigned __packb | 32 | 16 | 4x: 0 .. 28-1 | |
__packhw signed __packhw | 32 | 16 | 2x: -215 .. 215-1 | |
unsigned __packhw | 32 | 16 | 2x: 0 .. 216-1 |
Table 1-1: Data Types
The data object is located in a section that is addressable with a sign-extended 16-bit offset from address register A0, A1, A8 or A9 respectively.
With the __asm() keyword you can use assembly instructions in the C source and pass C variables as operands to the assembly code.
__asm( "instruction_template" [ : output_param_list [ : input_param_list [ : register_save_list]]] );
instruction_template Assembly instructions that may contain parameters from the input list or output list in the form: %parm_nr [.regnum]
%parm_nr[.regnum] Parameter number in the range 0 .. 9. With the optional .regnum you can access an individual register from a register pair or register quad. For example, with register pair d0/d1, .0 selects register d0.
output_param_list [[ "=[&]constraint_char"(C_expression)],...]
input_param_list [[ "constraint_char"(C_expression)],...]
& Says that an output operand is written to before the inputs are read, so this output must not be the same register as any input.
constraint _char Constraint character: the type of register to be used for the C_expression.
C_expression Any C expression. For output parameters it must be an lvalue, that is, something that is legal to have on the left side of an assignment.
register_save_list [["register_name"],...]
register_name Name of the register you want to reserve.
Constraint character | Type | Operand | Remark |
a | Address register | a0 .. a15 | |
d | Data register | d0 .. d15 | |
e | Data register pair | e0 .. e7 | |
m | Memory | variable | Stack or memory operand |
number | Type of operand it is associated with | same as %number | Indicates that %number and number are the same register. |
Table 1-2: Available input/output operand constraints
For more information on
__asm, see
section 3.6,
Using Assembly in the C Source, in Chapter TriCore C Language of the User's
Guide.
With the attribute __at() you can place an object at an absolute address.
int myvar __at(0x100);
If you have defined a 32-bits base variable (int, long) you can declare a single bit of that variable as a bit variable with the keyword __atbit(). The syntax is:
name is the name of an integer variable in which the bit is located. offset (range 0-31) is the bit-offset within the variable.
The TriCore C compiler supports the __circ keyword for circular buffers.
For more information see section
3.4.1,
Circular Buffers, in Chapter TriCore C Language of the User's Guide.
With keyword __near the declared data object will be located in the first 16 kB of a 256 MB block. These parts of memory are directly addressable with the absolute addressing mode.
With keyword __far the data object can be located anywhere in the indirect addressable memory region.
With the data type qualifiers __sfrbit16 and __sfrbit32 you can declare bit fields in special function registers. These keywords force 16-bit or 32-bit access.
For more information see section
3.4.2,
Declare an SFR Bit Field: __sfrbit16 and ___sfrbit32, in Chapter TriCore C Language of the User's Guide.
During the execution of an interrupt service routine or trap service routine, the system blocks the CPU from taking further interrupt requests. You can immediately re-enable the system to accept interrupt requests:
__interrupt(vector) __enable_ isr( void ) __trap(class) __enable_ tsr( void )
The function qualifier __bisr_() also re-enables the system to accept interrupt requests. In addition, the current CPU priority number (CCPN) in the interrupt control register is set:
__interrupt(vector) __bisr_(CCPN) isr( void ) __trap(class) __bisr_(CCPN) tsr( void )
For more information see section
3.9.2,
Interrupt and Trap Functions, in Chapter TriCore C Language of the User's Guide.
Functions are default called with a single word direct call. However, when you link the application and the target address appears to be out of reach (+/- 16 MB from the callg or jg instruction), the linker generates an error. In this case you can use the __indirect keyword to force the less efficient, two and a half word indirect call to the function:
int __indirect foo( void ) { ... }
You can use the inline qualifier to tell the compiler to inline the function body instead of calling the function. Use the __noinline qualifier to tell the compiler not to inline the function body.
inline int func1( void ) { // inline this function } __noinline int func2( void ) { // do not inline this function }
For more information see section
3.9.1,
Inlining Functions: inline, in Chapter TriCore C Language of the User's Guide.
You can use the qualifier __interrupt() to declare a function as an interrupt service routine.
void __interrupt(vector_number) isr(void) { ... }
The vector_number identifies the entry into the interrupt vector table (0..255). Unlike other interrupt systems, the priority number (PIPN) of the interrupt now being serviced by the CPU identifies the entry into the vector table.
When you define an interrupt service routine with the __interrupt_fast() qualifier, the interrupt handler is directly placed in the interrupt vector table, thereby eliminating the jump code.
For more information see section
3.9.2,
Interrupt and Trap Functions, in Chapter TriCore C Language of the User's Guide.
The definition of a trap service routine is similar to the definition of an interrupt service routine. Trap functions cannot accept arguments and do not return anything:
void __trap( class ) tsr( void ) { ... }
The argument class identifies the entry into the trap vector table. TriCore defines eight classes of trap functions. Each class has its own trap handler.
When you define a trap service routine with the __trap_fast() qualifier, the trap handler is directly placed in the trap vector table, thereby eliminating the jump code.
A special kind of trap service routine is the system call trap. With a system call the trap service routine of class 6 is called. For the system call trap, the trap identification number (TIN) is taken from the immediate constant specified with the function qualifier __syscallfunc():
__syscallfunc(TIN)
The TIN is a value in the range 0 and 255. You can only use __syscallfunc() in the function declaration. A function body is useless, because when you call the function declared with __syscallfunc(), a trap class 6 occurs which calls the corresponding trap service routine.
For more information see section
3.9.2,
Interrupt and Trap Functions, in Chapter TriCore C Language of the User's Guide.
The function qualifier __stackparm changes the standard calling convention of a function into a convention where all function arguments are passed via the stack, conforming a so called stack model. This qualifier is only needed for situations where you need to use an indirect call to a function for which you do not have a valid prototype.
void __stackparm stack_func ( int );
The TASKING TriCore C compiler recognizes intrinsic functions that serve the following purposes:
All intrinsic functions begin with a double underscore character (__). You can use intrinsic functions as if they were ordinary C functions.
The next table provides an overview of the intrinsic functions that return the minium or maximum of a signed integer, unsigned integer or short integer.
Intrinsic Function | Description |
int __min( int,int ) | Return minimum of two integers |
short __mins( short,short ) | Return minimum of two short integers |
unsigned int __minu( unsigned int, unsigned int ) | Return minimum of two unsigned integers |
int __max( int,int ) | Return maximum of two integers |
short __maxs( short,short ) | Return maximum of two short integers |
unsigned int __maxu( unsigned int, unsigned int ) | Return maximum of two unsigned integers |
Table 1-3: Intrinsic Functions for obtaining min/max values
The next table provides an overview of intrinsic functions to convert fractional values. Note that the TASKING TriCore C compiler fully supports the fractional type so normally you should not need these intrinsic functions (except for __mulfractlong). For compatibility reasons the TASKING TriCore C compiler does support these functions.
Intrinsic Function | Description |
long __mulfractlong( __fract,long ) | Integer part of __fract x long |
__sfract __round16( __fract ) | Convert __fract to __sfract |
__fract __getfract( __accum ) | Convert __accum to __fract |
short __clssf( __sfract ) | Count the consecutive number of bits that have the same value as bit 15 of an __sfract |
__sfract __shasfracts( __sfract,int ) | Left/right shift of an __sfract |
__fract __shafracts( __fract,int ) | Left/right shift of an __fract |
__laccum __shaaccum( __laccum,int ) | Left/right shift of an __laccum |
Table 1-4: Intrinsic Functions for Conversion of Fractional Values
The next table provides an overview of the intrinsic functions for initialization of packed data type.
Intrinsic Function | Description |
__packb __initpackbl( long ) | Initalize __packb with a long integer |
__packb __initpackb( int,int,int,int ) | Initalize __packb with four integers |
__packhw __initpackhwl( long ) | Initalize __packhw with a long integer |
__packhw __initpackhw( int,int ) | Initalize __packhw with two integers |
Table 1-5: Intrinsic Functions to Initialize Packed Data Types
The next table provides an overview of the intrinsic functions to extract a single byte or halfword from a __packb or __packhw data type.
Intrinsic Function | Description |
char __extractbyte1( __packb ) | Extract first byte from a __packb |
char __extractbyte2( __packb ) | Extract second byte from a __packb |
char __extractbyte3( __packb ) | Extract third byte from a __packb |
char __extractbyte4( __packb ) | Extract fourth byte from a __packb |
short __extracthw1( __packhw ) | Extract first short from a __packhw |
short __extracthw2( __packhw ) | Extract second short from a __packhw |
char __getbyte1( __packb * ) | Extract first byte from a __packb |
char __getbyte2( __packb * ) | Extract second byte from a __packb |
char __getbyte3( __packb * ) | Extract third byte from a __packb |
char __getbyte4( __packb * ) | Extract fourth byte from a __packb |
short __gethw1( __packhw * ) | Extract first integer from a __packhw |
short __gethw2( __packhw * ) | Extract short integer from a __packhw |
Table 1-6: Intrinsic Functions to Extract Values from Packed Data Types
The next table provides an overview of the intrinsic functions to insert a single byte or halfword into a __packb or __packhw data type.
Intrinsic Function | Description |
__packb __insertbyte1( __packb, char ) | Insert char into first byte of a __packb |
__packb __insertbyte2( __packb, char ) | Insert char into second byte of a __packb |
__packb __insertbyte3( __packb, char ) | Insert char into third byte of a __packb |
__packb __insertbyte4( __packb, char ) | Insert char into fourth byte of a __packb |
__packhw __inserthw1( __packhw, short ) | Insert short into first halfword of a __packhw |
__packhw __inserthw2( __packhw, short ) | Insert short into second halfword of a __packhw |
void __setbyte1( __packb *, char ) | Insert first byte into a __packb |
void __setbyte2( __packb *, char ) | Insert second byte into a __packb |
void __setbyte3( __packb *, char ) | Insert third byte into a __packb |
void __setbyte4( __packb *, char ) | Insert fourth byte into a __packb |
void __sethw1( __packhw *, short ) | Insert first integer into a __packhw |
void __sethw2( __packhw *, short ) | Insert short integer into a __packhw |
Table 1-7: Intrinsic Functions to Insert Values into Packed Data Types
The next table provides an overview of the intrinsic functions to combine the value of packed data types into a packed word. You can combine two __packb (2 x 4 bytes) into a long long or two __packhw (2 x 2 halfwords) into a long long.
The packed word is a double register that is represented by the additional datatype __packw. To access the values in a _packw variable, you can use a union data type: typedef double __packw.
These intrinsics are only supported for the TriCore2 (--is-tricore2).
Intrinsic Function | Description |
unsigned long long __transpose_byte( __packb,__packb ) | Combine two __packb |
unsigned long long __transpose_hword( __packhw,__packhw ) | Combine two __packhw |
Table 1-8: Intrinsic Functions to Combine Packed Data Types
The next table provides an overview of the intrinsic functions to calculate the absolute value of packed data type values.
Intrinsic Function | Description |
__packb __absb( __packb ) | Absolute value of __packb |
__packhw __absh( __packhw ) | Absolute value of __packhw |
__sat __packhw __abssh( __sat __packhw ) | Absolute value of __packhw using saturation |
Table 1-9: Intrinsic Functions to Calculate Absolute Values
The next table provides an overview of the intrinsic functions to calculate the minimum from two packed data type values.
Intrinsic Function | Description |
__packb __minb( __packb,__packb ) | Minimum of two __packb values |
unsigned __packb __minbu( unsigned __packb, unsigned __packb ) | Minimum of two unsigned __packb values |
__packhw __minh( __packhw,__packhw ) | Minimum of two __packhw values |
unsigned __packhw __minhu( unsigned __packhw, unsigned __packhw ) | Minimum of two unsigned __packhw values |
Table 1-10: Intrinsic Functions to Calculate Absolute Values
The next table provides an overview of the intrinsic functions to read or set interrupt handling:.
Intrinsic Function | Description |
void __enable ( void ) | Enable interrupts immediately at function entry |
void __disable ( void ) | Disable interrupts Only supported for TriCore1. |
int __disable_and_save ( void ) | Disable interrupts and return previous interrupt state (enabled or disabled). Only supported for TriCore2 (--is-tricore2). |
void __restore ( int ) | Restore interrupt state. Only supported for TriCore2 (--is-tricore2). |
void __bisr ( int ) | Set CPU priority number [0..512] and enable interrupts immediately at function entry |
void __sysc ( int ) | Call a system call function number |
Table 1-11: Intrinsic Functions for Interrupt Handling
The next table provides an overview of the intrinsic functions that you can use to insert a single assembly instruction.
You can also use inline assembly but these intrinsics provide a shorthand for frequently used assembly instructions.
See section 3.6
, Using Assembly in the C Source: __asm() of the User's Guide
Intrinsic Function | Description |
void __debug( void ) | Insert DEBUG instruction |
void __dsync( void ) | Insert DSYNC instruction |
void __isync( void ) | Insert ISYNC instruction |
void __svlcx( void ) | Insert SVLCX instruction |
void __rslcx( void ) | Insert RSLCX instruction |
void __nop( void ) | Insert NOP instruction |
Table 1-12: Intrinsic Functions for Inserting Assembly Instructions
The next table provides an overview of the intrinsic functions that you can use to acces control registers.
Intrinsic Function | Description |
int __mfcr( int ) | move contents of the addressed core SFR into a data register |
void __mtcr ( int,int ) | move contents of a data register (second int) to the addressed core SFR (first int) |
Table 1-13: Intrinsic Functions for Accessing Control Registers
The next table provides an overview of the intrinsic functions that operate on a register and return a value in another register.
Intrinsic Function | Description |
int __clz ( int ) | Count leading zeros in int |
int __clo ( int ) | Count leading ones in int |
int __cls ( int ) | Count number of redundant sign bits (all consecutive bits with the same value as bit 31) |
int __satb ( int ) | Return saturated byte |
int __satbu ( int ) | Return saturated unsigned byte |
int __sath ( int ) | Return saturated halfword |
int __sathu ( int ) | Return saturated unsigned halfword |
int __abs ( int ) | Return absolute value |
int __abss ( int ) | Return absolute value with saturation |
int __parity ( int ) | Return parity |
Table 1-14: Intrinsic Functions for Performing Register Value Operations
The next table provides an overview of the intrinsic functions to insert or extract a bit-field.
Intrinsic Function | Description | ||||||||
int __extr ( int value, int pos,int width ) |
Extract a bit-field (bit pos to bit pos+width) from value
unsigned int __extru ( int | value,int pos,int width )
Same as __extr() but return bit-field as unsigned integer |
int __insert ( int src,int | trg, int pos,int width )
Extract bit-field (bit pos to bit pos+width) from src
and insert it in trg. |
int _ins( int trg, int trgbit, | int src, int srcbit )
Return trg but replace trgbit by srcbit in src. |
int _insn(int trg, int trgbit, | int src, int srcbit )
Return trg but replace trgbit by
inverse of srcbit in src. | |
Table 1-15: Intrinsic Functions to Insert / Extract Bit-fields
With the next intrinsic function you can peform atomic Load-Modify-Store of a bit-field from an integer value. This function uses the IMASK and LDMST instruction. The intrinsic writes the number of bits of an integer value at a certain address location in memory with a bitoffset. The number of bits must be a constant value.
Intrinsic Function |
void __imaskldmst(int* address,int value,int bitoffset,int bits) |
Store a single bit
With the intrinsic macro __putbit() you can store a single bit atomicly in memory at a specified bit offset. The bit at offset 0 in value is stored at an address location in memory with a bitoffset.
This intrinsic is implemented as a macro definition which uses the _imaskldmst() intrinsic:
#define __putbit ( value, address, bitoffset ) __imaskldmst ( address, value, bitoffset, 1 )
Intrinsic Macro |
void __putbit( int value, int* address, int bitoffset ) |
Load a single bit
With the intrinsic macro __getbit() you can load a single bit from memory at a specified bit offset. A bit value is loaded from an address location in memory with a bitoffset and returned as an unsigned integer value.
This intrinsic is implemented as a macro definition which uses the __extru() intrinsic function:
#define _getbit ( address, bitoffset ) _extru ( *(address), bitoffset, 1 )
Intrinsic Macro |
unsigned integer __getbit( int* address, int bitoffset ) |
The next intrinsic multiplies two 32-bit numbers to an intermediate 64-bit result, and scales back the result to 32 bits. To scale back the result, 32 bits are extracted from the intermediate 64-bit result: bit 63-offset to bit 31-offset.
Intrinsic Function |
int __mulsc( int a, int b, int offset ) |
The next intrinsic exchanges the values of value and memory, but only those bits that are allowed by mask. Before the __swapmsk instruction is generated, the parameters value and mask are moved into a double register.
This intrinsic is only supported for the TriCore2 (--is-tricore2).
Intrinsic Function |
void __swapmsk ( int value, int mask, int * memory ) |
With the next intrinsic you can initialize a circular pointer with a dynamically allocated buffer at run-time.
Intrinsic Function |
__circ void * __initcirc( void * buf, unsigned short
bufsize, unsigned short byteindex ) |
See also Section 3.4.1
, Circular Buffers, in Chapter TriCore C Language of the User's Guide.
Pragmas are keywords in the C source that control the behavior of the compiler. Pragmas overrule compiler options and keywords. The syntax is:
#pragma name-of-pragma
The compiler recognizes the following pragmas, other pragmas are ignored.
Pragma name | Description |
align {n|restore} | Specifies object alignment |
clear noclear | Specifies 'clearing' of non-initialized static/public variables |
default_a0_size value | Threshold for '__a0' allocation |
default_near_size value | Threshold for '__near' allocation |
inline noinline smartinline | Specifies function inlining |
optimize flags endoptimize | Controls compiler optimizations |
pack {2|0} | Specifies packing of structures |
section type[=]"name " | Changes section names |
section code_init section data_overlay |
At startup copy code to RAM Allow overlaying data sections |
source nosource | Specifies which C source lines must be shown in assembly output |
switch {auto|jumptab| linear|lookup|restore} | Specifies switch statement |
Table 1-16: Pragmas
For more information see section
3.7,
Pragmas to Control the Compiler, in Chapter TriCore C Language of the User's Guide.
In addition to the predefined macros required by the ISO C standard, the TASKING TriCore C compiler supports the predefined macros as defined in Table 1-17. The macros are useful to make conditional C code.
Macro | Description |
__DOUBLE_FP__ | Defined when you do not use compiler option -F (Treat double as float) |
__SINGLE_FP__ | Defined when you use compiler option -F (Treat double as float) |
__FPU__ | Defined when you use compiler option --fpu-present (Use hardware floating point instructions) |
__CTC__ | Identifies the compiler. You can use this symbol to flag parts of the source which must be recognized by the ctc compiler only. It expands to the version number of the compiler. |
__TASKING__ | Identifies the compiler as the TASKING TriCore compiler. It expands to 1. |
__DSPC__ | Indicates conformation to the DSP-C standard. It expands to 1. |
__DSPC_VERSION__ | Expands to the decimal constant 200001L. |
Table 1-17: Predefined macros