several small changes:

fixed a bug where "number out of range" error led to bogus "label already defined" errors
 made "number out of range" errors more specific (8/16/24 bit range)
 re-phrased two error messages
 cleaned up docs concerning "command/opcode/mnemonic/instruction"
 added test program to trigger "out of range" errors
 internal cleanup concerning INW/DEW/JAM mnemonics


git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@278 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2020-07-18 13:50:46 +00:00
parent 62dd48ab9f
commit 465da8c139
10 changed files with 152 additions and 133 deletions

View File

@ -12,10 +12,10 @@ ACME.
----------------------------------------------------------------------
Section: Command aliases for "long" JMPs and JSRs
Section: Aliases for "long" JMPs and JSRs
----------------------------------------------------------------------
In addition to the commands JMP and JSR, the 65816 processor also
In addition to the mnemonics JMP and JSR, the 65816 processor also
knows JML and JSL, which are JMP and JSR using new (long) addressing
modes. ACME also accepts the new addressing modes when using the old
mnemonics JMP and JSR, but the old addressing modes cannot be used
@ -55,13 +55,13 @@ this at any time using the following pseudo opcodes:
!rs ; switch to short index registers
Please note that ACME, unlike some other assemblers, does *not* track
SEP/REP commands: I don't like that method - it fails when
SEP/REP instructions: I don't like that method - it fails when
encountering PLPs, for example. So if it doesn't work reliably in the
first place, why use it? :)
If you don't like that you always have to use a pseudo opcode
alongside SEP/REP commands, then have a look at the file <65816/std.a>
(in the library). There are some predefined macros that you can use.
alongside SEP/REP instructions, then have a look at the library file
<65816/std.a> which has some predefined macros you can use.
----------------------------------------------------------------------

View File

