adjusted docs (added !WHILE, ELSE IF, etc)

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@251 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2020-06-21 19:06:12 +00:00
parent 7f736ceccb
commit 1261960cad
9 changed files with 246 additions and 134 deletions

View File

@ -7,12 +7,12 @@
--- addressing modes ---
If a command can be used with different addressing modes, ACME has to
decide which one to use. Several commands of the 6502 CPU can be used
with either "absolute" addressing or "zeropage-absolute" addressing.
The former one means there's a 16-bit argument, the latter one means
there's an 8-bit argument.
And the 65816 CPU even knows some commands with 24-bit addressing...
If an instruction can be used with different addressing modes, ACME
has to decide which one to use. Several instructions of the 6502 CPU
can be used with either "absolute" addressing or "zeropage-absolute"
addressing. The former one means there's a 16-bit argument, the latter
one means there's an 8-bit argument.
And the 65816 CPU even has some instructions with 24-bit addressing...
So how does ACME know which addressing mode to use?
The simple approach is to always use the smallest possible argument,
@ -29,11 +29,10 @@ The two exceptions are:
*** 1) Symbols are defined too late
If ACME cannot figure out the argument value in the first pass, it
assumes that the command uses 16-bit addressing.
assumes that the instruction uses 16-bit addressing.
If it later finds out that the argument only needs 8 bits, ACME gives
a warning ("using oversized addressing mode") and continues. However,
@ -43,8 +42,7 @@ These problems can be solved by defining the symbols *before* using
them, so that the value can be figured out in the first pass. If this
is not possible, you can use the postfix method, effectively exactly
defining what addressing mode to use. The postfix method is described
in a separate paragraph below.
in a separate section below.
@ -89,8 +87,7 @@ This feature can be disabled using the "--ignore-zeroes" CLI switch.
The other possibility is to use the postfix method (described in the
next paragraph).
next section).
@ -132,7 +129,7 @@ will be assembled to
8c fd 00 ; sty $00fd
8f ff 00 00 ; sta $0000ff
Postfixes given directly after the command have higher priority than
Postfixes added directly to the mnemonic have higher priority than
those given to the argument. As you can see, you can add the postfix
to the symbol definition as well (equivalent to leading zeros).
@ -141,8 +138,7 @@ gives the high byte and "^" gives the bank byte of a value) to any
value will clear the argument's Force Bits 2 and 3 and set Force
Bit 1 instead. So "lda <symbol" will use 8-bit addressing, regardless
of the symbol's Force Bits. Of course, you can change this by
postfixing the command again... :)
postfixing the instruction again... :)
@ -152,7 +148,7 @@ You don't need to read this paragraph just to use ACME, I only
included it for completeness' sake. This is a description of ACME's
strategy for finding the addressing mode to use:
First, ACME checks whether the command has any postfix. If it has,
First, ACME checks whether the instruction has any postfix. If it has,
ACME acts upon it. So postfixes have the highest priority.
Otherwise, ACME checks whether the argument has any Force Bits set

View File

