From 465da8c1394eca668e7320e81144bff01a56a42e Mon Sep 17 00:00:00 2001 From: marcobaye Date: Sat, 18 Jul 2020 13:50:46 +0000 Subject: [PATCH] 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 --- docs/65816.txt | 10 ++-- docs/Errors.txt | 80 ++++++++++++++++--------------- docs/Upgrade.txt | 4 +- src/alu.c | 4 +- src/global.c | 73 ++++++++++++++--------------- src/global.h | 1 + src/mnemo.c | 93 +++++++++++++++++++------------------ src/pseudoopcodes.c | 4 +- src/version.h | 2 +- testing/errors/outofrange.a | 14 ++++++ 10 files changed, 152 insertions(+), 133 deletions(-) create mode 100644 testing/errors/outofrange.a diff --git a/docs/65816.txt b/docs/65816.txt index e08a9a0..1e86ce2 100644 --- a/docs/65816.txt +++ b/docs/65816.txt @@ -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. ---------------------------------------------------------------------- diff --git a/docs/Errors.txt b/docs/Errors.txt index e7a1d4a..2d2bf65 100644 --- a/docs/Errors.txt +++ b/docs/Errors.txt @@ -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. diff --git a/docs/Upgrade.txt b/docs/Upgrade.txt index 6d5f667..f406ec8 100644 --- a/docs/Upgrade.txt +++ b/docs/Upgrade.txt @@ -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: diff --git a/src/alu.c b/src/alu.c index 09f3cc1..b6bc7ac 100644 --- a/src/alu.c +++ b/src/alu.c @@ -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 } } diff --git a/src/global.c b/src/global.c index 52d6fcd..2155438 100644 --- a/src/global.c +++ b/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); -// } } diff --git a/src/global.h b/src/global.h index 2398e7a..e43fef5 100644 --- a/src/global.h +++ b/src/global.h @@ -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[]; diff --git a/src/mnemo.c b/src/mnemo.c index 7397215..c253b84 100644 --- a/src/mnemo.c +++ b/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 diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index d5d2412..53b457c 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -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); diff --git a/src/version.h b/src/version.h index 951320b..acfff7e 100644 --- a/src/version.h +++ b/src/version.h @@ -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 diff --git a/testing/errors/outofrange.a b/testing/errors/outofrange.a new file mode 100644 index 0000000..0dcf662 --- /dev/null +++ b/testing/errors/outofrange.a @@ -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