@ -112,12 +112,12 @@ Label name starts with a shift-space character.
warning is issued.
Memory already initialised.
The "!initmem" command was given more than once (or in addition to
the "--initmem" command line option). Only use it once.
The "!initmem" pseudo opcode was given more than once, or in
addition to the "--initmem" command line option. Only use it once.
Output file already chosen.
The "!to" command was given more than once (or in addition to the
"--outfile" command line option). Only use it once.
The "!to" pseudo opcode was given more than once, or in addition
to the "--outfile" command line option. Only use it once.
Segment reached another one, overwriting it.
The program counter has just reached the start of another segment.
@ -129,7 +129,7 @@ Segment reached another one, overwriting it.
ACME this might become the default.
Segment starts inside another one, overwriting it.
The given value in a "*=" command is located inside another
The given value in a "*=" assignment is located inside another
segment. Because some people might want to assemble "onto" a
binary file that was loaded before, this warning can be inhibited
using modifier keywords when changing the program counter via
@ -139,8 +139,8 @@ Segment starts inside another one, overwriting it.
ACME this might become the default.
Symbol list file name already chosen.
The "!sl" command was given more than once (or in addition to the
"--symbollist" command line option). Only use it once.
The "!sl" pseudo opcode was given more than once, or in addition
to the "--symbollist" command line option. Only use it once.
Used "!to" without file format indicator. Defaulting to "cbm".
Now that "!to" can be given a file format keyword (either "plain"
@ -148,19 +148,19 @@ Used "!to" without file format indicator. Defaulting to "cbm".
works though.
Using oversized addressing mode.
ACME just assembled a command using an addressing mode that was
larger than needed. This only happens if ACME could not work out
the argument's value in the first pass, therefore assuming a 16-
bit addressing mode. If, in a later pass, ACME finds out that the
argument is small enough to fit in 8 bits, then this warning is
shown. If you define all your zeropage symbols *before* they are
first used, this shouldn't happen. If you know that a specific
ACME just assembled an instruction using an addressing mode that
was larger than needed. This only happens if ACME could not work
out the argument's value in the first pass, therefore assuming a
16-bit addressing mode. If, in a later pass, ACME finds out that
the argument is small enough to fit in 8 bits, then this warning
is shown. If you define all your zeropage symbols *before* they
are first used, this shouldn't happen. If you know that a specific
argument fits in 8 bits, you can force ACME to use 8 bits
addressing by postfixing the command with "+1". Example:
addressing by postfixing the mnemonic with "+1". Example:
lda+1 label
ACME will then use an 8-bit addressing mode, regardless of whether
the label is known or not. If the label value happens to be too
large to fit in 8 bits, ACME will show an error of course (To
large to fit in 8 bits, ACME will show an error of course (to
always truncate a value to 8 bits, use the '<' operator).
More about the postfixing method can be found in "AddrModes.txt".
@ -233,6 +233,15 @@ Conversion table incomplete.
The conversion table file is too small. It needs to be exactly 256
bytes in size.
CPU does not support this addressing mode for this mnemonic.
The given mnemonic cannot be combined with the given addressing
mode on the CPU you have chosen.
CPU does not support this postfix for this mnemonic.
The given mnemonic cannot be combined with the addressing mode
indicated by the given postfix, at least not on the CPU you have
chosen.
Division by zero.
Guess what - you attempted to divide by zero.
@ -271,14 +280,6 @@ Hex digits are not given in pairs.
The two digits of a hex byte are separated by another character,
or there is an odd number of digits.
Illegal combination of command and addressing mode.
The given command cannot be used with the given addressing mode on
the CPU you have chosen.
Illegal combination of command and postfix.
The given command cannot be used with the addressing mode
indicated by the given postfix.
Illegal postfix.
You used a postfix other than "+1", "+2" or "+3".
@ -317,8 +318,9 @@ Negative value - cannot choose addressing mode.
No string given.
ACME expects a string but doesn't find it, or the string is empty.
Number does not fit in N bits.
Number out of range.
A value is too high or too low.
A value is too high or too low to be stored in 8/16/24 bits.
This can also mean the desired addressing mode is not available,
as in "sty $e000, x".
@ -349,14 +351,14 @@ Syntax error.
Target not in bank (0xTARGET).
You tried to branch to an address not in the 0x0000..0xffff range.
Relative addressing (branch commands or PER) cannot leave the
Relative addressing (branch instructions or PER) cannot leave the
current code bank of 64 KiB.
Target out of range (N; M too far).
Branch commands use relative addressing, which only has a limited
range. You exceeded it. N is the attempted offset, M is the
difference to the limit - so if you succeed in optimizing M bytes
away, the code would assemble.
Branch instructions use relative addressing, which only has a
limited range. You exceeded it. N is the attempted offset, M is
the difference to the limit - so if you succeed in optimizing M
bytes away, the code would assemble.
The chosen CPU uses opcode 0xXY as a prefix code, do not use this mnemonic!
The mnemonic is valid, but should not be used on this CPU. If you
@ -389,7 +391,8 @@ Un-pseudopc operator '&' has no !pseudopc context.
around the definition.
Unknown encoding.
You used the "!convtab" command with a keyword ACME does not know.
You used the "!convtab" pseudo opcode with a keyword ACME does not
know.
Unknown function.
You used a mathematical function ACME does not know.
@ -398,13 +401,15 @@ Unknown operator.
You used an arithmetic/logical operator ACME does not know.
Unknown output format.
You used the "!to" command with a keyword ACME does not know.
You used the "!to" pseudo opcode with a format specifier ACME does
not know.
Unknown processor.
You used the "!cpu" command with a keyword ACME does not know.
You used the "!cpu" pseudo opcode with a cpu specifier ACME does
not know.
Unknown pseudo opcode.
You have mistyped a "!" command.
You have mistyped the keyword after "!".
Unknown "*=" segment modifier.
You used a modifier keyword ACME does not know.
@ -441,8 +446,9 @@ Found end-of-file instead of '}'.
(because there was at least one block left open).
Loop count is negative.
You used the "!for" command with a negative loop count (getting
this error is only possible when using the now deprecated syntax).
You used the "!for" pseudo opcode with a negative loop count
(getting this error is only possible when using the now deprecated
syntax).
Macro already defined.
Macros can only be defined once. If you define a macro twice, ACME
@ -452,7 +458,7 @@ Macro already defined.
Missing '{'.
ACME didn't find the expected '{' character. Remember that '{'
characters must be given on the same line as the command they
characters must be given on the same line as the keyword they
belong to.
Out of memory.

View File

@ -163,8 +163,8 @@ The mnemonic BIT can no longer be assembled without any argument. If
you want to insert the opcode only to mask the next instruction, use
!src <6502/std.a>
to get the definitions for these two macros:
+bit8 ; output $24 to mask following 1-byte command
+bit16 ; output $2c to mask following 2-byte command
+bit8 ; output $24 to mask following 1-byte instruction
+bit16 ; output $2c to mask following 2-byte instruction
When using the 65816 cpu, ACME now uses the correct argument order for
the MVN and MVP mnemonics, which is:

View File

@ -2445,8 +2445,8 @@ static int parse_expression(struct expression *expression)
// make sure no additional (spurious) errors are reported:
Input_skip_remainder();
// FIXME - remove this when new function interface gets used:
// callers must decide for themselves what to do when expression parser returns error
// (currently LDA'' results in both "no string given" AND "illegal combination of command and addressing mode"!)
// callers must decide for themselves what to do when expression
// parser returns error (and may decide to call Input_skip_remainder)
return 1; // error
}
}

View File

@ -40,7 +40,11 @@ const char exception_no_left_brace[] = "Missing '{'.";
const char exception_no_memory_left[] = "Out of memory.";
const char exception_no_right_brace[] = "Found end-of-file instead of '}'.";
//const char exception_not_yet[] = "Sorry, feature not yet implemented.";
// TODO - show actual value in error message
const char exception_number_out_of_range[] = "Number out of range.";
const char exception_number_out_of_8b_range[] = "Number does not fit in 8 bits.";
static const char exception_number_out_of_16b_range[] = "Number does not fit in 16 bits.";
static const char exception_number_out_of_24b_range[] = "Number does not fit in 24 bits.";
const char exception_pc_undefined[] = "Program counter undefined.";
const char exception_symbol_defined[] = "Symbol already defined.";
const char exception_syntax[] = "Syntax error.";
@ -507,86 +511,79 @@ void output_object(struct object *object, struct iter_context *iter)
// output 8-bit value with range check
void output_8(intval_t value)
{
if ((value <= 0xff) && (value >= -0x80))
Output_byte(value);
else
Throw_error(exception_number_out_of_range);
if ((value < -0x80) || (value > 0xff))
Throw_error(exception_number_out_of_8b_range);
Output_byte(value);
}
// output 16-bit value with range check big-endian
void output_be16(intval_t value)
{
if ((value <= 0xffff) && (value >= -0x8000)) {
Output_byte(value >> 8);
Output_byte(value);
} else {
Throw_error(exception_number_out_of_range);
}
if ((value < -0x8000) || (value > 0xffff))
Throw_error(exception_number_out_of_16b_range);
Output_byte(value >> 8);
Output_byte(value);
}
// output 16-bit value with range check little-endian
void output_le16(intval_t value)
{
if ((value <= 0xffff) && (value >= -0x8000)) {
Output_byte(value);
Output_byte(value >> 8);
} else {
Throw_error(exception_number_out_of_range);
}
if ((value < -0x8000) || (value > 0xffff))
Throw_error(exception_number_out_of_16b_range);
Output_byte(value);
Output_byte(value >> 8);
}
// output 24-bit value with range check big-endian
void output_be24(intval_t value)
{
if ((value <= 0xffffff) && (value >= -0x800000)) {
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
} else {
Throw_error(exception_number_out_of_range);
}
if ((value < -0x800000) || (value > 0xffffff))
Throw_error(exception_number_out_of_24b_range);
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
}
// output 24-bit value with range check little-endian
void output_le24(intval_t value)
{
if ((value <= 0xffffff) && (value >= -0x800000)) {
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
} else {
Throw_error(exception_number_out_of_range);
}
if ((value < -0x800000) || (value > 0xffffff))
Throw_error(exception_number_out_of_24b_range);
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
}
// FIXME - the range checks below are commented out because 32-bit
// signed integers cannot exceed the range of 32-bit signed integers.
// But now that 64-bit machines are the norm, "intval_t" might be a
// 64-bit int. I need to address this problem one way or another.
// output 32-bit value (without range check) big-endian
void output_be32(intval_t value)
{
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
// if ((value < -0x80000000) || (value > 0xffffffff))
// Throw_error(exception_number_out_of_32b_range);
Output_byte(value >> 24);
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
// } else {
// Throw_error(exception_number_out_of_range);
// }
}
// output 32-bit value (without range check) little-endian
void output_le32(intval_t value)
{
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
// if ((value < -0x80000000) || (value > 0xffffffff))
// Throw_error(exception_number_out_of_32b_range);
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
Output_byte(value >> 24);
// } else {
// Throw_error(exception_number_out_of_range);
// }
}

View File

@ -31,6 +31,7 @@ extern const char exception_no_memory_left[];
extern const char exception_no_right_brace[];
//extern const char exception_not_yet[];
extern const char exception_number_out_of_range[];
extern const char exception_number_out_of_8b_range[];
extern const char exception_pc_undefined[];
extern const char exception_symbol_defined[];
extern const char exception_syntax[];

View File

@ -54,7 +54,7 @@
// only for m65:
#define LONG_INDIRECT_Z_INDEXED_ADDRESSING (AMB_LONGINDIRECT | AMB_INDEX(INDEX_Z))
// Constant values, used to mark the possible parameter lengths of commands.
// constant values, used to mark the possible parameter lengths of instructions.
// Not all of the eight possible combinations are actually used, however (because of the supported CPUs).
#define MAYBE______ 0
#define MAYBE_1____ NUMBER_FORCES_8
@ -71,10 +71,13 @@ enum mnemogroup {
GROUP_BITBRANCH, // bbr0..7 and bbs0..7 Byte value = opcode
GROUP_REL16_2, // 16bit relative to pc+2 Byte value = opcode
GROUP_REL16_3, // 16bit relative to pc+3 Byte value = opcode
GROUP_BOTHMOVES, // the "move" commands MVP and MVN Byte value = opcode
GROUP_ZPONLY, // rmb0..7 and smb0..7 Byte value = opcode FIXME - use for IDXeDEW,IDXeINW as well!
GROUP_BOTHMOVES, // the "move" instructions MVP and MVN Byte value = opcode
GROUP_ZPONLY, // rmb0..7, smb0..7, inw, dew Byte value = opcode
GROUP_PREFIX, // NOP on m65 (throws error) Byte value = opcode
};
// TODO: make sure groups like IMPLIEDONLY and ZPONLY output
// "Mnemonic does not support this addressing mode" instead of
// "Garbage data at end of statement".
// save some space
#define SCB static const unsigned char
@ -109,13 +112,13 @@ SCB accu_lindz8[] = { 0, 0, 0, 0, 0x12, 0, 0,
// mnemotable), the assembler finds out the column to use here. The row
// depends on the used addressing mode. A zero entry in these tables means
// that the combination of mnemonic and addressing mode is illegal.
// | 6502 | 6502/65c02/65ce02 | 65c02 | 65ce02 | 65816 | NMOS 6502 undocumented opcodes | C64DTV2 |
enum { IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_LDY,IDX_LDX,IDX_CPY,IDX_CPX,IDX_BIT,IDXcBIT,IDX_STX,IDXeSTX,IDX_STY,IDXeSTY,IDX_DEC,IDXcDEC,IDX_INC,IDXcINC,IDXcTSB,IDXcTRB,IDXcSTZ,IDXeASR,IDXeASW,IDXeCPZ,IDXeDEW,IDXeINW,IDXeLDZ,IDXePHW,IDXeROW,IDXeRTN,IDX16COP,IDX16REP,IDX16SEP,IDX16PEA,IDXuANC,IDXuASR,IDXuARR,IDXuSBX,IDXuNOP,IDXuDOP,IDXuTOP,IDXuJAM,IDXuLXA,IDXuANE,IDXuLAS,IDXuTAS,IDXuSHX,IDXuSHY,IDX_SAC,IDX_SIR};
SCB misc_impl[] = { 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0, 0x1a, 0, 0, 0, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x80, 0x0c, 0x02, 0, 0, 0, 0, 0, 0, 0, 0}; // implied/accu
SCB misc_imm[] = { 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0x89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc2, 0, 0, 0xa3, 0xf4, 0, 0x62, 0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0x80, 0, 0, 0xab, 0x8b, 0, 0, 0, 0, 0x32, 0x42}; // #$ff #$ffff
SCS misc_abs[] = { 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0x2c24, 0x2c24, 0x8e86, 0x8e86, 0x8c84, 0x8c84, 0xcec6, 0xcec6, 0xeee6, 0xeee6, 0x0c04, 0x1c14, 0x9c64, 0x44, 0xcb00, 0xdcd4, 0xc3, 0xe3, 0xab00, 0xfc00, 0xeb00, 0, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x0c04, 0x04, 0x0c00, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff $ffff
SCS misc_xabs[] = { 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0xbcb4, 0, 0, 0, 0, 0x3c34, 0, 0, 0x94, 0x8b94, 0xded6, 0xded6, 0xfef6, 0xfef6, 0, 0, 0x9e74, 0x54, 0, 0, 0, 0, 0xbb00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c14, 0x14, 0x1c00, 0, 0, 0, 0, 0, 0, 0x9c00, 0, 0}; // $ff,x $ffff,x
SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0xbeb6, 0, 0, 0, 0, 0x96, 0x9b96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbb00, 0x9b00, 0x9e00, 0, 0, 0}; // $ff,y $ffff,y
// | 6502 | 6502/65c02/65ce02 | 65c02 | 65ce02 | 65816 | NMOS 6502 undocumented opcodes | C64DTV2 |
enum { IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_LDY,IDX_LDX,IDX_CPY,IDX_CPX,IDX_BIT,IDXcBIT,IDX_STX,IDXeSTX,IDX_STY,IDXeSTY,IDX_DEC,IDXcDEC,IDX_INC,IDXcINC,IDXcTSB,IDXcTRB,IDXcSTZ,IDXeASR,IDXeASW,IDXeCPZ,IDXeLDZ,IDXePHW,IDXeROW,IDXeRTN,IDX16COP,IDX16REP,IDX16SEP,IDX16PEA,IDXuANC,IDXuASR,IDXuARR,IDXuSBX,IDXuNOP,IDXuDOP,IDXuTOP,IDXuLXA,IDXuANE,IDXuLAS,IDXuTAS,IDXuSHX,IDXuSHY,IDX_SAC,IDX_SIR};
SCB misc_impl[] = { 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0, 0x1a, 0, 0, 0, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x80, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0}; // implied/accu
SCB misc_imm[] = { 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0x89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc2, 0xa3, 0xf4, 0, 0x62, /*2?*/0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0x80, 0, 0xab, 0x8b, 0, 0, 0, 0, 0x32, 0x42}; // #$ff #$ffff
SCS misc_abs[] = { 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0x2c24, 0x2c24, 0x8e86, 0x8e86, 0x8c84, 0x8c84, 0xcec6, 0xcec6, 0xeee6, 0xeee6, 0x0c04, 0x1c14, 0x9c64, 0x44, 0xcb00, 0xdcd4, 0xab00, 0xfc00, 0xeb00, 0, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x0c04, 0x04, 0x0c00, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff $ffff
SCS misc_xabs[] = { 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0xbcb4, 0, 0, 0, 0, 0x3c34, 0, 0, 0x94, 0x8b94, 0xded6, 0xded6, 0xfef6, 0xfef6, 0, 0, 0x9e74, 0x54, 0, 0, 0xbb00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c14, 0x14, 0x1c00, 0, 0, 0, 0, 0, 0x9c00, 0, 0}; // $ff,x $ffff,x
SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0xbeb6, 0, 0, 0, 0, 0x96, 0x9b96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbb00, 0x9b00, 0x9e00, 0, 0, 0}; // $ff,y $ffff,y
// Code tables for group GROUP_ALLJUMPS:
// These tables are needed for finding out the correct code when the mnemonic
@ -136,7 +139,7 @@ SCS jump_lind[] = { 0, 0, 0xdc00, 0, 0, 0, 0xdc00,
#undef SCL
// error message strings
static const char exception_illegal_combination[] = "Illegal combination of command and addressing mode.";
static const char exception_illegal_combination[] = "CPU does not support this addressing mode for this mnemonic.";
static const char exception_oversized_addrmode[] = "Using oversized addressing mode.";
@ -157,7 +160,7 @@ static struct ronode *mnemo_aug_tree = NULL; // CSG 65ce02's "aug" instruction
static struct ronode *mnemo_map_eom_tree = NULL; // CSG 4502's "map" and "eom" instructions
static struct ronode *mnemo_m65_tree = NULL; // MEGA65 extensions
// Command's code, flags and group values are stored together in a single integer.
// mnemonic's code, flags and group values are stored together in a single integer.
// ("code" is either a table index or the opcode itself, depending on group value)
// To extract the code, use "& CODEMASK".
// To extract the flags, use "& FLAGSMASK".
@ -257,11 +260,9 @@ static struct ronode mnemos_6502undoc1[] = {
PREDEFNODE("nop", MERGE(GROUP_MISC, IDXuNOP)), // combines documented $ea and the undocumented dop/top below
PREDEFNODE("dop", MERGE(GROUP_MISC, IDXuDOP)), // "double nop" (skip next byte)
PREDEFNODE("top", MERGE(GROUP_MISC, IDXuTOP)), // "triple nop" (skip next word)
// FIXME: make sure GROUP_IMPLIEDONLY outputs "Illegal combination of command and addressing mode" instead of "Garbage data at end of statement",
// and then remove IDXuJAM column from table and change next line to "GROUP_IMPLIEDONLY, 0x02".
PREDEFNODE("jam", MERGE(GROUP_MISC, IDXuJAM)), // jam/crash/kill/halt-and-catch-fire
PREDEFNODE("ane", MERGE(GROUP_MISC, IDXuANE)), // A = (A | ??) & X & arg (aka XAA)
PREDEFLAST("lxa", MERGE(GROUP_MISC, IDXuLXA)), // A,X = (A | ??) & arg (aka OAL aka ATX)
PREDEFNODE("lxa", MERGE(GROUP_MISC, IDXuLXA)), // A,X = (A | ??) & arg (aka OAL aka ATX)
PREDEFLAST("jam", MERGE(GROUP_IMPLIEDONLY, 0x02)), // jam/crash/kill/halt-and-catch-fire
// ^^^^ this marks the last element
};
@ -350,7 +351,7 @@ static struct ronode mnemos_stp_wai[] = {
// ^^^^ this marks the last element
};
// most of the 65816 stuff
// the 65816 stuff
static struct ronode mnemos_65816[] = {
// CAUTION - these use 6502/65c02 indices, because the opcodes are the same - but I need flags for immediate mode!
PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY | IM_INDEXREGS)),
@ -433,8 +434,8 @@ static struct ronode mnemos_65ce02[] = {
PREDEFNODE("asr", MERGE(GROUP_MISC, IDXeASR)),
PREDEFNODE("asw", MERGE(GROUP_MISC, IDXeASW)),
PREDEFNODE("cpz", MERGE(GROUP_MISC, IDXeCPZ)),
PREDEFNODE("dew", MERGE(GROUP_MISC, IDXeDEW)),
PREDEFNODE("inw", MERGE(GROUP_MISC, IDXeINW)),
PREDEFNODE("dew", MERGE(GROUP_ZPONLY, 0xc3)),
PREDEFNODE("inw", MERGE(GROUP_ZPONLY, 0xe3)),
PREDEFNODE("ldz", MERGE(GROUP_MISC, IDXeLDZ)),
PREDEFNODE("phw", MERGE(GROUP_MISC, IDXePHW | IM_FORCE16)), // when using immediate addressing, arg is 16 bit
PREDEFNODE("row", MERGE(GROUP_MISC, IDXeROW)),
@ -682,18 +683,18 @@ static bits calc_arg_size(bits force_bit, struct number *argument, bits addressi
Throw_error(exception_illegal_combination);
return 0;
}
// if command has force bit, act upon it
// if a force bit postfix was given, act upon it
if (force_bit) {
// if command allows this force bit, return it
// if mnemonic supports this force bit, return it
if (addressing_modes & force_bit)
return force_bit;
// if not, complain
Throw_error("Illegal combination of command and postfix.");
Throw_error("CPU does not support this postfix for this mnemonic.");
return 0;
}
// Command has no force bit. Check whether value has one
// mnemonic did not have a force bit postfix.
// if value has force bit, act upon it
if (argument->flags & NUMBER_FORCEBITS) {
// Value has force bit set, so return this or bigger size
@ -844,7 +845,7 @@ static void far_branch(int preoffset)
// set addressing mode bits depending on which opcodes exist, then calculate
// argument size and output both opcode and argument
static void make_command(bits force_bit, struct number *result, unsigned long opcodes)
static void make_instruction(bits force_bit, struct number *result, unsigned long opcodes)
{
int addressing_modes = MAYBE______;
@ -925,52 +926,52 @@ static void group_main(int index, bits flags)
immediate_opcodes = imm_ops(&force_bit, accu_imm[index], flags & IMMASK);
// CAUTION - do not incorporate the line above into the line
// below - "force_bit" might be undefined (depends on compiler).
make_command(force_bit, &result, immediate_opcodes);
make_instruction(force_bit, &result, immediate_opcodes);
break;
case ABSOLUTE_ADDRESSING: // $ff, $ffff, $ffffff
make_command(force_bit, &result, accu_abs[index]);
make_instruction(force_bit, &result, accu_abs[index]);
break;
case X_INDEXED_ADDRESSING: // $ff,x, $ffff,x, $ffffff,x
make_command(force_bit, &result, accu_xabs[index]);
make_instruction(force_bit, &result, accu_xabs[index]);
break;
case Y_INDEXED_ADDRESSING: // $ffff,y (in theory, "$ff,y" as well)
make_command(force_bit, &result, accu_yabs[index]);
make_instruction(force_bit, &result, accu_yabs[index]);
break;
case STACK_INDEXED_ADDRESSING: // $ff,s
make_command(force_bit, &result, accu_sabs8[index]);
make_instruction(force_bit, &result, accu_sabs8[index]);
break;
case X_INDEXED_INDIRECT_ADDRESSING: // ($ff,x)
make_command(force_bit, &result, accu_xind8[index]);
make_instruction(force_bit, &result, accu_xind8[index]);
break;
case INDIRECT_ADDRESSING: // ($ff)
make_command(force_bit, &result, accu_ind8[index]);
make_instruction(force_bit, &result, accu_ind8[index]);
check_zp_wraparound(&result);
break;
case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y
make_command(force_bit, &result, accu_indy8[index]);
make_instruction(force_bit, &result, accu_indy8[index]);
check_zp_wraparound(&result);
break;
case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z only for 65ce02/4502/m65
make_command(force_bit, &result, accu_indz8[index]);
make_instruction(force_bit, &result, accu_indz8[index]);
check_zp_wraparound(&result);
break;
case LONG_INDIRECT_ADDRESSING: // [$ff] for 65816 and m65
// if in quad mode, m65 encodes this as NOP + ($ff),z
if (flags & LI_PREFIX_NOP)
Output_byte(0xea);
make_command(force_bit, &result, accu_lind8[index]);
make_instruction(force_bit, &result, accu_lind8[index]);
break;
case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y only for 65816
make_command(force_bit, &result, accu_lindy8[index]);
make_instruction(force_bit, &result, accu_lindy8[index]);
break;
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y only for 65816 and 65ce02/4502/m65
make_command(force_bit, &result, accu_sindy8[index]);
make_instruction(force_bit, &result, accu_sindy8[index]);
break;
case LONG_INDIRECT_Z_INDEXED_ADDRESSING: // [$ff],z only for m65
// if not in quad mode, m65 encodes this as NOP + ($ff),z
if (flags & LI_PREFIX_NOP)
Output_byte(0xea);
make_command(force_bit, &result, accu_lindz8[index]);
make_instruction(force_bit, &result, accu_lindz8[index]);
break;
default: // other combinations are illegal
Throw_error(exception_illegal_combination);
@ -995,7 +996,7 @@ static void group_misc(int index, bits immediate_mode)
immediate_opcodes = imm_ops(&force_bit, misc_imm[index], immediate_mode);
// CAUTION - do not incorporate the line above into the line
// below - "force_bit" might be undefined (depends on compiler).
make_command(force_bit, &result, immediate_opcodes);
make_instruction(force_bit, &result, immediate_opcodes);
// warn about unstable ANE/LXA (undocumented opcode of NMOS 6502)?
if ((CPU_state.type->flags & CPUFLAG_8B_AND_AB_NEED_0_ARG)
&& (result.ntype == NUMTYPE_INT)
@ -1007,13 +1008,13 @@ static void group_misc(int index, bits immediate_mode)
}
break;
case ABSOLUTE_ADDRESSING: // $ff or $ffff
make_command(force_bit, &result, misc_abs[index]);
make_instruction(force_bit, &result, misc_abs[index]);
break;
case X_INDEXED_ADDRESSING: // $ff,x or $ffff,x
make_command(force_bit, &result, misc_xabs[index]);
make_instruction(force_bit, &result, misc_xabs[index]);
break;
case Y_INDEXED_ADDRESSING: // $ff,y or $ffff,y
make_command(force_bit, &result, misc_yabs[index]);
make_instruction(force_bit, &result, misc_yabs[index]);
break;
default: // other combinations are illegal
Throw_error(exception_illegal_combination);
@ -1119,10 +1120,10 @@ static void group_jump(int index)
switch (get_addr_mode(&result)) {
case ABSOLUTE_ADDRESSING: // absolute16 or absolute24
make_command(force_bit, &result, jump_abs[index]);
make_instruction(force_bit, &result, jump_abs[index]);
break;
case INDIRECT_ADDRESSING: // ($ffff)
make_command(force_bit, &result, jump_ind[index]);
make_instruction(force_bit, &result, jump_ind[index]);
// check whether to warn about 6502's JMP() bug
if ((result.ntype == NUMTYPE_INT)
&& ((result.val.intval & 0xff) == 0xff)
@ -1130,10 +1131,10 @@ static void group_jump(int index)
Throw_warning("Assembling buggy JMP($xxff) instruction");
break;
case X_INDEXED_INDIRECT_ADDRESSING: // ($ffff,x)
make_command(force_bit, &result, jump_xind[index]);
make_instruction(force_bit, &result, jump_xind[index]);
break;
case LONG_INDIRECT_ADDRESSING: // [$ffff]
make_command(force_bit, &result, jump_lind[index]);
make_instruction(force_bit, &result, jump_lind[index]);
break;
default: // other combinations are illegal
Throw_error(exception_illegal_combination);
@ -1185,7 +1186,7 @@ static boolean check_mnemo_tree(struct ronode *tree, struct dynabuf *dyna_buf)
case GROUP_BOTHMOVES: // "mvp" and "mvn"
group_mvn_mvp(code);
break;
case GROUP_ZPONLY: // "rmb0..7" and "smb0..7"
case GROUP_ZPONLY: // "rmb0..7", "smb0..7", "inw", "dew"
group_only_zp(code);
break;
case GROUP_PREFIX: // NOP for m65 cpu

View File

@ -102,7 +102,7 @@ static enum eos po_initmem(void)
// get value
ALU_defined_int(&intresult);
if ((intresult.val.intval > 255) || (intresult.val.intval < -128))
Throw_error(exception_number_out_of_range);
Throw_error(exception_number_out_of_8b_range);
if (output_initmem(intresult.val.intval & 0xff))
return SKIP_REMAINDER;
return ENSURE_EOS;
@ -118,7 +118,7 @@ static enum eos po_xor(void)
old_value = output_get_xor();
ALU_any_int(&change);
if ((change > 255) || (change < -128)) {
Throw_error(exception_number_out_of_range);
Throw_error(exception_number_out_of_8b_range);
change = 0;
}
output_set_xor(old_value ^ change);

View File

@ -9,7 +9,7 @@
#define RELEASE "0.97" // update before release FIXME
#define CODENAME "Zem" // update before release
#define CHANGE_DATE "12 Jul" // update before release FIXME
#define CHANGE_DATE "18 Jul" // update before release FIXME
#define CHANGE_YEAR "2020" // update before release
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME

View File

@ -0,0 +1,14 @@
;ACME 0.97
*=$1000
; these must throw errors:
!by -129, 256
!wo -32769, 65536
!24 -0x800001, 16777216
; 32-bit values are not range checked atm:
!32 -0x80000001, 0x100000000
; these must work:
!by -128, 255
!wo -32768, 65535
!24 -0x800000, 16777215
!32 -0x80000000, 0xffffffff