@ -29,8 +29,9 @@ Examples: !08 127, symbol, -128 ; output some values
Call: !16 EXPRESSION [, EXPRESSION]*
Purpose: Insert 16-bit values in chosen CPU's byte order.
Parameters: EXPRESSION: Any formula the value parser accepts.
Aliases: "!wo", "!word" (and because all currently supported CPUs are
little-endian, "!le16" is in fact another alias)
Aliases: "!wo", "!word" (and because all currently supported
CPUs are little-endian, "!le16" is in fact another
alias)
Examples: !16 65535, symbol, -32768 ; output some values
!wo 14, $4f35, %100101010010110, &36304, *, 'c'
!word 3000 - 4, a1 AND a2, 2 ^ tz, (3+4)*70, l1 & .j2
@ -108,12 +109,12 @@ Examples: !be32 $7fffffff, symbol, -$80000000, 14, $46a4f35
Call: !hex PAIRS_OF_HEX_DIGITS
Purpose: Insert byte values with a minimum of additional syntax.
This pseudo opcode was added for easier writing of external
source code generator tools.
Parameters: PAIRS_OF_HEX_DIGITS: Just hexadecimal digits, without any
"0x" or "$" prefix. Spaces and TABs are allowed, but not
needed to separate the byte values.
Purpose: Insert byte values with a minimum of additional
syntax. This pseudo opcode was added for easier
writing of external source code generator tools.
Parameters: PAIRS_OF_HEX_DIGITS: Just hexadecimal digits, without
any "0x" or "$" prefix. Spaces and TABs are allowed,
but not needed to separate the byte values.
Aliases: "!h"
Examples: !h f0 f1 f2 f3 f4 f5 f6 f7 ; insert values 0xf0..0xf7
!h f0f1f2f3 f4f5f6f7 ; insert values 0xf0..0xf7
@ -136,10 +137,12 @@ Examples: !fi 256, $ff ; reserve 256 bytes
Call: !skip AMOUNT
Purpose: Advance in output buffer without starting a new segment.
Purpose: Advance in output buffer without starting a new
segment.
Parameters: AMOUNT: Any formula the value parser accepts, but it
must be solvable even in the first pass (this limitation
will hopefully be lifted in a future release).
must be solvable even in the first pass (this
limitation will hopefully be lifted in a future
release).
Aliases: None
Examples: !skip BUFSIZE ; reserve some bytes
!skip 5 ; reserve five bytes
@ -155,7 +158,7 @@ Parameters: ANDVALUE: Any formula the value parser accepts, but it
it must be solvable even in the first pass.
FILLVALUE: Any formula the value parser accepts. If it
is omitted, a default value is used (currently 234,
that's the 6502 CPU's NOP command).
that's the opcode of the 6502 CPU's NOP instruction).
Examples: !align 255, 0 ; align to page (256 bytes)
!align 63, 0 ; align to C64 sprite block (64 bytes)
@ -378,22 +381,24 @@ Section: Flow control
Call: !if CONDITION { BLOCK } [ else { BLOCK } ]
Purpose: Conditional assembly. If the given condition is true,
the first block of statements will be parsed;
if it isn't, the second block will be parsed instead
(if present).
the matching block of statements will be parsed;
if no condition is true, the ELSE block (if present)
will be parsed.
Parameters: CONDITION: Any formula the value parser accepts, but
it must be solvable even in the first pass.
BLOCK: A block of assembler statements.
Examples: !text "Black", 0 ; Choose wording according to
!if country = uk { ; content of "country" symbol.
Examples: ; Choose word according to "country" symbol:
!if country = uk {
!text "Grey"
} else if country = fr {
!text "Gris"
} else if country = de {
!text "Grau"
} else {
!text "Gray"
}
!byte 0
!text "White", 0
; Insert debug commands if symbol "debug" is not zero:
; Insert debug code depending on symbol "debug":
!if debug { lda #'z':jsr char_output }
@ -437,12 +442,26 @@ Examples: ; this was taken from <6502/std.a>:
; further instances will be skipped.
}
; include at most one driver source code:
!ifdef RAM_REU {
!src "driver_reu.a"
} else ifdef RAM_GEORAM {
!src "driver_georam.a"
} else ifdef RAM_VDCRAM {
!src "driver_vdcram.a"
} else ifdef RAM_SUPERRAM {
!src "driver_superram.a"
} else {
!src "driver_noram.a"
}
Call: !for SYMBOL, START, END { BLOCK }
Purpose: Looping assembly. The block of statements will be
parsed a fixed number of times, as specified by the
values of START and END. For a more flexible
possibility, have a look at "!do" below.
values of START and END. For more flexible
possibilities, have a look at "!do" and "!while"
below.
Parameters: SYMBOL: Any valid symbol name.
START: Any formula the value parser accepts, but it
must be solvable even in the first pass. SYMBOL will
@ -492,12 +511,13 @@ Examples:
Miscellaneous: The old syntax ("!for SYMBOL, END { BLOCK }" where
START was always implied to be 1) is still fully
supported, but gives a warning to get people to change
to the new syntax. You can disable this warning using
the "-Wno-old-for" switch, but then you will get
to the new syntax.
You can disable this warning using the "--dialect" or
the "-Wno-old-for" switches, but then you will get
warnings for using the *new* syntax.
When migrating your sources, bear in mind that it is
no longer possible to skip the block completely by
specifying a loop count of zero.
When migrating your sources to the current syntax,
bear in mind that it is no longer possible to skip the
block completely by specifying a loop count of zero.
Also note that with the new algorithm, SYMBOL has a
different value after the block than during the last
loop cycle, while the old algorithm kept that last
@ -507,9 +527,9 @@ Miscellaneous: The old syntax ("!for SYMBOL, END { BLOCK }" where
Call: !set SYMBOL = VALUE
Purpose: Assign given value to symbol even if the symbol
already has a different value. Needed for loop
counters when using "!do", for example. Only use this
opcode for something else if you're sure you *really*
know what you are doing... :)
counters when using "!do"or "!while", for example.
Only use this opcode for something else if you're sure
you *really* know what you are doing... :)
Parameters: SYMBOL: Any valid symbol name.
VALUE: Any formula the value parser accepts.
Example: see "!do" below
@ -549,6 +569,34 @@ Examples: ; a loop with conditions at both start and end
!do until 3 = 4 { } while 3 < 4
Call: !while [CONDITION] { BLOCK }
Purpose: Looping assembly. The block of statements can be
parsed several times, depending on the given
condition.
The condition is parsed in every repetition before the
actual block. If it isn't met when first checked, the
block will be skipped.
Parameters: CONDITION: Any formula the value parser accepts, but
it must be solvable even in the first pass.
BLOCK: A block of assembler statements.
Examples: ; a loop with a counter
!set a = 0 ; init loop counter
!while a < 6 {
lda #a
sta label + a
!set a = a + 1
}
; a loop depending on program counter
!while * < $c000 { nop }
; a never ending loop - this will cause an error
!while 3 < 4 { nop }
; an empty loop - this will hang ACME
!while 3 != 4 { }
Call: !endoffile
Purpose: Stop processing the current source file. Using this
pseudo opcode you can add explanatory text inside your
@ -563,22 +611,24 @@ Example: rts ; some assembler mnemonic
"!eof" is reached.
Call: !warn STRING_VALUE [, STRING_VALUE]*
Call: !warn VALUE [, VALUE]*
Purpose: Show a warning during assembly.
Parameters: STRING_VALUE: Can be either a string given in double
quotes or any formula the value parser accepts.
Numbers will be output in decimal _and_ hex format.
Parameters: VALUE: Can be either a string given in double quotes
or any formula the value parser accepts.
Integer numbers will be output in both decimal _and_
hex formats.
Example: !if * > $a000 {
!warn "Program reached ROM: ", * - $a000, " bytes overlap."
}
Call: !error STRING_VALUE [, STRING_VALUE]*
Call: !error VALUE [, VALUE]*
Purpose: Generate an error during assembly (therefore, no
output file will be generated).
Parameters: STRING_VALUE: Can be either a string given in double
quotes or any formula the value parser accepts.
Numbers will be output in decimal _and_ hex format.
Parameters: VALUE: Can be either a string given in double quotes
or any formula the value parser accepts.
Integer numbers will be output in both decimal _and_
hex formats.
Example: rts ; end of some function
start !source "colors.a"
end !if end - start > 256 {
@ -586,12 +636,13 @@ Example: rts ; end of some function
}
Call: !serious STRING_VALUE [, STRING_VALUE]*
Call: !serious VALUE [, VALUE]*
Purpose: Generate a serious error, immediately stopping
assembly.
Parameters: STRING_VALUE: Can be either a string given in double
quotes or any formula the value parser accepts.
Numbers will be output in decimal _and_ hex format.
Parameters: VALUE: Can be either a string given in double quotes
or any formula the value parser accepts.
Integer numbers will be output in both decimal _and_
hex formats.
Example: !source "part1.a" ; sets part1_version
!source "part2.a" ; sets part2_version
!if part1_version != part2_version {
@ -611,9 +662,9 @@ Parameters: TITLE: The macro's desired name (same rules as for
could want this is beyond me).
SYMBOL: The desired name for the parameter value at
call time. Normally, these parameter symbols should be
local (first character a dot), as different macro
calls will almost for sure have different parameter
values.
local (first character a '.' or a '@'), as different
macro calls will almost for sure have different
parameter values.
If you prefix SYMBOL with a '~' character, it will be
called by reference, not by value: Changing the value
inside the macro will result in the "outer" symbol to
@ -740,8 +791,10 @@ Purpose: Set program counter to given value and start new
issued. Because some people do this overlapping
on purpose, the warnings can be suppressed using
modifier keywords.
Future versions of ACME may issue errors instead of
warnings.
Using the "--strict-segments" CLI switch, these
warnings can be turned onto errors. Future versions of
ACME may do that by default - so if needed, use the
modifier keywords.
Parameters: EXPRESSION: Any formula the value parser accepts, but
it must be solvable even in the first pass.
MODIFIER: "overlay" or "invisible" (without quotes):
@ -847,6 +900,13 @@ Examples: ldx #.shifted_end - .shifted_start
}
.shifted_end
Miscellaneous: If you need to convert a label or the program counter
from its "pseudopc" to its "real" value, you can do
that using the "&" operator. Given the example above,
the symbol ".target" will evaluate to the value $0400,
but "&.target" will evaluate to the same value as
".shifted_start" will.
----------------------------------------------------------------------
Section: CPU support pseudo opcodes (especially 65816 support)
@ -856,21 +916,23 @@ Call: !cpu KEYWORD [ { BLOCK } ]
Purpose: Select the processor to produce code for. If this PO
isn't used, ACME defaults to the 6502 CPU (or to the
one selected by the "--cpu" command line option).
ACME will give errors if you try to assemble commands
the chosen CPU does not have. You can change the
chosen CPU at any time. When used with block syntax,
the previously chosen CPU value is restored
afterwards.
ACME will give errors if you try to assemble
instructions the chosen CPU does not support. You can
change the chosen CPU at any time. When used with
block syntax, the previously chosen CPU value is
restored afterwards.
Parameters: KEYWORD: Currently valid keywords are:
6502 for the original MOS 6502
6510 6502 plus undocumented opcodes
65c02 6502 plus BRA,PHX/Y,PLX/Y,STZ,TRB/TSB
r65c02 65c02 plus BBRx, BBSx, RMBx, SMBx
w65c02 r65c02 plus STP/WAI
65816 65c02 plus 16/24-bit extensions
65ce02 r65c02 plus Z reg, long branches, ...
4502 65ce02 with MAP instead of AUG
c64dtv2 6502 plus BRA/SAC/SIR plus some of the
6502 for the original MOS 6502
nmos6502 6502 plus undocumented opcodes
6510 (alias for "nmos6502")
65c02 6502 plus BRA,PHX/Y,PLX/Y,STZ,TRB/TSB
r65c02 65c02 plus BBRx, BBSx, RMBx, SMBx
w65c02 r65c02 plus STP/WAI
65816 65c02 plus 16/24-bit extensions
65ce02 r65c02 plus Z reg, long branches, ...
4502 65ce02 with MAP instead of AUG
m65 4502 plus 32-bit extensions
c64dtv2 6502 plus BRA/SAC/SIR plus some of the
undocumented opcodes
See "docs/cputypes/all.txt" for more info.
BLOCK: A block of assembler statements.
@ -885,7 +947,7 @@ Examples: !if cputype = $65c02 {
pla
}
rts
!cpu 65816 ; allow 65816 commands from here on
!cpu 65816 ; now allow instructions of 65816 cpu
Call: !al [ { BLOCK } ]
@ -933,6 +995,8 @@ Parameters: BLOCK: A block of assembler statements
If no block is given, only the current statement will
be affected, which should then be an explicit symbol
definition.
To make use of this feature, you need to use the
"-Wtype-mismatch" CLI switch.
Aliases: "!addr"
Examples: !addr k_chrout = $ffd2 ; this is an address
CLEAR = 147 ; but this is not
@ -958,6 +1022,10 @@ Purpose: Use PetSCII as the text conversion table. Now
superseded by the "!convtab" pseudo opcode.
Old usage: !cbm ; gives "use !ct pet instead" error
Now use: !convtab pet ; does the same without error
If you just want to assemble an old source code
without touching it, use the "--dialect" CLI switch:
Using "--dialect 0.94.6" or earlier will assemble this
pseudo opcode without throwing an error.
Call: !subzone [TITLE] { BLOCK }
@ -972,6 +1040,10 @@ Old usage: !subzone graphics {
Now use: !zone graphics {
!source "graphics.a"
}
If you just want to assemble an old source code
without touching it, use the "--dialect" CLI switch:
Using "--dialect 0.94.6" or earlier will assemble this
pseudo opcode without throwing an error.
Call: !realpc
@ -985,3 +1057,8 @@ Old usage: !pseudopc $0400
Now use: !pseudopc $0400 {
; imagine some code here...
}
If you just want to assemble an old source code
without touching it, use the "--dialect" CLI switch:
Using "--dialect 0.94.6" or earlier will assemble this
pseudo opcode without throwing an error.
Using "--dialect 0.85", not even a warning is thrown.

View File

@ -38,15 +38,16 @@ Assembling buggy JMP($xxff) instruction
location ARGUMENT + 1, but from ARGUMENT - 255. Therefore ACME
issues this warning if you are about to generate such an
instruction.
Note that this warning is only given for CPU types 6502 and 6510,
because 65c02 and 65816 have been fixed in this respect.
Note that this warning is only given for some CPU types (6502,
nmos6502/6510, c64dtv2) because later ones like 65c02 and 65816
have been fixed in this regard.
Assembling unstable ANE #NONZERO instruction
Assembling unstable LXA #NONZERO instruction
These warnings are only ever given for CPU type 6510. ANE and LXA
are undocumented ("illegal") opcodes of this CPU, and they only
work reliably if the argument is zero or the accumulator contains
0xff.
These warnings are only ever given for CPU type nmos6502 (6510).
ANE and LXA are undocumented ("illegal") opcodes of this CPU, and
they only work reliably if the argument is zero or the accumulator
contains 0xff.
Therefore ACME issues these warnings if it is about to generate
these instructions with a non-zero argument.
@ -64,7 +65,7 @@ C-style "==" comparison detected.
Converted to integer for binary logic operator.
Applying binary logic to float values does not make much sense,
therefore floats will be converted to integer in this case.
therefore floats will be converted to integer in such cases.
"EOR" is deprecated; use "XOR" instead.
This means the operator, not the mnemonic.
@ -72,7 +73,9 @@ Converted to integer for binary logic operator.
Found old "!for" syntax.
Please update your sources to use the new "!for" syntax. See
AllPOs.txt for details.
You can suppress this warning using the "-Wno-old-for" switch.
You can suppress this warning using the "--dialect" or the
"-Wno-old-for" CLI switch.
("-Wno-old-for" does _exactly_ the same as "--dialect 0.94.8")
Found new "!for" syntax.
When using the "-Wno-old-for" switch to disable the warning about
@ -187,14 +190,23 @@ Section: Errors during assembly
"!cbm" is obsolete; use "!ct pet" instead.
This is given when the now obsolete "!cbm" pseudo opcode is
encountered.
If you want to assemble an old source code without first updating
it, you can use the "--dialect" CLI switch to make ACME mimic an
older version.
"!pseudopc/!realpc" is obsolete; use "!pseudopc {}" instead.
This is given when one of the now obsolete !pseudopc/!realpc
pseudo opcodes is encountered.
If you want to assemble an old source code without first updating
it, you can use the "--dialect" CLI switch to make ACME mimic an
older version.
"!subzone {}" is obsolete; use "!zone {}" instead.
This is given when the now obsolete "!subzone" pseudo opcode is
encountered.
If you want to assemble an old source code without first updating
it, you can use the "--dialect" CLI switch to make ACME mimic an
older version.
!error: ...
This is given when the pseudo opcode "!error" is executed. The
@ -293,7 +305,7 @@ Negative value - cannot choose addressing mode.
your program to use positive addresses instead.
No string given.
ACME expects a string but doesn't find it.
ACME expects a string but doesn't find it, or the string is empty.
Number out of range.
A value is too high or too low.
@ -315,6 +327,9 @@ Quotes still open at end of line.
Source file contains illegal character.
Your source code file contained a null byte.
String length is not 1.
You tried something like LDA#"X" with an illegal string length.
Symbol already defined.
You defined a symbol that already had a different type or value.
To change a symbol's type or value, use the "!set" pseudo opcode.
@ -334,8 +349,8 @@ Target out of range (N; M too far).
away, the code would assemble.
There's more than one character.
You used a text string in an arithmetic expression, but the string
contained more than a single character.
You used a text string containing more than one character in a
situation where only a string with length one is allowed.
Too late for postfix.
You can only postfix symbols at the start, before they are used for
@ -346,8 +361,8 @@ Too many '('.
Un-pseudopc operator '&' can only be applied to labels.
You tried to apply the operator '&' to something that is not a
label. This operator only works on labels, it cannot be used on
other objects.
label. This operator only works on labels and on '*' (the program
counter), it cannot be used on other objects.
Un-pseudopc operator '&' has no !pseudopc context.
You either tried to apply the operator '&' to something that is
@ -443,7 +458,7 @@ Too deeply nested. Recursive "!source"?
The default limit is 64, this can be changed using the
"--maxdepth" CLI switch.
Value not yet defined.
Value not defined.
A value could not be worked out. Maybe you mistyped a symbol name.
Whether this is given as a "normal" or as a serious error depends
on the currently parsed pseudo opcode.
@ -489,6 +504,9 @@ ArgStackNotEmpty
The expression parser has finished though there are still
arguments left to process.
ExtendingListWithItself
There were multiple references to the same list.
IllegalBlockTerminator
A RAM block (macro or loop) was terminated incorrectly.
@ -502,6 +520,9 @@ IllegalImmediateMode
The mnemonic tree contains invalid info about the size of immediate
arguments.
IllegalNumberTypeX
A number was neither INT nor FLOAT nor UNDEFINED.
IllegalOperatorId
IllegalOperatorGroup
The expression parser found an operator that does not exist.

View File

@ -6,15 +6,15 @@
- free software -
(C) 1998-2019 Marco Baye
(C) 1998-2020 Marco Baye
----------------------------------------------------------------------
Section: Copyright
----------------------------------------------------------------------
ACME - a crossassembler for producing 6502/6510/65c02/65816 code.
Copyright (C) 1998-2017 Marco Baye
ACME - a crossassembler for producing 6502/65c02/65816 code.
Copyright (C) 1998-2020 Marco Baye
The ACME icon was designed by Wanja "Brix" Gayk
This program is free software; you can redistribute it and/or modify
@ -39,9 +39,9 @@ Section: Introduction
ACME is a crossassembler for the 65xx range of processors. It knows
about the standard 6502, the 65c02 and the 65816. It also supports
the undocumented ("illegal") opcodes of the 6510 processor (a 6502-
variant that is used in the Commodore C=64), and the extensions added
in the C64DTV2.
the undocumented ("illegal") opcodes of the NMOS versions of the 6502,
like the 6510 variant that is used in the Commodore C=64, and it also
supports extensions to the intruction set done by other parties.
This text and the other files in the same directory only describe the
basic functions independent of the platform used. There should be
@ -61,14 +61,16 @@ The files in the docs directory and what they contain:
Help.txt ...is this text.
Illegals.txt Support for undocumented opcodes
Lib.txt Information about the library
QuickRef.txt All the basic stuff about ACME
QuickRef.txt All the basic stuff about ACME <- START HERE!
Source.txt How to compile ACME
Upgrade.txt Incompatibilities to earlier versions
cputypes/ Instruction sets of target CPUs
IMPORTANT: If you upgrade from ACME 0.05 or earlier, don't forget to
read the file "Upgrade.txt" - release 0.07 and all later ones are
slightly incompatible to 0.05 and earlier.
IMPORTANT: If you upgrade from an earlier version of ACME, don't
forget to read the files "Changes.txt" and "Upgrade.txt". Adding new
features can not always be done in a 100% compatible way, so newer
version may behave slightly different. To solve this problem, the
"--dialect" CLI switch can be used.
If you want to start using ACME right away, read the file
"QuickRef.txt", it contains the main help text.
@ -79,15 +81,14 @@ Section: What it can and does
----------------------------------------------------------------------
ACME is a crossassembler.
ACME can produce code for the 6502, 6510, 65c02 and 65816 processors.
ACME can produce code for the 6502, 65c02 and 65816 processors.
It does this *fast*.
It can produce at most 64 KBytes of code.
You can use global labels, local labels and anonymous labels.
It is fast.
You can use global and local macros.
You can use conditional assembly.
You can use looping assembly (There are two ways to do this; a very
simple and a very flexible one).
You can use looping assembly.
You can include other source files.
You can include binary files (either whole or parts) directly into the
output.
@ -100,6 +101,7 @@ ACME's maths parser has no problems concerning parentheses and
indirect addressing modes.
ACME's maths parser knows a shit load of different operations.
ACME supports both integer and floating point maths operations.
In addition to numbers, symbols can also hold strings or lists.
You can dump the global symbols into a file.
ACME supports a library of commonly used macros and symbols.
It always takes as many passes as are needed.

View File

@ -8,7 +8,7 @@
In release 0.87, support for some of the undocumented opcodes of the
6502 processor was added.
NMOS 6502 processor was added.
In release 0.89, some more were added.
In release 0.94.8, another one was added (lxa).
In release 0.95.3, C64DTV2 support was added, which includes these
@ -31,7 +31,6 @@ opcodes (mnemonics in parentheses are used by other sources):
dcp (dcm) | c7 d7 cf df db c3 d3 | dec + cmp
isc (isb, ins) | e7 f7 ef ff fb e3 f3 | inc + sbc
las (lar, lae) | bb | A,X,S = {addr} & S
These five are said to be unstable:
tas (shs, xas) | 9b | S = A & X {addr} = A&X& {H+1}
sha (axa, ahx) | 9f 93 | {addr} = A & X & {H+1}
shx (xas, sxa) | 9e | {addr} = X & {H+1}
@ -53,13 +52,15 @@ These two are somewhat unstable, because they involve an arbitrary value:
lxa (lax, atx) | ab*** | A,X = (A | ??) & arg
Example:
!cpu 6510 ; activate additional mnemonics...
!cpu nmos6502 ; activate additional mnemonics...
lax (some_zp_label,x) ; ...and use them. No, this
dcp (other_zp_label),y ; example does not make sense.
*) Up until ACME version 0.95.1, anc#8 generated opcode 0x2b. Since
ACME version 0.95.2, anc#8 generates opcode 0x0b. Both opcodes work
the same way on a real 6510 CPU, but they do not work on the C64DTV2.
the same way on a real NMOS 6502 CPU, but they do not work on the
C64DTV2.
Using the "--dialect" CLI switch does not change the generated opcode!
**) Note that DOP ("double nop") and TOP ("triple nop") can be used
with implied addressing, but the generated opcodes are those for
@ -68,7 +69,7 @@ and TOP can be used to skip the following one- or two-byte
instruction.
Using DOP/TOP with x-indexed addressing might have its uses when
timing is critical (crossing a page border adds a penalty cycle).
Unless using implied addressing, DOP/TOP can now also be written as NOP.
Unless using implied addressing, DOP/TOP can also be written as NOP.
***) ANE and LXA first perform an ORA with an arbitrary(!) value and
then perform an AND with the given argument. So they are unstable and
@ -79,10 +80,8 @@ ACME will output a warning if these opcodes get assembled with a
nonzero argument.
There is no guarantee that these opcodes actually work on a given 6502
(or 6510, or 8500, or 8502) CPU. But as far as I know, nobody ever
found an unmodified C64/C128 where these illegals didn't work. That's
why I used "6510" as the CPU keyword instead of "6502illegal" or
something like that.
(or 6510, or 8500, or 8501, or 8502) CPU. But as far as I know, nobody
ever found an unmodified C64/C128 where these illegals didn't work.
These illegals will definitely *not* work on 65c02 and 65816 CPUs. But
I really should not have to tell you that ;)
@ -92,7 +91,7 @@ people use different names for them. I hope my choices are not too
exotic for your taste.
Just for the sake of completeness: Here are all the remaining opcodes
(the ones ACME won't generate even with "6510" cpu):
(the ones ACME won't generate even with "nmos6502" cpu chosen):
Opcode| Description C64DTV2
------+--------------------------------------------------------------
@ -137,7 +136,10 @@ For more information about what these opcodes do, see these documents:
Extra Instructions Of The 65XX Series CPU, Adam Vardy, 27 Sept. 1996
6502 Undocumented Opcodes, by Freddy Offenga, 5/17/1997
AAY64 (All About Your 64)
and the most comprehensive work is:
"No More Secrets - NMOS 6510 Unintended Opcodes"
Download it from https://csdb.dk/release/?id=185341
...but the most comprehensive work is:
"No More Secrets - NMOS 6510 Unintended Opcodes"
Download it from https://csdb.dk/release/?id=185341
or ask google for the latest version.

View File

@ -106,6 +106,10 @@ 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 a '@' character.
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
@ -113,6 +117,7 @@ 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
@ -149,7 +154,7 @@ found in the file "AllPOs.txt". Here's just a short overview:
!convtab !pet !raw !scr !scrxor !text
...for converting and outputting strings.
!do !endoffile !for !if !ifdef !ifndef !set
!do !endoffile !for !if !ifdef !ifndef !set !while
...for flow control; looping assembly and conditional assembly.
!binary !source !to
@ -170,7 +175,7 @@ found in the file "AllPOs.txt". Here's just a short overview:
!warn !error !serious
...for generating warnings, errors and serious errors.
!addr
!address
...to mark symbols as addresses, for the optional type check system.
@ -276,6 +281,8 @@ Available options are:
-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...
-Wtype-mismatch
Enables type checking system (warns about wrong types).
@ -296,6 +303,15 @@ Available options are:
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.
@ -389,8 +405,8 @@ $d011 hexadecimal values are indicated by either a
more readable, especially when building bitmapped
objects (like C64 sprites or fonts) in your source
code.
"p" character values are indicated by double or single
'q' quotes. The actual numeric value depends on the
'p' character values are indicated by single or double
"q" quotes. The actual numeric value depends on the
current conversion table (none/petscii/screen),
chosen using the "!ct" pseudo opcode.
poll_joy2 a global symbol

View File

@ -695,7 +695,7 @@ static void list_append_list(struct listitem *selfhead, struct listitem *otherhe
struct listitem *item;
if (selfhead == otherhead)
Bug_found("ExtendingListWithItself", 0); // TODO - add to docs!
Bug_found("ExtendingListWithItself", 0);
item = otherhead->next;
while (item != otherhead) {
list_append_object(selfhead, &item->u.payload);
@ -1659,7 +1659,7 @@ static void number_handle_monadic_operator(struct object *self, const struct op
float_handle_monadic_operator(self, op);
break;
default:
Bug_found("IllegalNumberType1", self->u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType1", self->u.number.ntype);
}
}
@ -2101,7 +2101,7 @@ static void number_handle_dyadic_operator(struct object *self, const struct op *
else if (self->u.number.ntype == NUMTYPE_FLOAT)
float_handle_dyadic_operator(self, op, other);
else
Bug_found("IllegalNumberType2", self->u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType2", self->u.number.ntype);
}
@ -2122,7 +2122,7 @@ static int get_valid_index(int *target, int length, const struct object *self, c
if (other->u.number.ntype == NUMTYPE_FLOAT)
float_to_int(other);
if (other->u.number.ntype != NUMTYPE_INT)
Bug_found("IllegalNumberType3", other->u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType3", other->u.number.ntype);
index = other->u.number.val.intval;
// negative indices access from the end
@ -2279,7 +2279,7 @@ static void number_fix_result(struct object *self)
&& (self->u.number.val.fpval >= -128.0))
self->u.number.flags |= NUMBER_FITS_BYTE; // FIXME - what for? isn't this flag only of use when undefined?
} else {
Bug_found("IllegalNumberType4", self->u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType4", self->u.number.ntype);
}
}
@ -2307,7 +2307,7 @@ static void number_print(const struct object *self, struct dynabuf *db)
sprintf(buffer, "%.30g", self->u.number.val.fpval);
DynaBuf_add_string(db, buffer);
} else {
Bug_found("IllegalNumberType5", self->u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType5", self->u.number.ntype);
}
}
@ -2480,7 +2480,7 @@ void ALU_any_int(intval_t *target) // ACCEPT_UNDEFINED
else if (expression.result.u.number.ntype == NUMTYPE_FLOAT)
*target = expression.result.u.number.val.fpval;
else
Bug_found("IllegalNumberType6", expression.result.u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType6", expression.result.u.number.ntype);
} else {
*target = 0;
Throw_error(exception_not_number);
@ -2510,13 +2510,13 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
Throw_serious_error(exception_no_value);
if (expression.result.type == &type_number) {
if (expression.result.u.number.ntype == NUMTYPE_UNDEFINED) {
Throw_serious_error(exception_value_not_defined);
Throw_serious_error("Value not defined.");
} else if (expression.result.u.number.ntype == NUMTYPE_INT) {
// ok
} else if (expression.result.u.number.ntype == NUMTYPE_FLOAT) {
float_to_int(&expression.result);
} else {
Bug_found("IllegalNumberType7", expression.result.u.number.ntype); // FIXME - add to docs!
Bug_found("IllegalNumberType7", expression.result.u.number.ntype);
}
} else {
Throw_serious_error(exception_not_number);
@ -2548,7 +2548,7 @@ void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFI
// FIXME - throw a warning?
string_to_byte(&(expression->result), 0);
} else {
Throw_error("String length is not 1."); // FIXME - add to docs!
Throw_error("String length is not 1.");
}
} else {
Throw_error(exception_not_number);

View File

@ -57,7 +57,6 @@ const char exception_number_out_of_range[] = "Number out of range.";
const char exception_pc_undefined[] = "Program counter undefined.";
const char exception_symbol_defined[] = "Symbol already defined.";
const char exception_syntax[] = "Syntax error.";
const char exception_value_not_defined[] = "Value not defined.";
// default value for number of errors before exiting
#define MAXERRORS 10

View File

@ -46,7 +46,6 @@ extern const char exception_number_out_of_range[];
extern const char exception_pc_undefined[];
extern const char exception_symbol_defined[];
extern const char exception_syntax[];
extern const char exception_value_not_defined[];
// byte flags table
extern const char global_byte_flags[];
#define BYTE_STARTS_KEYWORD(b) (global_byte_flags[(unsigned char) b] & (1u << 7)) // byte is allowed at start of keyword (a-z, A-Z, _, everything>127)