C Inline Assembly

From llvm-mos

Clang supports most of the standard GCC inline assembly syntax. There are a few notable exceptions:

  • Unsupported Constraints: o, V, <, >, and g
  • Goto Labels are unsupported.

"General purpose registers" for the purposes of inline assembly are taken to be 8-bit or 16-bit imaginary registers, depending on the size of the operand.

The compiler also supports a few MOS-specific constraints:

  • a: The A register.
  • x: The X register.
  • y: The Y register.
  • R: One of A, X, or Y.
  • d: Either X or Y.
  • c: The C flag.
  • v: The V flag.

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;
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.

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