mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-01-10 21:30:30 +00:00
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:
parent
7f736ceccb
commit
1261960cad
@ -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
|
||||
|
185
docs/AllPOs.txt
185
docs/AllPOs.txt
@ -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,20 +916,22 @@ 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
|
||||
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.
|
||||
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
||||
...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.
|
||||
|
@ -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
|
||||
|
20
src/alu.c
20
src/alu.c
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user