mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-08-31 23:30:32 +00:00
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:
parent
62dd48ab9f
commit
465da8c139
@ -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.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
73
src/global.c
73
src/global.c
@ -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);
|
||||
// }
|
||||
}
|
||||
|
@ -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[];
|
||||
|
93
src/mnemo.c
93
src/mnemo.c
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
14
testing/errors/outofrange.a
Normal file
14
testing/errors/outofrange.a
Normal 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
|
Loading…
Reference in New Issue
Block a user