C Inline Assembly
Clang supports most of the standard GCC inline assembly syntax. There are a few notable exceptions:
- Unsupported Constraints:
o
,V
,<
,>
, andg
- Goto Labels are unsupported.
"General purpose registers" for the purposes of inline assembly are taken to be 8-bit (__rcxx
) or 16-bit (__rsxx
) imaginary registers, depending on the size of the operand.
The compiler also supports a few MOS-specific constraints:
a
: TheA
register.x
: TheX
register.y
: TheY
register.R
: One ofA
,X
, orY
.d
: EitherX
orY
.c
: TheC
flag.v
: TheV
flag.
These modifiers are case-sensitive, and violating constraint use in inline assembly can crash the compiler, so use with a high degree of caution.
The unique opcode syntax of the 6502 allows using these operands in unorthodox ways. For example, to issue a copy from a d
constrained operand to A
, you can use the following which will issue either txa
or tya
, depending on where the compiler places c
:
unsigned char c = 1;
__attribute__((leaf)) __asm__ volatile ("t%0a" : /* no output */ : /* input */ "d"(c) : /* clobbers */ "a");
Using GCC-style inline assembly has a lot of sharp edges and footguns, so beware. For a detailed guide on how to use this feature well, see: Frequently asked questions#Why is inline assembly behaving so strangely?
One more thing to note: the compiler tracks the contents of C and V (but not N and Z). Accordingly, if the inline assembly fragment can clobber C or V, they must be added to the clobber or output register list with e.g. "c"
, "v"
, or "p"
.
If you're writing a lot of assembly, note that mos-clang works well as a frontend to the MOS assembler. You can put your labels and assembly code in its own .s file, and compile it with something like:
mos-clang -c my-assembly-file.s