<article>
<title>cc65 Users Guide
-<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
-<date>2015-05-26
+<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
+<url url="mailto:gregdk@users.sf.net" name="Greg King">
+<date>2016-04-22
<abstract>
cc65 is a C compiler for 6502 targets. It supports several 6502 based home
<!-- Begin the document -->
-
<sect>Overview<p>
cc65 was originally a C compiler for the Atari 8-bit machines written by
that you must not mix pointers to those functions with pointers to
user-written, cdecl functions (the calling conventions are incompatible).
<p>
-<item> The <tt/volatile/ keyword doesn't have an effect. This is not as bad
+<item> The <tt/volatile/ keyword has almost no effect. That is not as bad
as it sounds, since the 6502 has so few registers that it isn't
possible to keep values in registers anyway.
<p>
file. The syntax is
<tscreen><verb>
- asm (<string literal>[, optional parameters]) ;
+ asm [optional volatile] (<string literal>[, optional parameters]) ;
</verb></tscreen>
or
<tscreen><verb>
- __asm__ (<string literal>[, optional parameters]) ;
+ __asm__ [optional volatile] (<string literal>[, optional parameters]) ;
</verb></tscreen>
- The first form is in the user namespace and is disabled if the <tt/-A/
+ The first form is in the user namespace; and, is disabled if the <tt/-A/
switch is given.
There is a whole section covering inline assembler statements,
<p>
+
<sect>Predefined macros<p>
The compiler defines several macros at startup:
syntax is
<tscreen><verb>
- asm (<string literal>[, optional parameters]) ;
+ asm [optional volatile] (<string literal>[, optional parameters]) ;
</verb></tscreen>
or
<tscreen><verb>
- __asm__ (<string literal>[, optional parameters]) ;
+ __asm__ [optional volatile] (<string literal>[, optional parameters]) ;
</verb></tscreen>
<p>
-The first form is in the user namespace and is disabled by <tt><ref
+The first form is in the user namespace; and, is disabled by <tt><ref
id="option--standard" name="--standard"></tt> if the argument is not <tt/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 <tt/void/.
+The <tt/asm/ statement can be used only inside a function. Please note that
+the result of an inline assembler expression is always of type <tt/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 <tt/.import/, <tt/.byte/ and so on) are <em/not/ allowed,
+The contents of the string literal are preparsed by the compiler; and, inserted
+into the generated assembly output, so that it can be processed further by
+the backend -- and, especially the optimizer. For that reason, the compiler does
+allow only regular 6502 opcodes to be used with the inline assembler. Pseudo
+instructions (like <tt/.import/, <tt/.byte/, and so on) are <em/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.
+code) would accept them. The built-in 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.
+compiler. There currently is no way to protect an inline assembler statement
+-- alone -- from being moved or removed completely by the optimizer. If in
+doubt, check the generated assembler output; or, disable optimizations (for
+that function).
+
+As a shortcut, you can put the <tt/volatile/ qualifier in your <tt/asm/
+statements. It will disable optimization for the functions in which those
+<tt/asm volatile/ statements sit. The effect is the same as though you put
+</#pragma optimize(push, off)/ above those functions, and </#pragma
+optimize(pop)/ below those functions.
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.
+the format specifier, before passing the assembly code line to the backend.
<itemize>
<item><tt/%b/ - Numerical 8-bit value
<item><tt/%%/ - The % sign itself
</itemize><p>
-Using these format specifiers, you can access C <tt/#defines/, variables or
+Using those format specifiers, you can access C <tt/#defines/, variables, or
similar stuff from the inline assembler. For example, to load the value of
-a C <tt/#define/ into the Y register, one would use
+a C <tt/#define/ into the Y index register, one would use
<tscreen><verb>
- #define OFFS 23
- __asm__ ("ldy #%b", OFFS);
+ #define OFFS 23
+ __asm__ ("ldy #%b", OFFS);
</verb></tscreen>
Or, to access a struct member of a static variable:
<tscreen><verb>
- 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);
+ 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);
</verb></tscreen>
<p>
The next example shows how to use global variables to exchange data between C
-an assembler and how to handle assembler jumps:
+and assembler; and, how to handle assembler jumps:
<tscreen><verb>
- unsigned char globalSubA, globalSubB, globalSubResult;
+ static unsigned char globalSubA, globalSubB, globalSubResult;
/* return a-b, return 255 if b>a */
unsigned char sub (unsigned char a, unsigned char b)
</verb></tscreen>
<p>
-Arrays can also be accessed:
+Arrays also can be accessed:
<tscreen><verb>
- unsigned char globalSquareTable[] = {
+ static const unsigned char globalSquareTable[] = {
0, 1, 4, 9, 16, 25, 36, 49, 64, 81,
100, 121, 144, 169, 196, 225
};
- unsigned char globalSquareA, globalSquareResult;
+ static unsigned char globalSquareA, globalSquareResult;
/* return a*a for a<16, else 255 */
unsigned char square (unsigned char a)
{
- if (a>15){
+ if (a > 15) {
return 255;
}
globalSquareA = a;
<p>
Note: Do not embed the assembler labels that are used as names of global
-variables or functions into your asm statements. Code like this
+variables or functions into your <tt/asm/ statements. Code such as this:
<tscreen><verb>
int foo;
- int bar () { return 1; }
- __asm__ ("lda _foo"); /* DON'T DO THAT! */
+ int bar (void) { return 1; }
+ ...
+ __asm__ ("lda _foo"); /* DON'T DO THAT! */
...
__asm__ ("jsr _bar"); /* DON'T DO THAT EITHER! */
</verb></tscreen>
<p>
-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:
+might stop working if the way that the compiler generates those names is changed in
+a future version. Instead, use the format specifiers from the table above:
<tscreen><verb>
- __asm__ ("lda %v", foo); /* OK */
+ __asm__ ("lda %v", foo); /* OK */
...
__asm__ ("jsr %v", bar); /* OK */
</verb></tscreen>
<p>
+
<sect>Implementation-defined behavior<p>
This section describes the behavior of cc65 when the standard describes the
</enum>
</article>
-