1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 19:29:37 +00:00

Added the optional C keyword "volatile" to the __asm__ statement grammar.

It prevents the statement's Assembly code from being optimized (e.g., moved or removed).  Optimization is disabled for that statement's entire function (other functions aren't affected).
This commit is contained in:
Greg King 2016-04-22 11:33:52 -04:00
parent 62c2177599
commit 2c7ccca210
2 changed files with 68 additions and 50 deletions

View File

@ -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 (&lt;string literal&gt;[, optional parameters]) ; asm [optional volatile] (&lt;string literal&gt;[, optional parameters]) ;
</verb></tscreen> </verb></tscreen>
or or
<tscreen><verb> <tscreen><verb>
__asm__ (&lt;string literal&gt;[, optional parameters]) ; __asm__ [optional volatile] (&lt;string literal&gt;[, 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 (&lt;string literal&gt;[, optional parameters]) ; asm [optional volatile] (&lt;string literal&gt;[, optional parameters]) ;
</verb></tscreen> </verb></tscreen>
or or
<tscreen><verb> <tscreen><verb>
__asm__ (&lt;string literal&gt;[, optional parameters]) ; __asm__ [optional volatile] (&lt;string literal&gt;[, 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,9 +1275,9 @@ 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
@ -1292,10 +1298,10 @@ Or, to access a struct member of a static variable:
</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,14 +1320,14 @@ 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)
@ -1339,19 +1345,20 @@ 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 */
@ -1361,6 +1368,7 @@ a future version. Instead use the format specifiers from the table above:
<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>

View File

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