Next Previous Contents

## 9. Inline assembler

The compiler allows to insert assembler statements into the output file. The syntax is

> `

>             asm (<string literal>[, optional parameters]) ;

> `

or

> `

>             __asm__ (<string literal>[, optional parameters]) ;

> `

The first form is in the user namespace and is disabled by `--standard` if the argument is not `cc65`.

The asm statement may be used inside a function and on global file level. An inline assembler statement is a primary expression, so it may also be used as part of an expression. Please note however that the result of an expression containing just an inline assembler statement is always of type `void`.

The contents of the string literal are preparsed by the compiler and inserted into the generated assembly output, so that the can be further processed by the backend and especially the optimizer. For this reason, the compiler does only allow regular 6502 opcodes to be used with the inline assembler. Pseudo instructions (like `.import`, `.byte` and so on) are not allowed, even if the ca65 assembler (which is used to translate the generated assembler code) would accept them. The builtin inline assembler is not a replacement for the full blown macro assembler which comes with the compiler.

Note: Inline assembler statements are subject to all optimizations done by the compiler. There is currently no way to protect an inline assembler statement from being moved or removed completely by the optimizer. If in doubt, check the generated assembler output, or disable optimizations.

The string literal may contain format specifiers from the following list. For each format specifier, an argument is expected which is inserted instead of the format specifier before passing the assembly code line to the backend.

- `%b` - Numerical 8-bit value
- `%w` - Numerical 16-bit value
- `%l` - Numerical 32-bit value
- `%v` - Assembler name of a (global) variable or function
- `%o` - Stack offset of a (local) variable
- `%g` - Assembler name of a C label
- `%s` - The argument is converted to a string
- `%%` - The % sign itself

Using these format specifiers, you can access C `#defines`, variables or similar stuff from the inline assembler. For example, to load the value of a C `#define` into the Y register, one would use

> `

>             #define OFFS  23
>             __asm__ ("ldy #%b", OFFS);

> `

Or, to access a struct member of a static variable:

> `

>             typedef struct {
>                 unsigned char x;
>                 unsigned char y;
>                 unsigned char color;
>             } pixel_t;
>             static pixel_t pixel;
>             __asm__ ("ldy #%b", offsetof(pixel_t, color));
>             __asm__ ("lda %v,y", pixel);

> `

Note: Do not embed the assembler labels that are used as names of global variables or functions into your asm statements. Code like this

> `

>             int foo;
>             int bar () { return 1; }
>             __asm__ ("lda _foo");           /* DON'T DO THAT! */
>             ...
>             __asm__ ("jsr _bar");           /* DON'T DO THAT EITHER! */

> `

may stop working if the way, the compiler generates these names is changed in a future version. Instead use the format specifiers from the table above:

> `

>             __asm__ ("lda %v", foo);        /* OK */
>             ...
>             __asm__ ("jsr %v", bar);        /* OK */

> `

Next Previous Contents