◄ Back to index

# GTC Extensions

GTC supports a number of extensions, designed to take advantage of the TI platform, or simply to maintain compatibility with existing programs.

# GNU extensions

## Statements and Declarations in Expressions

See Statements and Declarations in Expressions.

## Referring to a Type with typeof

See Referring to a Type with typeof

## Generalized Lvalues

See Generalized Lvalues.

Note however that weird constructs like `(a,b)+=5` are rejected by GTC -- commas are not considered legal lvalues.

## Conditionals with Omitted Operands

See Conditionals with Omitted Operands.

## Binary Numbers

See Binary Numbers.

## Structures With No Members

See Structures With No Members.

## Arrays of Length Zero

See Arrays of Length Zero.

## Macros with a Variable Number of Arguments

See Macros with a Variable Number of Arguments.

## Arithmetic on void and Function Pointers

See Arithmetic on void and Function Pointers.

## Non-Constant Initializers

See Non-Constant Initializers.

## Compound Literals (Cast Constructors)

See Compound Literals (Cast Constructors). There is some difference in the handling of static storage duration though, see Differences between GTC and TIGCC.

## Designated Initializers

See Designated Initializers, but in GTC this only works for array types.

## Case Ranges

See Case Ranges.

## Specifying Attributes of Functions

See Specifying Attributes of Functions, however not all of the specifiers are meaningful in GTC.

## C++ Style Comments

See C++ Style Comments.

## Dollar Signs in Identifier Names

See Dollar Signs in Identifier Names.

## Escape Character in Constants

See Escape Character in Constants.

## Alternate Keywords

See Alternate Keywords.

## `__builtin_constant_p`

See __builtin_constant_p.

## Mixed Declarations and Code

See Mixed Declarations and Code.

## Unnamed struct/union Fields within structs/unions

See Unnamed struct/union Fields within structs/unions.

# GTC-specific extensions

## `incbin` directive

It is sometimes convenient to include binary files directly into your program, for example when using sprites. The `incbin` directives allows you to do just that, without having to convert your data to a decimal or hexadecimal header (which can be memory-consuming on a TI).

### Using `incbin` to declare a C array

You can use `incbin` to initialize the contents of a C array:

    // The following declares a sprite using normal C initializers
    short sprite1[] = {
        0xFFFF, 0x8008, 0x8008, 0xFFFF,
        0xFF00, 0x8800, 0x8800, 0x8800,
        0x00FF, 0x0088, 0x0088, 0x0088,
        0xFFFF, 0x8008, 0x8008, 0xFFFF,
    };

    // The following declares a sprite using incbin,
    // reading the contents from the file sprite.bin
    short sprite2[] = incbin "sprite.bin";

The first declaration creates an array of 16 shorts containing the hexadecimal numbers provided. The second declaration creates an array of 16 shorts whose representation in memory will be the same as `sprite.bin`.

Note that for the sake of portability, `import_binary` can be a useful alternative, although there are several caveats: you will have to manually declare the size of the array if `sizeof` is to be used, and you cannot use it to declare a static array inside a function.

### Using `incbin` within an `asm{}` statement

Like in a68k, you can also use `incbin` inside an `asm{}` statement to insert binary data.

    asm {
    // Insert the values 1,2,3,4 after label1
    label1:
        dc.w 1,2
        dc.w 3,4
    // Insert the content of sprite.bin after label2
    label2:
        incbin "sprite.bin"
    };

## `asm{}` statement

GTC allows you to program in assembly, with a syntax very close to that of a68k. In fact, it is powerful enough to write full assembly programs using only GTC!

### Inserting an `asm{}` statement in the code

#### Global `asm{}` statements

You can insert assembly code at the global level, for example:

    asm {
    add_3_and_multiply_by_5:
        add.w #3,d0
        mulu #5,d0
        rts
    };

This creates an assembly function named `add_3_and_multiply_by_5` that takes an input argument in `d0`, adds 3 to it, multiplies it by 5, and returns the result in `d0`.

To use such a function in C code, you need to prototype it:

    short add_3_and_multiply_by_5(short x);

This tells GTC that your function takes a `short` named `x` as an input, and outputs a `short`. Because of the calling convention, `x` will be placed in `d0`: see default calling convention for more information on where input arguments to assembly functions will be located.

#### Inline `asm{}` statements

