mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-08-31 23:30:32 +00:00
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@317 4df02467-bbd4-4a76-a152-e7ce94205b78
501 lines
21 KiB
Plaintext
501 lines
21 KiB
Plaintext
|
|
|
|
ACME
|
|
|
|
...the ACME Crossassembler for Multiple Environments
|
|
|
|
--- Quick reference ---
|
|
|
|
|
|
This file should give you a basic overview. More specialized stuff
|
|
like forcing a specific addressing mode is discussed in extra files
|
|
("AddrModes.txt" in this case).
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
Section: Example of what an ACME source code file looks like
|
|
----------------------------------------------------------------------
|
|
|
|
;--- Example code fragment, start ---
|
|
|
|
!to "tiny.o", cbm ; set output file and format
|
|
* = $c000 ; set program counter
|
|
|
|
CLEAR = 147 ; a global symbol definition
|
|
!addr basout = $ffd2 ; another one, marked as an address
|
|
|
|
; a string output loop:
|
|
ldx #0
|
|
beq + ; enter loop
|
|
|
|
- jsr basout ; output character
|
|
inx ; advance pointer
|
|
+ lda .string, x ; get character
|
|
bne - ; check whether last
|
|
rts
|
|
.string !pet "Dumb example", 13, 0
|
|
|
|
;--- Example code fragment, end ---
|
|
|
|
|
|
Here's the same fragment again, now with some additional info:
|
|
|
|
;--- Example code fragment, start ---
|
|
|
|
!to "tiny.o", cbm ; set output file and format
|
|
; This is a pseudo opcode to select the output filename and format.
|
|
; This can also be done using the command line options "-o" and "-f",
|
|
; respectively.
|
|
* = $c000 ; set program counter
|
|
; This can also be done using the command line option "--setpc".
|
|
|
|
; some global symbol definitions
|
|
CLEAR = 147 ; this is a simple constant
|
|
; Now "CLEAR" is defined as a global symbol having the value 147.
|
|
!addr basout = $ffd2 ; this gets marked as an address
|
|
; Now "basout" is defined as a global "address" type symbol having the
|
|
; value $ffd2.
|
|
; The distinction between addresses and non-addresses only
|
|
; matters when the type check system gets activated using
|
|
; the "-Wtype-mismatch" switch. Then, a line like
|
|
; "lda CLEAR" would trigger a type mismatch warning because
|
|
; of the missing '#' character.
|
|
|
|
; a string output loop:
|
|
ldx #0
|
|
beq + ; enter loop
|
|
; "+" is an anonymous forward label. Other ones are "++", "+++", etc.
|
|
; They can be used like any other symbol, but they always reference
|
|
; their *NEXT* definition. This saves having to think of names for
|
|
; unimportant labels. As the label's value is not defined yet, ACME
|
|
; will need to perform a second pass.
|
|
- jsr basout ; output character
|
|
; "-" is an anonymous backward label. Other ones are "--", "---", etc.
|
|
; They can be used like any other symbol, but they always reference
|
|
; their *PREVIOUS* definition. This saves having to think of names for
|
|
; unimportant labels. In the line above, the value of "-" is set to
|
|
; the current program counter.
|
|
inx ; advance pointer
|
|
+ lda .string,x ; get character
|
|
; Here the value of "+" is set to the current program counter.
|
|
; ".string" is a local symbol (because its name starts with a '.'
|
|
; character), but as its value is not defined yet, ACME will need to
|
|
; perform a second pass.
|
|
bne - ; check whether last
|
|
; Here the last definition of the anonymous "-" label is referenced.
|
|
rts
|
|
.string !pet "Dumb example", 13, 0
|
|
; Now the value of the local label ".string" is set to the current
|
|
; program counter. All label values are defined now, so after having
|
|
; done the second pass, the binary will be saved. The "!pet" pseudo
|
|
; opcode stores its string argument in PetSCII encoding to memory,
|
|
; followed by the given byte values.
|
|
|
|
;--- Example code fragment, end ---
|
|
|
|
As you can see, pseudo opcodes are prefixed with an exclamation mark.
|
|
That's non-standard, but: Backwards compatibility is the root of all
|
|
evil. :)
|
|
|
|
Summary about symbols:
|
|
|
|
There are global symbols (their names starting with a letter or an
|
|
underscore character). These can be accessed throughout the whole
|
|
assembly.
|
|
Then there are local symbols (their names starting with a '.'
|
|
character). These can only be accessed from inside the macro or zone
|
|
they were defined in (for more about macros and zones, see the file
|
|
"AllPOs.txt").
|
|
There are also "cheap locals": their names start with an '@'.
|
|
The area where these can be accessed is limited automatically by the
|
|
previous and the following global label (cheap locals are "cheap"
|
|
because you don't have to put in any extra work to limit their range).
|
|
And then there are anonymous labels (their names being sequences of
|
|
either '-' or '+' characters). They are also local (bound to their
|
|
macro/zone), but in addition to that, the "-" labels can only be used
|
|
for backward references, while the "+" labels can only be used for
|
|
forward references.
|
|
In contrast to global and local labels, anonymous labels can not be
|
|
defined explicitly (as in SYMBOL = VALUE).
|
|
Each macro call automatically gets its own scope for local symbols.
|
|
|
|
Save the given example source code to a file called "tiny.a" and start
|
|
acme by typing
|
|
|
|
acme tiny.a
|
|
|
|
ACME will then parse the file and report any errors. An output file
|
|
will only be generated if there were no errors and if an output
|
|
filename has been given.
|
|
|
|
After assembly, the example program can be run on a C64 using
|
|
|
|
LOAD "tiny.o", 8, 1
|
|
SYS 49152
|
|
|
|
Note that ACME does not include any routines for transferring data to
|
|
a C64. Such tools exist on almost every platform, and I didn't want
|
|
ACME to become bloatware.
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
Section: The pseudo opcodes
|
|
----------------------------------------------------------------------
|
|
|
|
A list with information on how to use all the Pseudo Opcodes can be
|
|
found in the file "AllPOs.txt". Here's just a short overview:
|
|
|
|
!byte !word !24 !32 !fill !align
|
|
...for directly placing values into the output file.
|
|
|
|
!zone !symbollist
|
|
...for defining the scope of local symbols and saving global symbols.
|
|
|
|
!convtab !pet !raw !scr !scrxor !text
|
|
...for converting and outputting strings.
|
|
|
|
!do !endoffile !for !if !ifdef !ifndef !set !while
|
|
...for flow control; looping assembly and conditional assembly.
|
|
|
|
!binary !source !to
|
|
...for handling input and output files.
|
|
|
|
!pseudopc
|
|
...for offset assembly.
|
|
|
|
!initmem *=
|
|
...for segment assembly.
|
|
|
|
!macro +
|
|
...for defining and calling macros.
|
|
|
|
!cpu !al !as !rl !rs
|
|
...for CPU support, especially the 65816 processor.
|
|
|
|
!warn !error !serious
|
|
...for generating warnings, errors and serious errors.
|
|
|
|
!address
|
|
...to mark symbols as addresses, for the optional type check system.
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
Section: Command line arguments
|
|
----------------------------------------------------------------------
|
|
|
|
The command line syntax for calling acme is quite simple:
|
|
|
|
acme [options] [files]
|
|
|
|
Available options are:
|
|
-h, --help show this help and exit
|
|
This is more or less useless, because the help is also shown
|
|
if ACME is run without any arguments at all.
|
|
|
|
-f, --format FORMAT set output file format
|
|
Use this with a bogus format type to get a list of all
|
|
supported ones (as of writing: "plain", "cbm" and "apple")
|
|
-o, --outfile FILE set output file name
|
|
Output file name and format can also be given using the "!to"
|
|
pseudo opcode. If the format is not specified, "!to" defaults
|
|
to "cbm", while the command line option defaults to "plain".
|
|
|
|
-r, --report set report file name
|
|
This creates a text listing containing the original line
|
|
number, the resulting memory address, the byte value(s) put
|
|
there and the original text line from the source file.
|
|
|
|
-l, --symbollist FILE set symbol list file name
|
|
This can also be given using the "!symbollist"/"!sl" pseudo
|
|
opcode. The switch was called "--labeldump" in older versions,
|
|
that name still works, too.
|
|
|
|
--vicelabels FILE set file name for label dump in VICE format
|
|
The resulting file uses a format suited for the VICE emulator.
|
|
|
|
--setpc VALUE set program counter
|
|
This can also be given in the source code using "* = VALUE".
|
|
|
|
--cpu CPU_TYPE set target processor
|
|
This can be changed in the source code using the "!cpu" pseudo
|
|
opcode. Defaults to 6502.
|
|
Use this with a bogus cpu type to get a list of all supported
|
|
ones.
|
|
|
|
--initmem VALUE define 'empty' memory
|
|
This can also be given using the "!initmem" pseudo opcode.
|
|
Defaults to zero.
|
|
|
|
--maxerrors NUMBER set number of errors before exiting
|
|
If not given, defaults to 10.
|
|
|
|
--maxdepth NUMBER set recursion depth for macro calls and !src
|
|
The default value for this is 64.
|
|
|
|
--ignore-zeroes do not determine number size by leading zeroes
|
|
Normally, using leading zeroes forces ACME to generate
|
|
oversized addressing modes, like 3-byte absolute instructions
|
|
instead of 2-byte zero page instructions.
|
|
Using this CLI switch disables this behavior.
|
|
|
|
--strict-segments turn segment overlap warnings into errors
|
|
When changing the program counter, segment overlap warnings may
|
|
be generated. Using this CLI switch turns those warnings into
|
|
errors (which is recommended).
|
|
This strict behavior may become the default in future releases!
|
|
|
|
-vDIGIT set verbosity level
|
|
Sets how much additional informational output is generated.
|
|
Higher values mean more output:
|
|
acme -v0 source.a
|
|
This is the default: No additional output is generated,
|
|
ACME will only display warnings and errors.
|
|
acme -v1 source.a
|
|
Now the start and end addresses of the generated output
|
|
file are displayed, along with its size (a CBM-style
|
|
"load address" is *not* counted).
|
|
acme -v2 source.a
|
|
In addition to the "-v1" output, ACME will announce each
|
|
pass, will show amount and offset of "!binary" loads, and
|
|
show start and end addresses and size of each segment.
|
|
acme -v3 source.a
|
|
In addition to the "-v2" output, ACME will now announce
|
|
each source file.
|
|
|
|
-DSYMBOL=VALUE define global symbol
|
|
This option is useful if you build your projects using
|
|
Makefiles: "-DSYSTEM=64" could build the C64 version while
|
|
"-DSYSTEM=128" could build the C128 version of the software
|
|
(using conditional assembly in your source code file).
|
|
|
|
-I PATH/TO/DIR add search path for input files
|
|
This option allows to add a directory to the search list for
|
|
input files. If an input file cannot be found in the current
|
|
working directory, all directories in the search list are
|
|
tried (the first match is used).
|
|
|
|
-W fine-tune amount and type of warnings
|
|
-Wno-label-indent
|
|
Disables warnings about labels not being in the leftmost
|
|
column.
|
|
-Wno-old-for
|
|
Disables warnings about the old "!for" syntax and at the
|
|
same time enables warnings about the _new_ "!for" syntax.
|
|
Internally, this does exactly the same as what happens
|
|
when the "--dialect 0.94.8" CLI switch is used...
|
|
-Wno-bin-len
|
|
Do not complain about unusual number of digits in a binary
|
|
literal.
|
|
-Wtype-mismatch
|
|
Enables type checking system (warns about wrong types).
|
|
|
|
--use-stdout fix for 'Relaunch64' IDE
|
|
With this option, errors are written to the standard output
|
|
stream instead of to the standard error stream.
|
|
|
|
--msvc output errors in MS VS format
|
|
This changes the format of the error output to that used by
|
|
a certain commercial IDE.
|
|
|
|
--color uses ANSI color codes for error output
|
|
If your terminal emulation supports ANSI escape codes, use
|
|
this option to have warnings and errors displayed in color.
|
|
|
|
--fullstop use '.' as pseudo opcode prefix
|
|
This changes the prefix character used to mark pseudo opcodes
|
|
from '!' to '.' (so sources intended for other assemblers can
|
|
be converted with less effort).
|
|
|
|
--dialect VERSION behave like different version
|
|
This CLI switch tells ACME to mimic the behavior of an older
|
|
version. Use this with a bogus version to get a list of all
|
|
supported ones.
|
|
|
|
--test enable experimental features
|
|
This is for people who want to help test new features before
|
|
they are officially announced.
|
|
|
|
-V, --version show version and exit.
|
|
|
|
Platform-specific versions of ACME might offer more options.
|
|
Since version 0.89, ACME accepts more than one top-level-filename
|
|
given on the command line.
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
Section: The expression parser
|
|
----------------------------------------------------------------------
|
|
|
|
ACME has a relatively powerful maths parser. This parser is used
|
|
whenever ACME expects to read a value. Supported operations include
|
|
addition, subtraction, multiplication, divisions, comparisons, shifts,
|
|
negation, boolean operations and some assembler-specific stuff like
|
|
extracting the "low byte", the "high byte" or the "bank byte" of a
|
|
value.
|
|
Calculations are done using either signed (at least 32-bit) integer
|
|
arithmetic or floating point arithmetic using the C "double" data
|
|
type. Symbol values are stored the same way.
|
|
|
|
|
|
This is a list of the value formats currently known by ACME:
|
|
|
|
Examples Notes
|
|
---------------------------------------------------------------------
|
|
128 a decimal value, integer
|
|
128.5 a decimal value, floating point
|
|
$d011 hexadecimal values are indicated by either a
|
|
0xffd2 leading "$" or a leading "0x".
|
|
&1701 an octal value, indicated by "&"
|
|
%1010 binary values are indicated by either a leading "%"
|
|
%....#... or a leading "0b". In binary values, you can
|
|
0b01100110 substitute the characters "0" and "1" by "." and
|
|
"#" respectively. This way the values are much
|
|
more readable, especially when building bitmapped
|
|
objects (like C64 sprites or fonts) in your source
|
|
code.
|
|
'p' single characters in single quotes are converted to
|
|
their character code. The actual numeric value
|
|
depends on the current conversion table chosen
|
|
using the "!ct" pseudo opcode.
|
|
"player 2" double quotes indicate text strings. See below for
|
|
more information on single vs. double quotes.
|
|
[2, 3, 5, 7] brackets indicate lists. These are useful to group
|
|
[0, [x, y], 9] data, for example when passing an arbitrary number
|
|
of arguments to a macro.
|
|
poll_joy2 a global symbol
|
|
.fail a local symbol, indicated by leading "."
|
|
@loop a "cheap local", indicated by leading "@"
|
|
* the current program counter. During offset assembly,
|
|
"*" gives the value of the "Pseudo PC". Just to
|
|
make sure: The value of the program counter is
|
|
always the value that was valid at the start of
|
|
the current statement, so
|
|
!word *, *, *, *
|
|
will give the same value four times. I think most
|
|
assemblers do it this way.
|
|
|
|
In older versions of ACME, 'x' and "x" were the same thing, namely the
|
|
character code of the letter x using the currently selected encoding
|
|
table.
|
|
Since release 0.97, anything in single quotes gives the character code
|
|
(as before), while anything in double quotes is treated as a string
|
|
object. To be compatible to those older versions, ACME keeps accepting
|
|
one-char strings in a lot of places where actually single characters
|
|
are expected.
|
|
|
|
|
|
This is a list of the operators currently known by ACME:
|
|
|
|
Priority Example Meaning Alias Note
|
|
----------------------------------------------------------------------
|
|
16 is_number(v) these three functions return 1 *3
|
|
16 is_list(v) if v is the correct symbol *3
|
|
16 is_string(v) type and 0 otherwise *3
|
|
16 len(v) length of list or string *2
|
|
16 sin(v) trigonometric sine function
|
|
16 cos(v) trigonometric cosine function
|
|
16 tan(v) trigonometric tangent function
|
|
16 arcsin(v) inverse of sin()
|
|
16 arccos(v) inverse of cos()
|
|
16 arctan(v) inverse of tan()
|
|
16 address(v) mark as address addr(v)
|
|
16 int(v) convert to integer
|
|
16 float(v) convert to float
|
|
15 &symbol "unpseudopc" symbol (see docs on "!pseudopc")
|
|
14 v[w] access v with index w *2
|
|
13 ! v bit-wise complement NOT
|
|
12 v ^ w to the power of
|
|
11 - v negate
|
|
10 v * w multiply
|
|
10 v / w divide
|
|
10 v DIV w integer divide
|
|
10 v % w remainder of DIV MOD
|
|
9 v + w add *3
|
|
9 v - w subtract
|
|
8 v << w shift left ASL, LSL
|
|
8 v >> w arithmetic shift right ASR
|
|
8 v >>> w logical shift right LSR
|
|
7 < v low byte of
|
|
7 > v high byte of
|
|
7 ^ v bank byte of
|
|
6 v <= w lower or equal
|
|
6 v < w lower than
|
|
6 v >= w higher or equal
|
|
6 v > w higher than
|
|
5 v != w not equal <>, >< *3
|
|
4 v == w equal = *3
|
|
3 v & w bit-wise AND AND
|
|
2 bit-wise exclusive OR XOR
|
|
1 v | w bit-wise OR OR
|
|
|
|
Notes:
|
|
"*2" means this operator only works on lists and strings.
|
|
"*3" means this operator works on all three data types (numbers, lists
|
|
and strings).
|
|
All other operators only work on numbers.
|
|
|
|
Operations with higher priority are done first. Of course you can
|
|
change this using parentheses.
|
|
Note that though there are operators to extract the "low byte", the
|
|
"high byte" and the "bank byte", there is no operator to extract the
|
|
fourth byte. If you want to access that, shift it down using ">>>" or
|
|
"LSR".
|
|
In cases where it's not clear which operator was wanted, ACME takes
|
|
the longest possible one:
|
|
v<>w ...checks for "v not equal w"
|
|
v< >w ...checks for "v smaller than high byte of w"
|
|
So you may have to separate operators with spaces to make sure ACME
|
|
does what you want.
|
|
The "power-of" operator is right-associative, so a^b^c means a^(b^c).
|
|
|
|
Calculating 0^0 (zero to the power of zero) will give 1. If
|
|
you don't know why I'm telling you this, ask a mathematician. :)
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
Section: Almost, but not quite, complete syntax
|
|
----------------------------------------------------------------------
|
|
|
|
Every ACME source code file consists of a non-negative number of
|
|
"lines". The lines have to be separated from each other using CR, LF
|
|
or CRLF characters.
|
|
|
|
Every line consists of a non-negative number of "statements" and an
|
|
optional comment. Statements have to be separated from each other
|
|
using colon (":") characters, the comment has to be prefixed with a
|
|
semicolon (";") character or two slashes ("//").
|
|
|
|
Every statement consists of an optional "label" and an optional
|
|
"command". These are separated from each other using any number of
|
|
SPACE or TAB characters. If a label has blanks before it, a warning is
|
|
issued (to spot typing errors - see Errors.txt for more info).
|
|
|
|
Every symbol name consists of these characters: "a" to "z", "A" to
|
|
"Z", "0" to "9", the underscore character "_" and all characters with
|
|
values beyond 127. The first character must not be a digit though. But
|
|
it can be '.' or '@', making the symbol a local one.
|
|
Local symbols beginning with '.' are only valid inside the current
|
|
zone (marked using the "!zone" pseudo opcode) or the current macro.
|
|
Local symbols beginning with '@' are only valid between the enclosing
|
|
global labels (or inside the current macro).
|
|
Two other possibilities for label names are "all-characters-are-minus"
|
|
(then it is an anonymous backward label) and "all-characters-are-plus"
|
|
(then it is an anonymous forward label).
|
|
|
|
Every command is one of the following:
|
|
An assembler mnemonic with an optional argument
|
|
A pseudo opcode, beginning with a "!" character
|
|
An explicit symbol definition (SYMBOL = VALUE)
|
|
A pc definition, beginning with a "*" character
|
|
A macro call, beginning with a "+" character
|
|
...and the syntax of those things varies. :)
|
|
|
|
Assembler mnemonics and pseudo opcodes are case insensitive, so
|
|
whether you write "LDA" or "lda" or "LdA" does not make a difference.
|
|
|
|
In earlier releases of ACME, arithmetic operators like MOD, XOR, LSL
|
|
had to be written in UPPER CASE. This is no longer needed.
|
|
|
|
Symbol names are case sensitive, so "label" and "Label" are two
|
|
different things.
|