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:
parent
62c2177599
commit
2c7ccca210
107
doc/cc65.sgml
107
doc/cc65.sgml
@ -2,8 +2,9 @@
|
||||
|
||||
<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
|
||||
@ -15,7 +16,6 @@ computers like the Commodore and Atari machines, but it is easily retargetable.
|
||||
|
||||
<!-- Begin the document -->
|
||||
|
||||
|
||||
<sect>Overview<p>
|
||||
|
||||
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
|
||||
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>
|
||||
@ -586,14 +586,14 @@ This cc65 version has some extensions to the ISO C standard.
|
||||
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,
|
||||
@ -735,6 +735,7 @@ This cc65 version has some extensions to the ISO C standard.
|
||||
<p>
|
||||
|
||||
|
||||
|
||||
<sect>Predefined macros<p>
|
||||
|
||||
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
|
||||
|
||||
<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
|
||||
@ -1269,33 +1275,33 @@ the format specifier before passing the assembly code line to the backend.
|
||||
<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)
|
||||
@ -1314,19 +1320,19 @@ an assembler and how to handle assembler jumps:
|
||||
</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;
|
||||
@ -1339,28 +1345,30 @@ Arrays can also be accessed:
|
||||
<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
|
||||
@ -1434,4 +1442,3 @@ freely, subject to the following restrictions:
|
||||
</enum>
|
||||
|
||||
</article>
|
||||
|
||||
|
@ -41,12 +41,14 @@
|
||||
/* cc65 */
|
||||
#include "asmlabel.h"
|
||||
#include "codegen.h"
|
||||
#include "codeseg.h"
|
||||
#include "datatype.h"
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "function.h"
|
||||
#include "litpool.h"
|
||||
#include "scanner.h"
|
||||
#include "segments.h"
|
||||
#include "stackptr.h"
|
||||
#include "symtab.h"
|
||||
#include "asmstmt.h"
|
||||
@ -422,6 +424,15 @@ void AsmStatement (void)
|
||||
/* Skip the ASM */
|
||||
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 */
|
||||
if (!ConsumeLParen ()) {
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user