Merge pull request #285 from greg-king5/asm-volatile
Add the C keyword "volatile" to the __asm__ statement grammar.
This commit is contained in:
107
doc/cc65.sgml
107
doc/cc65.sgml
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
<article>
|
<article>
|
||||||
<title>cc65 Users Guide
|
<title>cc65 Users Guide
|
||||||
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
|
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
|
||||||
<date>2015-05-26
|
<url url="mailto:gregdk@users.sf.net" name="Greg King">
|
||||||
|
<date>2016-04-22
|
||||||
|
|
||||||
<abstract>
|
<abstract>
|
||||||
cc65 is a C compiler for 6502 targets. It supports several 6502 based home
|
cc65 is a C compiler for 6502 targets. It supports several 6502 based home
|
||||||
@@ -15,7 +16,6 @@ computers like the Commodore and Atari machines, but it is easily retargetable.
|
|||||||
|
|
||||||
<!-- Begin the document -->
|
<!-- Begin the document -->
|
||||||
|
|
||||||
|
|
||||||
<sect>Overview<p>
|
<sect>Overview<p>
|
||||||
|
|
||||||
cc65 was originally a C compiler for the Atari 8-bit machines written by
|
cc65 was originally a C compiler for the Atari 8-bit machines written by
|
||||||
@@ -564,7 +564,7 @@ and the one defined by the ISO standard:
|
|||||||
that you must not mix pointers to those functions with pointers to
|
that you must not mix pointers to those functions with pointers to
|
||||||
user-written, cdecl functions (the calling conventions are incompatible).
|
user-written, cdecl functions (the calling conventions are incompatible).
|
||||||
<p>
|
<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
|
as it sounds, since the 6502 has so few registers that it isn't
|
||||||
possible to keep values in registers anyway.
|
possible to keep values in registers anyway.
|
||||||
<p>
|
<p>
|
||||||
@@ -586,14 +586,14 @@ This cc65 version has some extensions to the ISO C standard.
|
|||||||
file. The syntax is
|
file. The syntax is
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
asm (<string literal>[, optional parameters]) ;
|
asm [optional volatile] (<string literal>[, optional parameters]) ;
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
or
|
or
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
__asm__ (<string literal>[, optional parameters]) ;
|
__asm__ [optional volatile] (<string literal>[, optional parameters]) ;
|
||||||
</verb></tscreen>
|
</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.
|
switch is given.
|
||||||
|
|
||||||
There is a whole section covering inline assembler statements,
|
There is a whole section covering inline assembler statements,
|
||||||
@@ -735,6 +735,7 @@ This cc65 version has some extensions to the ISO C standard.
|
|||||||
<p>
|
<p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<sect>Predefined macros<p>
|
<sect>Predefined macros<p>
|
||||||
|
|
||||||
The compiler defines several macros at startup:
|
The compiler defines several macros at startup:
|
||||||
@@ -1224,39 +1225,44 @@ The compiler allows to insert assembler statements into the output file. The
|
|||||||
syntax is
|
syntax is
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
asm (<string literal>[, optional parameters]) ;
|
asm [optional volatile] (<string literal>[, optional parameters]) ;
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
or
|
or
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
__asm__ (<string literal>[, optional parameters]) ;
|
__asm__ [optional volatile] (<string literal>[, optional parameters]) ;
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<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/.
|
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
|
The <tt/asm/ statement can be used only inside a function. Please note that
|
||||||
inline assembler statement is a primary expression, so it may also be used as
|
the result of an inline assembler expression is always of type <tt/void/.
|
||||||
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 contents of the string literal are preparsed by the compiler and inserted
|
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
|
into the generated assembly output, so that it can be processed further by
|
||||||
the backend and especially the optimizer. For this reason, the compiler does
|
the backend -- and, especially the optimizer. For that reason, the compiler does
|
||||||
only allow regular 6502 opcodes to be used with the inline assembler. Pseudo
|
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,
|
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
|
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
|
code) would accept them. The built-in inline assembler is not a replacement for
|
||||||
the full blown macro assembler which comes with the compiler.
|
the full-blown macro assembler which comes with the compiler.
|
||||||
|
|
||||||
Note: Inline assembler statements are subject to all optimizations done by the
|
Note: Inline assembler statements are subject to all optimizations done by the
|
||||||
compiler. There is currently no way to protect an inline assembler statement
|
compiler. There currently is no way to protect an inline assembler statement
|
||||||
from being moved or removed completely by the optimizer. If in doubt, check
|
-- alone -- from being moved or removed completely by the optimizer. If in
|
||||||
the generated assembler output, or disable optimizations.
|
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
|
The string literal may contain format specifiers from the following list. For
|
||||||
each format specifier, an argument is expected which is inserted instead of
|
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>
|
<itemize>
|
||||||
<item><tt/%b/ - Numerical 8-bit value
|
<item><tt/%b/ - Numerical 8-bit value
|
||||||
@@ -1269,33 +1275,33 @@ the format specifier before passing the assembly code line to the backend.
|
|||||||
<item><tt/%%/ - The % sign itself
|
<item><tt/%%/ - The % sign itself
|
||||||
</itemize><p>
|
</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
|
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>
|
<tscreen><verb>
|
||||||
#define OFFS 23
|
#define OFFS 23
|
||||||
__asm__ ("ldy #%b", OFFS);
|
__asm__ ("ldy #%b", OFFS);
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
Or, to access a struct member of a static variable:
|
Or, to access a struct member of a static variable:
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char x;
|
unsigned char x;
|
||||||
unsigned char y;
|
unsigned char y;
|
||||||
unsigned char color;
|
unsigned char color;
|
||||||
} pixel_t;
|
} pixel_t;
|
||||||
static pixel_t pixel;
|
static pixel_t pixel;
|
||||||
__asm__ ("ldy #%b", offsetof(pixel_t, color));
|
__asm__ ("ldy #%b", offsetof(pixel_t, color));
|
||||||
__asm__ ("lda %v,y", pixel);
|
__asm__ ("lda %v,y", pixel);
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
The next example shows how to use global variables to exchange data between C
|
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>
|
<tscreen><verb>
|
||||||
unsigned char globalSubA, globalSubB, globalSubResult;
|
static unsigned char globalSubA, globalSubB, globalSubResult;
|
||||||
|
|
||||||
/* return a-b, return 255 if b>a */
|
/* return a-b, return 255 if b>a */
|
||||||
unsigned char sub (unsigned char a, unsigned char b)
|
unsigned char sub (unsigned char a, unsigned char b)
|
||||||
@@ -1314,19 +1320,19 @@ an assembler and how to handle assembler jumps:
|
|||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
Arrays can also be accessed:
|
Arrays also can be accessed:
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
unsigned char globalSquareTable[] = {
|
static const unsigned char globalSquareTable[] = {
|
||||||
0, 1, 4, 9, 16, 25, 36, 49, 64, 81,
|
0, 1, 4, 9, 16, 25, 36, 49, 64, 81,
|
||||||
100, 121, 144, 169, 196, 225
|
100, 121, 144, 169, 196, 225
|
||||||
};
|
};
|
||||||
unsigned char globalSquareA, globalSquareResult;
|
static unsigned char globalSquareA, globalSquareResult;
|
||||||
|
|
||||||
/* return a*a for a<16, else 255 */
|
/* return a*a for a<16, else 255 */
|
||||||
unsigned char square (unsigned char a)
|
unsigned char square (unsigned char a)
|
||||||
{
|
{
|
||||||
if (a>15){
|
if (a > 15) {
|
||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
globalSquareA = a;
|
globalSquareA = a;
|
||||||
@@ -1339,28 +1345,30 @@ Arrays can also be accessed:
|
|||||||
<p>
|
<p>
|
||||||
|
|
||||||
Note: Do not embed the assembler labels that are used as names of global
|
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>
|
<tscreen><verb>
|
||||||
int foo;
|
int foo;
|
||||||
int bar () { return 1; }
|
int bar (void) { return 1; }
|
||||||
__asm__ ("lda _foo"); /* DON'T DO THAT! */
|
...
|
||||||
|
__asm__ ("lda _foo"); /* DON'T DO THAT! */
|
||||||
...
|
...
|
||||||
__asm__ ("jsr _bar"); /* DON'T DO THAT EITHER! */
|
__asm__ ("jsr _bar"); /* DON'T DO THAT EITHER! */
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
may stop working if the way, the compiler generates these names is changed in
|
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:
|
a future version. Instead, use the format specifiers from the table above:
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
__asm__ ("lda %v", foo); /* OK */
|
__asm__ ("lda %v", foo); /* OK */
|
||||||
...
|
...
|
||||||
__asm__ ("jsr %v", bar); /* OK */
|
__asm__ ("jsr %v", bar); /* OK */
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<sect>Implementation-defined behavior<p>
|
<sect>Implementation-defined behavior<p>
|
||||||
|
|
||||||
This section describes the behavior of cc65 when the standard describes the
|
This section describes the behavior of cc65 when the standard describes the
|
||||||
@@ -1434,4 +1442,3 @@ freely, subject to the following restrictions:
|
|||||||
</enum>
|
</enum>
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,14 @@
|
|||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "asmlabel.h"
|
#include "asmlabel.h"
|
||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
|
#include "codeseg.h"
|
||||||
#include "datatype.h"
|
#include "datatype.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
|
#include "segments.h"
|
||||||
#include "stackptr.h"
|
#include "stackptr.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "asmstmt.h"
|
#include "asmstmt.h"
|
||||||
@@ -422,6 +424,15 @@ void AsmStatement (void)
|
|||||||
/* Skip the ASM */
|
/* Skip the ASM */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
|
/* An optional volatile qualifier disables optimization for
|
||||||
|
** the entire function [same as #pragma optimize(push, off)].
|
||||||
|
*/
|
||||||
|
if (CurTok.Tok == TOK_VOLATILE) {
|
||||||
|
/* Don't optimize the Current code Segment */
|
||||||
|
CS->Code->Optimize = 0;
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Need left parenthesis */
|
/* Need left parenthesis */
|
||||||
if (!ConsumeLParen ()) {
|
if (!ConsumeLParen ()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user