mirror of
https://github.com/cc65/cc65.git
synced 2025-02-11 00:31:06 +00:00
Merge pull request #285 from greg-king5/asm-volatile
Add the C keyword "volatile" to the __asm__ statement grammar.
This commit is contained in:
commit
b3d84d511c
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…
x
Reference in New Issue
Block a user