You can also insert assembly code within a function. This has the advantage over global assembly functions to eliminate the overhead associated with a function call.

    void do_something(char *command) {
        if (!strcmp(command,"off"))
    	asm { trap #4 };
        else
    	printf("unknown command!\n");
    }

This functions turns off the calculator when `command` is `"off"`, by calling `trap #4`.

### Structure of an `asm{}` statement

An `asm{}` statement is comprised of a set of declarations between the outer `{` and `}` braces. A declaration can be:

- a 68000 instruction, e.g. `moveq #123,d0`
- a label definition, e.g. `my_function:`
- a data declaration, e.g. `dc.w 123,456,789` or `incbin "data.bin"`

You must separate different declarations either:

- by putting them on separate lines
- by simply concatenating them if the first is a label
- by separating them with a semicolon (`;`) -- however you should absolutely avoid doing this outside `#define`, as the behaviour may change some day

### `asm{}` interpretation rules

The behaviour of GTC is indeed very close to that of `a68k`. Like `a68k`, GTC tries to optimize instructions when it is possible, for example `add.w #3,d0` will be optimized to `addq.w #3,d0`. Like `a68k`, you don't need to add a `:` after label names: however, while with `a68k` you can only do so if the label is placed on the first char of the line, with GTC you can do so any time as long as the label does not correspond to an assembly instruction.

The most notable difference is perhaps that, where `a68k` uses specific commands like `equ` and `equr` to define macros, GTC simply uses the C preprocessor. This is very powerful, as it allows you to define constants just once and reuse them in C code. You can also use normal C conditionals like `#if` or `#ifdef`, making conditional compilation easier. You can also interface your code with C much more easily, for example you have access to the `sizeof` operator:

    int table[] = { 1,2,3,4 };

    asm {
    negate_table:
        lea table,a0
        moveq #sizeof(table)/2-1,d0
    \loop
        neg.w (a0)+
        dbra d0,\loop
        rts
    };

After execution of `negate_table`, `table` will be equal to `{ -1,-2,-3,-4 }`.

Note the `\` in `\loop`: this means that the label is local. However, this notion differs slightly from that of `a68k`: while the label is only valid between the surrounding two global labels in `a68k`, the label is valid throughout the `asm{}` statement in GTC. It is often more convenient, as this example shows:

    asm {
    \return_with_error
        moveq #-1,d0
        rts
    my_function:
        addq.w #5,d0
        bmi.s \return_with_error
        tst.w d1
        bmi.s \return_with_error
        ... very long code (longer than 128 bytes) ...
        rts
    };

In this example, `\return_with_error` is placed before `my_function` because it allows the branches to `\return_with_error` to be short branches (`bmi.s`, 2 bytes) rather than long branches (`bmi.w`, 4 bytes). If GTC followed the rules of `a68k`, then it would require `\return_with_error` to be a global, which can be inconvenient if you have lots of these. Instead, it allows you to structurally divide your program in logical `asm{}` blocks.

### Extra features of `asm{}` statements

Because `asm{}` statements rely on the C compiler architecture of GTC, there are lots of nice features, for example:

    #define USE_KERNEL
    #include <std.h>
    asm {
    _main:
        pea "Hello, world!"(pc)
        jsr ST_helpMsg
        addq.l #4,a7
        rts
    };

What's most interesting in all this is that the C library required no modification whatsoever to allow using ROM calls in such a way: ROM calls are not defined twice, and there isn't even a conditional statement acting differently inside `asm{}` code and inside C code! This is possible because the assembler was able to interpret the C construct corresponding to `ST_helpMsg`.

### `asm{}` special operator: `__c__`

This is an operator reserved to operands of instructions in `asm{}` statements.

The reason why this operator exists is simple: assembly and C each have different arithmetic rules. For example, if you have the following code:

    int table[] = { 1,2,3,4 };

then, while in C `table+2` will designate the address of `table[2]` (the number `3`), in assembly `table+2` will designate the address of `table[0]` plus 2 bytes, which happens to be the address of `table[1]`.

So when you write:

    asm {
    load_address:
        lea table+2(pc),a0
        rts
    };

then, as you would expect from assembly code, `table+2` corresponds to the address given by assembly arithmetic rules.

This works with `#define` statements too:

    asm {
    load_address:
    #define my_item table+2
        lea my_item(pc),a0
        rts
    };

But GTC allows you to do much more: you may want to access information that requires access to the full typing system of C, not just the addresses of different objects. The way you can access this typing system is by the `__c__` operator: if you write

    asm {
    load_address:
        lea __c__(table+2)(pc),a0
        rts
    };

then `table+2` will not be interpreted according to assembly rules, but according to C rules: that is, `__c__(table+2)` is the adress of `table[2]`.

GTC goes one step further, by automatically enclosing `#define`s written as part of C code in the `__c__` operator:

    int table[] = { 1,2,3,4 };
    #define third_item &table[2]  // note: table+2 would give the same results

    int *c_load_address() {
        return third_item;
    }

    asm {
    load_address:
        lea third_item(pc),a0
        rts
    };

Here both `c_load_address()` and `load_address()` do the same thing, without ever having to define `third_item` twice!

## `@@` prefix

The prefix `@@` can be prepended to any identifier to prevent it from being expanded by the preprocessor. For example, `@@MY_SYMBOL` will expand to `MY_SYMBOL` even if `MY_SYMBOL` has been `#define`d to expand to `0x1234`.

This is not very useful in normal C code, but it can be useful in conjunction with other GTC extensions, mainly `asm{}` statements and pre-compiled headers.