diff --git a/docs/AllPOs.txt b/docs/AllPOs.txt index de4c33c..b9cd335 100644 --- a/docs/AllPOs.txt +++ b/docs/AllPOs.txt @@ -817,13 +817,17 @@ Purpose: Select the processor to produce code for. If this PO the previously chosen CPU value is restored afterwards. Parameters: KEYWORD: Currently valid keywords are: - 6502 mnemonics and addressing modes of 6502 cpu - 65c02 superset of 6502, adds 65c02 extensions - 65816 superset of 65c02, adds 65816 extensions - 6510 superset of 6502, adds mnemonics for - undocumented opcodes - c64dtv2 superset of 6510, adds mnemonics for DTV2 - extensions (BRA/SAC/SIR) + 6502 for the original MOS 6502 + 6510 6502 plus undocumented opcodes + 65c02 6502 plus BRA,PHX/Y,PLX/Y,STZ,TRB/TSB + r65c02 65c02 plus BBRx, BBSx, RMBx, SMBx + w65c02 r65c02 plus STP/WAI + 65816 65c02 plus 16/24-bit extensions + 65ce02 r65c02 plus Z reg, long branches, ... + 4502 65ce02 with MAP instead of AUG + c64dtv2 6502 plus BRA/SAC/SIR plus some of the + undocumented opcodes + See "docs/cputypes.txt" for more info. BLOCK: A block of assembler statements. Examples: !if cputype = $65c02 { !cpu 65c02 { ; temporarily allow 65c02 stuff diff --git a/docs/Changes.txt b/docs/Changes.txt index 20030a3..e03b0a4 100644 --- a/docs/Changes.txt +++ b/docs/Changes.txt @@ -12,6 +12,16 @@ platform used. There should be another help file in this archive outlining the platform specific changes. +---------------------------------------------------------------------- +Section: New in release 0.96 +---------------------------------------------------------------------- + +Added experimental support for instruction sets of Rockwell 65C02, + WDC 65C02(S), CSG 65CE02 and CSG 4502. +Stack indexing can now be given either as ",s" or as ",sp" (only + relevant for 65816 and 65CE02). + + ---------------------------------------------------------------------- Section: New in release 0.95.8 ---------------------------------------------------------------------- diff --git a/docs/Errors.txt b/docs/Errors.txt index 171d5d7..a0c54b4 100644 --- a/docs/Errors.txt +++ b/docs/Errors.txt @@ -71,6 +71,12 @@ Found new "!for" syntax. When using the "-Wno-old-for" switch to disable the warning about the older syntax, the new syntax will trigger this warning. +Found SED instruction for CPU with known decimal SBC bug. + This warning is only ever given for CPU types 65ce02 and 4502, + because they are known to be buggy in decimal mode. + Pavel Zima and Eric Smith found an example where $41 minus $08 + gave $39 instead of $33. + Label name not in leftmost column. A label definition has blanks before the label name. Imagine this source code: @@ -408,6 +414,10 @@ IllegalBlockTerminator IllegalOperatorHandle The expression parser found an operator that does not exist. +IllegalImmediateMode + The mnemonic tree contains invalid info about the size of immediate + arguments. + OperandStackNotEmpty The expression parser has finished though there are still operands left to parse. diff --git a/docs/cputypes.txt b/docs/cputypes.txt new file mode 100644 index 0000000..bdece96 --- /dev/null +++ b/docs/cputypes.txt @@ -0,0 +1,129 @@ + + + ACME + + ...the ACME Crossassembler for Multiple Environments + + --- cpu types --- + + +ACME supports the following cpu types: + + + + +*** 6502 + +This is the instruction set of the original NMOS 6502 designed by MOS +(later CSG). +There are 151 documented opcodes. + + + + +*** 6510 + +This is the 6502 variant used in the C64 computer. It uses the same +instruction set as the 6502, but in addition to that, ACME supports +most of the undocumented opcodes as well. +See docs/Illegals.txt for more info. + + + + +*** 65c02 + +This is the CMOS re-design of the 6502. It seems to have also been +available from Rockwell, GTE/CMD and others. Features: +- new instructions: + BRA (branch always) + PHX, PHY, PLX, PLY (push/pull X/Y register) + STZ (store zero, 4 addr modes) + TRB (test and reset bits, 2 addr modes) + TSB (test and set bits, 2 addr modes) +- new addressing modes for existing instructions: + BIT #$12 + BIT $12, x + BIT $1234, x + LDA/STA/ADC/SBC ($12) (zp indirect without index) + AND/ORA/EOR/CMP ($12) (zp indirect without index) + INC (increment accumulator) + DEC (decrement accumulator) + JMP ($1234,x) (jump indexed indirect) +- bugfix for flags in decimal mode +- bugfix for JMP($xxff) instruction +- undocumented opcodes are NOPs (although of different lengths) +There are 178 documented opcodes. + + + +*** r65c02 + +This is a superset of 65c02, probably originally from Rockwell. +- It adds bit manipulation instructions: + BBR0..BBR7 (branch on bit reset) + BBS0..BBS7 (branch on bit set) + RMB0..RMB7 (reset memory bit) + SMB0..SMB7 (set memory bit) +Chips with this instruction set seem to have been available from +Rockwell, GTE/CMD and others. +There are 210 documented opcodes. + + + +*** w65c02 + +This is a superset of r65c02, originating at WDC. +- It adds the STP and WAI instructions. +There are 212 documented opcodes. + + + +*** 65816 + +This is a superset of 65c02, originally designed by WDC (it seems to +have been available from GTE/CMD as well). Features: +- register sizes can be changed to 16-bit +- 24-bit address space +- several new addressing modes +- block transfers +There are 256 documented opcodes, but one of them ("WDM") is reserved +for future expansion. + + + +*** 65ce02 + +This is a superset of r65c02, originating at CSG. Features: +- Z register +- 16-bit stack pointer +- 16-bit branches +- a few 16-bit instructions +- new addressing modes +There is a known bug: SBC does not work corrently in decimal mode. +There are 256 documented opcodes, but one of them ("AUG") is reserved +for future expansion. + + + +*** 4502 + +This is basically the same as 65ce02, but +- MAP replaces AUG +- EOM is synonymous to NOP +This cpu core can be found in the CSG4510 chip in the C65. +There are 256 documented opcodes. + + + +*** c64dtv2 + +This is the cpu in version 2 of the C64DTV. It uses a superset of the +6502 instruction set. Features: +- new instructions: + BRA $1234 (branch always) + SAC #$12 (set accumulator mapping) + SIR #$12 (set index register mapping) +- support for some of the undocumented opcodes. + + diff --git a/src/_amiga.h b/src/_amiga.h index 5e398e6..315b601 100644 --- a/src/_amiga.h +++ b/src/_amiga.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for AmigaOS) diff --git a/src/_dos.c b/src/_dos.c index 3e83098..6ba973a 100644 --- a/src/_dos.c +++ b/src/_dos.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for DOS, OS/2 and Windows) diff --git a/src/_dos.h b/src/_dos.h index 0d5b099..4e3c288 100644 --- a/src/_dos.h +++ b/src/_dos.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for DOS, OS/2 and Windows) diff --git a/src/_riscos.c b/src/_riscos.c index 03dd3ff..ce28753 100644 --- a/src/_riscos.c +++ b/src/_riscos.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for RISC OS) diff --git a/src/_riscos.h b/src/_riscos.h index d3a6b62..bea08a6 100644 --- a/src/_riscos.h +++ b/src/_riscos.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for RISC OS) diff --git a/src/_std.c b/src/_std.c index 25f1509..9fac2df 100644 --- a/src/_std.c +++ b/src/_std.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for unknown OSes) diff --git a/src/_std.h b/src/_std.h index 23f30e8..ecddf64 100644 --- a/src/_std.h +++ b/src/_std.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff (in this case, for unknown OSes) diff --git a/src/acme.c b/src/acme.c index 8f91d88..b2e35fe 100644 --- a/src/acme.c +++ b/src/acme.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // // This program is free software; you can redistribute it and/or modify diff --git a/src/acme.h b/src/acme.h index 619ad25..3296501 100644 --- a/src/acme.h +++ b/src/acme.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Main definitions diff --git a/src/alu.c b/src/alu.c index 7a8716d..b259d40 100644 --- a/src/alu.c +++ b/src/alu.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/alu.h b/src/alu.h index cffb43b..1eef42b 100644 --- a/src/alu.h +++ b/src/alu.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/cliargs.c b/src/cliargs.c index 955d2c0..9ba7232 100644 --- a/src/cliargs.c +++ b/src/cliargs.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // CLI argument stuff diff --git a/src/cliargs.h b/src/cliargs.h index aa1efad..10a7ef2 100644 --- a/src/cliargs.h +++ b/src/cliargs.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // CLI argument stuff diff --git a/src/config.h b/src/config.h index 55c7cd4..535f15e 100644 --- a/src/config.h +++ b/src/config.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/cpu.c b/src/cpu.c index 222638b..41afad5 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // @@ -16,42 +16,50 @@ // constants static struct cpu_type cpu_type_6502 = { - keyword_is_6502mnemo, + keyword_is_6502_mnemo, CPUFLAG_INDIRECTJMPBUGGY, // JMP ($xxFF) is buggy 234 // !align fills with "NOP" }; static struct cpu_type cpu_type_6510 = { - keyword_is_6510mnemo, + keyword_is_6510_mnemo, CPUFLAG_INDIRECTJMPBUGGY | CPUFLAG_8B_AND_AB_NEED_0_ARG, // JMP ($xxFF) is buggy, ANE/LXA #$xx are unstable unless arg is $00 234 // !align fills with "NOP" }; static struct cpu_type cpu_type_c64dtv2 = { - keyword_is_c64dtv2mnemo, + keyword_is_c64dtv2_mnemo, CPUFLAG_INDIRECTJMPBUGGY | CPUFLAG_8B_AND_AB_NEED_0_ARG, // JMP ($xxFF) is buggy, ANE/LXA #$xx are unstable unless arg is $00 234 // !align fills with "NOP" }; static struct cpu_type cpu_type_65c02 = { - keyword_is_65c02mnemo, + keyword_is_65c02_mnemo, 0, // no flags 234 // !align fills with "NOP" }; -/* -static struct cpu_type cpu_type_Rockwell65c02 = { - keyword_is_Rockwell65c02mnemo, +static struct cpu_type cpu_type_r65c02 = { + keyword_is_r65c02_mnemo, 0, // no flags 234 // !align fills with "NOP" }; -static struct cpu_type cpu_type_WDC65c02 = { - keyword_is_WDC65c02mnemo, +static struct cpu_type cpu_type_w65c02 = { + keyword_is_w65c02_mnemo, 0, // no flags 234 // !align fills with "NOP" }; -*/ static struct cpu_type cpu_type_65816 = { - keyword_is_65816mnemo, + keyword_is_65816_mnemo, CPUFLAG_SUPPORTSLONGREGS, // allows A and XY to be 16bits wide 234 // !align fills with "NOP" }; +static struct cpu_type cpu_type_65ce02 = { + keyword_is_65ce02_mnemo, + CPUFLAG_DECIMALSUBTRACTBUGGY, // SBC does not work reliably in decimal mode + 234 // !align fills with "NOP" +}; +static struct cpu_type cpu_type_4502 = { + keyword_is_4502_mnemo, + CPUFLAG_DECIMALSUBTRACTBUGGY, // SBC does not work reliably in decimal mode + 234 // !align fills with "NOP" +}; // variables @@ -59,15 +67,17 @@ static struct cpu_type cpu_type_65816 = { // predefined stuff static struct ronode *cputype_tree = NULL; static struct ronode cputype_list[] = { -#define KNOWN_TYPES "'6502', '6510', 'c64dtv2', '65c02', '65816'" // shown in CLI error message for unknown types +#define KNOWN_TYPES "'6502', '6510', '65c02', 'r65c02', 'w65c02', '65816', '65ce02', '4502', 'c64dtv2'" // shown in CLI error message for unknown types // PREDEFNODE("z80", &cpu_type_Z80), PREDEFNODE("6502", &cpu_type_6502), PREDEFNODE("6510", &cpu_type_6510), - PREDEFNODE("c64dtv2", &cpu_type_c64dtv2), PREDEFNODE("65c02", &cpu_type_65c02), -// PREDEFNODE("Rockwell65c02", &cpu_type_Rockwell65c02), -// PREDEFNODE("WDC65c02", &cpu_type_WDC65c02), - PREDEFLAST("65816", &cpu_type_65816), + PREDEFNODE("r65c02", &cpu_type_r65c02), + PREDEFNODE("w65c02", &cpu_type_w65c02), + PREDEFNODE("65816", &cpu_type_65816), + PREDEFNODE("65ce02", &cpu_type_65ce02), + PREDEFNODE("4502", &cpu_type_4502), + PREDEFLAST("c64dtv2", &cpu_type_c64dtv2), // ^^^^ this marks the last element }; const char cputype_names[] = KNOWN_TYPES; // string to show if cputype_find() returns NULL diff --git a/src/cpu.h b/src/cpu.h index 394a053..cbfce00 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // @@ -22,6 +22,7 @@ struct cpu_type { #define CPUFLAG_SUPPORTSLONGREGS (1u << 1) // allow "!al" and "!rl" pseudo opcodes #define CPUFLAG_8B_AND_AB_NEED_0_ARG (1u << 2) // warn if "ane/lxa #$xx" uses non-zero arg #define CPUFLAG_ISBIGENDIAN (1u << 3) // for 16/24/32-bit values, output msb first +#define CPUFLAG_DECIMALSUBTRACTBUGGY (1u << 4) // warn if "sed" is assembled // if cpu type and value match, set register length variable to value. diff --git a/src/dynabuf.c b/src/dynabuf.c index 6d73e96..2e078a7 100644 --- a/src/dynabuf.c +++ b/src/dynabuf.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Dynamic buffer stuff diff --git a/src/dynabuf.h b/src/dynabuf.h index 0957f90..d143753 100644 --- a/src/dynabuf.h +++ b/src/dynabuf.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Dynamic buffer stuff diff --git a/src/encoding.c b/src/encoding.c index 9f65b6b..45d16b7 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Character encoding stuff diff --git a/src/encoding.h b/src/encoding.h index 1db0920..9fd0c92 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Character encoding stuff diff --git a/src/flow.c b/src/flow.c index 63835ec..9ef0106 100644 --- a/src/flow.c +++ b/src/flow.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Flow control stuff (loops, conditional assembly etc.) diff --git a/src/flow.h b/src/flow.h index 74cf9e3..cf30b2e 100644 --- a/src/flow.h +++ b/src/flow.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2015 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // flow control stuff (loops, conditional assembly etc.) diff --git a/src/global.c b/src/global.c index 807b392..854d183 100644 --- a/src/global.c +++ b/src/global.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/global.h b/src/global.h index 20f1ded..b68129e 100644 --- a/src/global.h +++ b/src/global.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/input.c b/src/input.c index 1a0fe39..43f555e 100644 --- a/src/input.c +++ b/src/input.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/input.h b/src/input.h index 47e7d6d..1e20511 100644 --- a/src/input.h +++ b/src/input.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/macro.c b/src/macro.c index 867f7e1..c310dea 100644 --- a/src/macro.c +++ b/src/macro.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/macro.h b/src/macro.h index 74ee5b9..7d423bc 100644 --- a/src/macro.h +++ b/src/macro.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Macro stuff diff --git a/src/mnemo.c b/src/mnemo.c index f8b8e68..5f2fdd7 100644 --- a/src/mnemo.c +++ b/src/mnemo.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2015 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Mnemonics stuff @@ -19,42 +19,39 @@ #define s_ror (s_error + 2) // Yes, I know I'm sick #define MNEMO_DYNABUF_INITIALSIZE 8 // 4 + terminator should suffice -// These values are needed to recognize addressing modes. -// Bits: -// 7....... "Implied" no value given -// .6...... "Immediate" "#" at start -// ..5..... "IndirectLong" "[" at start and "]" after value -// ...4.... "Indirect" Value has at least one unnecessary pair of "()" -// ....32.. "Indexed-Int" Index given inside of "()" -// ......10 "Indexed-Ext" Index given outside of (or without any) "()" -// -// Index bits: -// 00 = no index -// 01 = ",s" (Stack-indexed) -// 10 = ",x" (X-indexed) -// 11 = ",y" (Y-indexed) +// These values are needed to recognize addressing modes: +// indexing: +#define INDEX_NONE 0 // no index +#define INDEX_S 1 // stack-indexed (",s" or ",sp"), for 65816 and 65ce02 +#define INDEX_X 2 // x-indexed (",x") +#define INDEX_Y 3 // y-indexed (",y") +#define INDEX_Z 4 // z-indexed (",z"), only for 65ce02 + // 5..7 are left for future expansion, 8 would need the AMB_INDEX macro below to be adjusted! +// adress mode bits: +#define AMB_IMPLIED (1u << 0) // no value given +#define AMB_IMMEDIATE (1u << 1) // '#' at start +#define AMB_INDIRECT (1u << 2) // value has at least one unnecessary pair of "()" +#define AMB_LONGINDIRECT (1u << 3) // value is given in [] +#define AMB_PREINDEX(idx) ((idx) << 4) // three bits for indexing inside () +#define AMB_INDEX(idx) ((idx) << 7) // three bits for external indexing -// Components (Values for indices) -#define HAM__ (0u << 0) // No index -#define HAM_S (1u << 0) // Stack-indexed -#define HAM_X (2u << 0) // X-indexed -#define HAM_Y (3u << 0) // Y-indexed - -// End values base value internal index external index -#define HAM_IMP (1u << 7) -#define HAM_IMM (1u << 6) -#define HAM_ABS 0 -#define HAM_ABSS (1u << 0) -#define HAM_ABSX (2u << 0) -#define HAM_ABSY (3u << 0) -#define HAM_IND (1u << 4) -#define HAM_XIND ((1u << 4) | (2u << 2)) -#define HAM_INDY ((1u << 4) | (3u << 0)) -#define HAM_SINDY ((1u << 4) | (1u << 2) | (3u << 0)) -#define HAM_LIND (1u << 5) -#define HAM_LINDY ((1u << 5) | (3u << 0)) -// Values of internal indices equal values of external indices, shifted left -// by two bits. The program relies on this ! +// end values (here, "absolute addressing" always includes zeropage addressing, because they look the same) +#define IMPLIED_ADDRESSING AMB_IMPLIED +#define IMMEDIATE_ADDRESSING AMB_IMMEDIATE +#define ABSOLUTE_ADDRESSING 0 +#define X_INDEXED_ADDRESSING AMB_INDEX(INDEX_X) +#define Y_INDEXED_ADDRESSING AMB_INDEX(INDEX_Y) +#define INDIRECT_ADDRESSING AMB_INDIRECT +#define X_INDEXED_INDIRECT_ADDRESSING (AMB_PREINDEX(INDEX_X) | AMB_INDIRECT) +#define INDIRECT_Y_INDEXED_ADDRESSING (AMB_INDIRECT | AMB_INDEX(INDEX_Y)) +// only for 65ce02: +#define INDIRECT_Z_INDEXED_ADDRESSING (AMB_INDIRECT | AMB_INDEX(INDEX_Z)) +// for 65816 and 65ce02: +#define STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING (AMB_PREINDEX(INDEX_S) | AMB_INDIRECT | AMB_INDEX(INDEX_Y)) +// only for 65816: +#define STACK_INDEXED_ADDRESSING AMB_INDEX(INDEX_S) +#define LONG_INDIRECT_ADDRESSING AMB_LONGINDIRECT +#define LONG_INDIRECT_Y_INDEXED_ADDRESSING (AMB_LONGINDIRECT | AMB_INDEX(INDEX_Y)) // Constant values, used to mark the possible parameter lengths of commands. // Not all of the eight values are actually used, however (because of the @@ -75,8 +72,11 @@ enum mnemogroup { GROUP_ALLJUMPS, // the jump instructions Byte value = table index GROUP_IMPLIEDONLY, // mnemonics using only implied addressing Byte value = opcode GROUP_RELATIVE8, // short branch instructions Byte value = opcode - GROUP_RELATIVE16, // mnemonics with 16bit relative addressing Byte value = opcode - GROUP_BOTHMOVES // the "move" commands MVP and MVN Byte value = opcode + 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_MEMBIT // rmb0..7 and smb0..7 Byte value = opcode }; // save some space @@ -90,19 +90,20 @@ enum mnemogroup { // 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 | 65c02 | 65816 | 6510 illegals | -enum { IDX_ORA,IDX_AND,IDX_EOR,IDX_ADC,IDX_STA,IDX_LDA,IDX_CMP,IDX_SBC,IDXcORA,IDXcAND,IDXcEOR,IDXcADC,IDXcSTA,IDXcLDA,IDXcCMP,IDXcSBC,IDX816ORA,IDX816AND,IDX816EOR,IDX816ADC,IDX816STA,IDX816LDA,IDX816CMP,IDX816SBC,IDX816PEI,IDX_SLO,IDX_RLA,IDX_SRE,IDX_RRA,IDX_SAX,IDX_LAX,IDX_DCP,IDX_ISC,IDX_SHA}; -SCL accu_abs[] = { 0x0d05, 0x2d25, 0x4d45, 0x6d65, 0x8d85, 0xada5, 0xcdc5, 0xede5, 0x0d05, 0x2d25, 0x4d45, 0x6d65, 0x8d85, 0xada5, 0xcdc5, 0xede5, 0x0f0d05, 0x2f2d25, 0x4f4d45, 0x6f6d65, 0x8f8d85, 0xafada5, 0xcfcdc5, 0xefede5, 0, 0x0f07, 0x2f27, 0x4f47, 0x6f67, 0x8f87, 0xafa7, 0xcfc7, 0xefe7, 0}; // $ff $ffff $ffffff -SCL accu_xabs[] = { 0x1d15, 0x3d35, 0x5d55, 0x7d75, 0x9d95, 0xbdb5, 0xddd5, 0xfdf5, 0x1d15, 0x3d35, 0x5d55, 0x7d75, 0x9d95, 0xbdb5, 0xddd5, 0xfdf5, 0x1f1d15, 0x3f3d35, 0x5f5d55, 0x7f7d75, 0x9f9d95, 0xbfbdb5, 0xdfddd5, 0xfffdf5, 0, 0x1f17, 0x3f37, 0x5f57, 0x7f77, 0, 0, 0xdfd7, 0xfff7, 0}; // $ff,x $ffff,x $ffffff,x -SCS accu_yabs[] = { 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0, 0x1b00, 0x3b00, 0x5b00, 0x7b00, 0x97, 0xbfb7, 0xdb00, 0xfb00, 0x9f00}; // $ff,y $ffff,y -SCB accu_xind8[] = { 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0, 0x03, 0x23, 0x43, 0x63, 0x83, 0xa3, 0xc3, 0xe3, 0}; // ($ff,x) -SCB accu_indy8[] = { 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0, 0x13, 0x33, 0x53, 0x73, 0, 0xb3, 0xd3, 0xf3, 0x93}; // ($ff),y -SCB accu_imm[] = { 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // #$ff #$ffff -SCB accu_ind8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x32, 0x52, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 0x12, 0x32, 0x52, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff) -SCB accu_sabs8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0x23, 0x43, 0x63, 0x83, 0xa3, 0xc3, 0xe3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff,s -SCB accu_sindy8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x13, 0x33, 0x53, 0x73, 0x93, 0xb3, 0xd3, 0xf3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff,s),y -SCB accu_lind8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x07, 0x27, 0x47, 0x67, 0x87, 0xa7, 0xc7, 0xe7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // [$ff] -SCB accu_lindy8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x17, 0x37, 0x57, 0x77, 0x97, 0xb7, 0xd7, 0xf7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // [$ff],y +// | 6502 | 65c02 | 65ce02 | 65816 | 6510 illegals | +enum { IDX_ORA,IDX_AND,IDX_EOR,IDX_ADC,IDX_STA,IDX_LDA,IDX_CMP,IDX_SBC,IDXcORA,IDXcAND,IDXcEOR,IDXcADC,IDXcSTA,IDXcLDA,IDXcCMP,IDXcSBC,IDXeORA,IDXeAND,IDXeEOR,IDXeADC,IDXeSTA,IDXeLDA,IDXeCMP,IDXeSBC,IDX816ORA,IDX816AND,IDX816EOR,IDX816ADC,IDX816STA,IDX816LDA,IDX816CMP,IDX816SBC,IDX816PEI,IDX_SLO,IDX_RLA,IDX_SRE,IDX_RRA,IDX_SAX,IDX_LAX,IDX_DCP,IDX_ISC,IDX_SHA}; +SCB accu_imm[] = { 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0x09, 0x29, 0x49, 0x69, 0, 0xa9, 0xc9, 0xe9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // #$ff #$ffff +SCL accu_abs[] = { 0x0d05, 0x2d25, 0x4d45, 0x6d65, 0x8d85, 0xada5, 0xcdc5, 0xede5, 0x0d05, 0x2d25, 0x4d45, 0x6d65, 0x8d85, 0xada5, 0xcdc5, 0xede5, 0x0d05, 0x2d25, 0x4d45, 0x6d65, 0x8d85, 0xada5, 0xcdc5, 0xede5, 0x0f0d05, 0x2f2d25, 0x4f4d45, 0x6f6d65, 0x8f8d85, 0xafada5, 0xcfcdc5, 0xefede5, 0, 0x0f07, 0x2f27, 0x4f47, 0x6f67, 0x8f87, 0xafa7, 0xcfc7, 0xefe7, 0}; // $ff $ffff $ffffff +SCL accu_xabs[] = { 0x1d15, 0x3d35, 0x5d55, 0x7d75, 0x9d95, 0xbdb5, 0xddd5, 0xfdf5, 0x1d15, 0x3d35, 0x5d55, 0x7d75, 0x9d95, 0xbdb5, 0xddd5, 0xfdf5, 0x1d15, 0x3d35, 0x5d55, 0x7d75, 0x9d95, 0xbdb5, 0xddd5, 0xfdf5, 0x1f1d15, 0x3f3d35, 0x5f5d55, 0x7f7d75, 0x9f9d95, 0xbfbdb5, 0xdfddd5, 0xfffdf5, 0, 0x1f17, 0x3f37, 0x5f57, 0x7f77, 0, 0, 0xdfd7, 0xfff7, 0}; // $ff,x $ffff,x $ffffff,x +SCS accu_yabs[] = { 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0x1900, 0x3900, 0x5900, 0x7900, 0x9900, 0xb900, 0xd900, 0xf900, 0, 0x1b00, 0x3b00, 0x5b00, 0x7b00, 0x97, 0xbfb7, 0xdb00, 0xfb00, 0x9f00}; // $ff,y $ffff,y +SCB accu_xind8[] = { 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0x01, 0x21, 0x41, 0x61, 0x81, 0xa1, 0xc1, 0xe1, 0, 0x03, 0x23, 0x43, 0x63, 0x83, 0xa3, 0xc3, 0xe3, 0}; // ($ff,x) +SCB accu_indy8[] = { 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0x11, 0x31, 0x51, 0x71, 0x91, 0xb1, 0xd1, 0xf1, 0, 0x13, 0x33, 0x53, 0x73, 0, 0xb3, 0xd3, 0xf3, 0x93}; // ($ff),y +SCB accu_ind8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x32, 0x52, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x32, 0x52, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff) +SCB accu_indz8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x32, 0x52, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 0x12, 0x32, 0x52, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff) +SCB accu_sabs8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0x23, 0x43, 0x63, 0x83, 0xa3, 0xc3, 0xe3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff,s +SCB accu_sindy8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x82, 0xe2, 0, 0, 0x13, 0x33, 0x53, 0x73, 0x93, 0xb3, 0xd3, 0xf3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff,s),y +SCB accu_lind8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x07, 0x27, 0x47, 0x67, 0x87, 0xa7, 0xc7, 0xe7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // [$ff] +SCB accu_lindy8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x17, 0x37, 0x57, 0x77, 0x97, 0xb7, 0xd7, 0xf7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // [$ff],y // Code tables for group GROUP_MISC: // These tables are needed for finding out the correct code in cases when @@ -110,13 +111,13 @@ SCB accu_lindy8[] = { 0, 0, 0, 0, 0, 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 | 65c02 | 65816 | 6510 illegals | C64DTV2 | -enum { IDX_BIT,IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_STY,IDX_STX,IDX_LDY,IDX_LDX,IDX_CPY,IDX_CPX,IDX_DEC,IDX_INC,IDXcTSB,IDXcTRB,IDXcBIT,IDXcDEC,IDXcINC,IDXcSTZ,IDX816COP,IDX816REP,IDX816SEP,IDX816PEA,IDX_ANC,IDX_ASR,IDX_ARR,IDX_SBX,IDX_DOP,IDX_TOP,IDX_JAM,IDX_LXA,IDX_ANE,IDX_LAS,IDX_TAS,IDX_SHX,IDX_SHY,IDX_SAC,IDX_SIR}; -SCS misc_abs[] = { 0x2c24, 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0x8c84, 0x8e86, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0xcec6, 0xeee6, 0x0c04, 0x1c14, 0x2c24, 0xcec6, 0xeee6, 0x9c64, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x04, 0x0c00, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff $ffff -SCS misc_xabs[] = { 0, 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0x94, 0, 0xbcb4, 0, 0, 0, 0xded6, 0xfef6, 0, 0, 0x3c34, 0xded6, 0xfef6, 0x9e74, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0x1c00, 0, 0, 0, 0, 0, 0, 0x9c00, 0, 0}; // $ff,x $ffff,x -SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0, 0x96, 0, 0xbeb6, 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 -SCB misc_imm[] = { 0, 0, 0, 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0, 0, 0, 0x89, 0, 0, 0, 0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0, 0, 0xab, 0x8b, 0, 0, 0, 0, 0x32, 0x42}; // #$ff -SCB misc_impl[] = { 0, 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0x1a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x0c, 0x02, 0, 0, 0, 0, 0, 0, 0, 0}; // implied/accu +// | 6502 | 65c02 | 65ce02 | 65816 | 6510 illegals | C64DTV2 | +enum { IDX_BIT,IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_STY,IDX_STX,IDX_LDY,IDX_LDX,IDX_CPY,IDX_CPX,IDX_DEC,IDX_INC,IDXcTSB,IDXcTRB,IDXcBIT,IDXcDEC,IDXcINC,IDXcSTZ,IDXeASR,IDXeASW,IDXeCPZ,IDXeDEW,IDXeINW,IDXeLDZ,IDXePHW,IDXeROW,IDXeRTN,IDXeSTX,IDXeSTY,IDX816COP,IDX816REP,IDX816SEP,IDX816PEA,IDX_ANC,IDX_ASR,IDX_ARR,IDX_SBX,IDX_DOP,IDX_TOP,IDX_JAM,IDX_LXA,IDX_ANE,IDX_LAS,IDX_TAS,IDX_SHX,IDX_SHY,IDX_SAC,IDX_SIR}; +SCB misc_impl[] = { 0, 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0x1a, 0, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x0c, 0x02, 0, 0, 0, 0, 0, 0, 0, 0}; // implied/accu +SCB misc_imm[] = { 0, 0, 0, 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0, 0, 0, 0x89, 0, 0, 0, 0, 0, 0xc2, 0, 0, 0xa3, 0xf4, 0, 0x62, 0, 0, 0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0, 0, 0xab, 0x8b, 0, 0, 0, 0, 0x32, 0x42}; // #$ff #$ffff +SCS misc_abs[] = { 0x2c24, 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0x8c84, 0x8e86, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0xcec6, 0xeee6, 0x0c04, 0x1c14, 0x2c24, 0xcec6, 0xeee6, 0x9c64, 0x44, 0xcb00, 0xdcd4, 0xc3, 0xe3, 0xab00, 0xfc00, 0xeb00, 0, 0x8e86, 0x8c84, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x04, 0x0c00, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff $ffff +SCS misc_xabs[] = { 0, 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0x94, 0, 0xbcb4, 0, 0, 0, 0xded6, 0xfef6, 0, 0, 0x3c34, 0xded6, 0xfef6, 0x9e74, 0x54, 0, 0, 0, 0, 0xbb00, 0, 0, 0, 0, 0x8b94, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0x1c00, 0, 0, 0, 0, 0, 0, 0x9c00, 0, 0}; // $ff,x $ffff,x +SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0, 0x96, 0, 0xbeb6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x9b96, 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 @@ -125,12 +126,12 @@ SCB misc_impl[] = { 0, 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, // 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 | 65c02 | 65816 | -enum { IDX_JMP,IDX_JSR,IDXcJMP,IDX816JMP,IDX816JML,IDX816JSR,IDX816JSL}; -SCL jump_abs[] = { 0x4c00, 0x2000, 0x4c00, 0x5c4c00, 0x5c0000, 0x222000, 0x220000}; // $ffff $ffffff -SCS jump_ind[] = { 0x6c00, 0, 0x6c00, 0x6c00, 0, 0, 0}; // ($ffff) -SCS jump_xind[] = { 0, 0, 0x7c00, 0x7c00, 0, 0xfc00, 0}; // ($ffff,x) -SCS jump_lind[] = { 0, 0, 0, 0xdc00, 0xdc00, 0, 0}; // [$ffff] +// | 6502 | 65c02 | 65ce02| 65816 | +enum { IDX_JMP,IDX_JSR,IDXcJMP,IDXeJSR,IDX816JMP,IDX816JML,IDX816JSR,IDX816JSL}; +SCL jump_abs[] = { 0x4c00, 0x2000, 0x4c00, 0x2000, 0x5c4c00, 0x5c0000, 0x222000, 0x220000}; // $ffff $ffffff +SCS jump_ind[] = { 0x6c00, 0, 0x6c00, 0x2200, 0x6c00, 0, 0, 0}; // ($ffff) +SCS jump_xind[] = { 0, 0, 0x7c00, 0x2300, 0x7c00, 0, 0xfc00, 0}; // ($ffff,x) +SCS jump_lind[] = { 0, 0, 0, 0, 0xdc00, 0xdc00, 0, 0}; // [$ffff] #undef SCB #undef SCS @@ -145,55 +146,62 @@ static const char exception_highbyte_zero[] = "Using oversized addressing mode." static struct dynabuf *mnemo_dyna_buf; // dynamic buffer for mnemonics // predefined stuff -static struct ronode *mnemo_6502_tree = NULL; // holds 6502 mnemonics -static struct ronode *mnemo_6502undoc1_tree = NULL; // holds 6502 undocumented ("illegal") opcodes supported by DTV2 -static struct ronode *mnemo_6502undoc2_tree = NULL; // holds remaining 6502 undocumented ("illegal") opcodes (currently ANC only, maybe more will get moved) -static struct ronode *mnemo_c64dtv2_tree = NULL; // holds C64DTV2 extensions (BRA/SAC/SIR) -static struct ronode *mnemo_65c02_tree = NULL; // holds 65c02 extensions -//static struct ronode *mnemo_Rockwell65c02_tree = NULL; // Rockwell -static struct ronode *mnemo_WDC65c02_tree = NULL; // WDC's "stp"/"wai" -static struct ronode *mnemo_65816_tree = NULL; // holds 65816 extensions +static struct ronode *mnemo_6502_tree = NULL; // 6502 mnemonics +static struct ronode *mnemo_6502undoc1_tree = NULL; // 6502 undocumented ("illegal") opcodes supported by DTV2 +static struct ronode *mnemo_6502undoc2_tree = NULL; // remaining 6502 undocumented ("illegal") opcodes (currently ANC only, maybe more will get moved) +static struct ronode *mnemo_c64dtv2_tree = NULL; // C64DTV2 extensions (BRA/SAC/SIR) +static struct ronode *mnemo_65c02_tree = NULL; // 65c02 extensions +static struct ronode *mnemo_bitmanips_tree = NULL; // Rockwell's bit manipulation extensions +static struct ronode *mnemo_stp_wai_tree = NULL; // WDC's "stp" and "wai" instructions +static struct ronode *mnemo_65816_tree = NULL; // WDC 65816 extensions +static struct ronode *mnemo_65ce02_tree = NULL; // CSG 65ce02/4502 extensions +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 // Command's code and group values are stored together in a single integer. // To extract the code, use "& CODEMASK". -// To extract the group, use ">> GROUPSHIFT" -#define CODEMASK 0xff // opcode or table index -#define FLAGSMASK 0x300 // flags concerning immediate addressing: -#define IMM_ACCU 0x100 // ...depends on accumulator length -#define IMM_IDX 0x200 // ...depends on index register length -#define GROUPSHIFT 10 // shift right by this to extract group -#define MERGE(g, v) ((g << GROUPSHIFT) | v) +// To extract the immediate mode, use "& IMMASK". +// To extract the group, use GROUP() +#define CODEMASK 0x0ff // opcode or table index +// immediate mode: +#define IM_FORCE8 0x000 // immediate values are 8 bits (CAUTION - program relies on "no bits set" being the default!) +#define IM_FORCE16 0x100 // immediate value is 16 bits (for 65ce02's PHW#) +#define IM_ACCUMULATOR 0x200 // immediate value depends on accumulator length +#define IM_INDEXREGS 0x300 // immediate value depends on index register length +#define IMMASK 0x300 // mask for immediate modes +#define MERGE(g, v) (((g) << 10) | (v)) +#define GROUP(v) ((v) >> 10) static struct ronode mnemos_6502[] = { - PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX_ORA | IMM_ACCU)), - PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDX_AND | IMM_ACCU)), - PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDX_EOR | IMM_ACCU)), - PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX_ADC | IMM_ACCU)), + PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX_ORA)), + PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDX_AND)), + PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDX_EOR)), + PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX_ADC)), PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX_STA)), - PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX_LDA | IMM_ACCU)), - PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX_CMP | IMM_ACCU)), - PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX_SBC | IMM_ACCU)), - PREDEFNODE("bit", MERGE(GROUP_MISC, IDX_BIT | IMM_ACCU)), + PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX_LDA)), + PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX_CMP)), + PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX_SBC)), + PREDEFNODE("bit", MERGE(GROUP_MISC, IDX_BIT)), PREDEFNODE(s_asl, MERGE(GROUP_MISC, IDX_ASL)), PREDEFNODE("rol", MERGE(GROUP_MISC, IDX_ROL)), PREDEFNODE(s_lsr, MERGE(GROUP_MISC, IDX_LSR)), PREDEFNODE(s_ror, MERGE(GROUP_MISC, IDX_ROR)), PREDEFNODE("sty", MERGE(GROUP_MISC, IDX_STY)), PREDEFNODE("stx", MERGE(GROUP_MISC, IDX_STX)), - PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY | IMM_IDX)), - PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX | IMM_IDX)), - PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY | IMM_IDX)), - PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX | IMM_IDX)), + PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY)), + PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX)), + PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY)), + PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX)), PREDEFNODE("dec", MERGE(GROUP_MISC, IDX_DEC)), PREDEFNODE("inc", MERGE(GROUP_MISC, IDX_INC)), - PREDEFNODE("bpl", MERGE(GROUP_RELATIVE8, 16)), - PREDEFNODE("bmi", MERGE(GROUP_RELATIVE8, 48)), - PREDEFNODE("bvc", MERGE(GROUP_RELATIVE8, 80)), - PREDEFNODE("bvs", MERGE(GROUP_RELATIVE8, 112)), - PREDEFNODE("bcc", MERGE(GROUP_RELATIVE8, 144)), - PREDEFNODE("bcs", MERGE(GROUP_RELATIVE8, 176)), - PREDEFNODE("bne", MERGE(GROUP_RELATIVE8, 208)), - PREDEFNODE("beq", MERGE(GROUP_RELATIVE8, 240)), + PREDEFNODE("bpl", MERGE(GROUP_RELATIVE8, 0x10)), + PREDEFNODE("bmi", MERGE(GROUP_RELATIVE8, 0x30)), + PREDEFNODE("bvc", MERGE(GROUP_RELATIVE8, 0x50)), + PREDEFNODE("bvs", MERGE(GROUP_RELATIVE8, 0x70)), + PREDEFNODE("bcc", MERGE(GROUP_RELATIVE8, 0x90)), + PREDEFNODE("bcs", MERGE(GROUP_RELATIVE8, 0xb0)), + PREDEFNODE("bne", MERGE(GROUP_RELATIVE8, 0xd0)), + PREDEFNODE("beq", MERGE(GROUP_RELATIVE8, 0xf0)), PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDX_JMP)), PREDEFNODE("jsr", MERGE(GROUP_ALLJUMPS, IDX_JSR)), PREDEFNODE("brk", MERGE(GROUP_IMPLIEDONLY, 0)), @@ -224,6 +232,7 @@ static struct ronode mnemos_6502[] = { // ^^^^ this marks the last element }; +// undocumented opcodes of the NMOS 6502 that are also supported by c64dtv2: static struct ronode mnemos_6502undoc1[] = { PREDEFNODE("slo", MERGE(GROUP_ACCU, IDX_SLO)), // ASL + ORA (aka ASO) PREDEFNODE("rla", MERGE(GROUP_ACCU, IDX_RLA)), // ROL + AND @@ -249,32 +258,37 @@ static struct ronode mnemos_6502undoc1[] = { // ^^^^ this marks the last element }; +// undocumented opcodes of the NMOS 6502 that are _not_ supported by c64dtv2: static struct ronode mnemos_6502undoc2[] = { PREDEFLAST("anc", MERGE(GROUP_MISC, IDX_ANC)), // ROL + AND, ASL + ORA (aka AAC) // ^^^^ this marks the last element }; +// additional opcodes of c64dtv2: static struct ronode mnemos_c64dtv2[] = { - PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 0x12)), // branch always + PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 0x12)), // branch always PREDEFNODE("sac", MERGE(GROUP_MISC, IDX_SAC)), // set accumulator mapping PREDEFLAST("sir", MERGE(GROUP_MISC, IDX_SIR)), // set index register mapping // ^^^^ this marks the last element }; +// new stuff in CMOS re-design: static struct ronode mnemos_65c02[] = { - PREDEFNODE("ora", MERGE(GROUP_ACCU, IDXcORA | IMM_ACCU)), - PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDXcAND | IMM_ACCU)), - PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDXcEOR | IMM_ACCU)), - PREDEFNODE("adc", MERGE(GROUP_ACCU, IDXcADC | IMM_ACCU)), + // more addressing modes for some mnemonics: + PREDEFNODE("ora", MERGE(GROUP_ACCU, IDXcORA)), + PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDXcAND)), + PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDXcEOR)), + PREDEFNODE("adc", MERGE(GROUP_ACCU, IDXcADC)), PREDEFNODE("sta", MERGE(GROUP_ACCU, IDXcSTA)), - PREDEFNODE("lda", MERGE(GROUP_ACCU, IDXcLDA | IMM_ACCU)), - PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDXcCMP | IMM_ACCU)), - PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDXcSBC | IMM_ACCU)), + PREDEFNODE("lda", MERGE(GROUP_ACCU, IDXcLDA)), + PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDXcCMP)), + PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDXcSBC)), PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDXcJMP)), - PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IMM_ACCU)), + PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT)), PREDEFNODE("dec", MERGE(GROUP_MISC, IDXcDEC)), PREDEFNODE("inc", MERGE(GROUP_MISC, IDXcINC)), - PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 128)), + // and eight new mnemonics: + PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 0x80)), PREDEFNODE("phy", MERGE(GROUP_IMPLIEDONLY, 90)), PREDEFNODE("ply", MERGE(GROUP_IMPLIEDONLY, 122)), PREDEFNODE("phx", MERGE(GROUP_IMPLIEDONLY, 218)), @@ -285,66 +299,77 @@ static struct ronode mnemos_65c02[] = { // ^^^^ this marks the last element }; -//static struct ronode mnemos_Rockwell65c02[] = { -// PREDEFNODE("rmb0", MERGE(G_ , 0x07)), -// PREDEFNODE("rmb1", MERGE(G_ , 0x17)), -// PREDEFNODE("rmb2", MERGE(G_ , 0x27)), -// PREDEFNODE("rmb3", MERGE(G_ , 0x37)), -// PREDEFNODE("rmb4", MERGE(G_ , 0x47)), -// PREDEFNODE("rmb5", MERGE(G_ , 0x57)), -// PREDEFNODE("rmb6", MERGE(G_ , 0x67)), -// PREDEFNODE("rmb7", MERGE(G_ , 0x77)), -// PREDEFNODE("smb0", MERGE(G_ , 0x87)), -// PREDEFNODE("smb1", MERGE(G_ , 0x97)), -// PREDEFNODE("smb2", MERGE(G_ , 0xa7)), -// PREDEFNODE("smb3", MERGE(G_ , 0xb7)), -// PREDEFNODE("smb4", MERGE(G_ , 0xc7)), -// PREDEFNODE("smb5", MERGE(G_ , 0xd7)), -// PREDEFNODE("smb6", MERGE(G_ , 0xe7)), -// PREDEFNODE("smb7", MERGE(G_ , 0xf7)), -// PREDEFNODE("bbr0", MERGE(G_ , 0x0f)), -// PREDEFNODE("bbr1", MERGE(G_ , 0x1f)), -// PREDEFNODE("bbr2", MERGE(G_ , 0x2f)), -// PREDEFNODE("bbr3", MERGE(G_ , 0x3f)), -// PREDEFNODE("bbr4", MERGE(G_ , 0x4f)), -// PREDEFNODE("bbr5", MERGE(G_ , 0x5f)), -// PREDEFNODE("bbr6", MERGE(G_ , 0x6f)), -// PREDEFNODE("bbr7", MERGE(G_ , 0x7f)), -// PREDEFNODE("bbs0", MERGE(G_ , 0x8f)), -// PREDEFNODE("bbs1", MERGE(G_ , 0x9f)), -// PREDEFNODE("bbs2", MERGE(G_ , 0xaf)), -// PREDEFNODE("bbs3", MERGE(G_ , 0xbf)), -// PREDEFNODE("bbs4", MERGE(G_ , 0xcf)), -// PREDEFNODE("bbs5", MERGE(G_ , 0xdf)), -// PREDEFNODE("bbs6", MERGE(G_ , 0xef)), -// PREDEFLAST("bbs7", MERGE(G_ , 0xff)), -// // ^^^^ this marks the last element -//}; +// bit-manipulation extensions (by Rockwell?) +static struct ronode mnemos_bitmanips[] = { + PREDEFNODE("rmb0", MERGE(GROUP_MEMBIT, 0x07)), + PREDEFNODE("rmb1", MERGE(GROUP_MEMBIT, 0x17)), + PREDEFNODE("rmb2", MERGE(GROUP_MEMBIT, 0x27)), + PREDEFNODE("rmb3", MERGE(GROUP_MEMBIT, 0x37)), + PREDEFNODE("rmb4", MERGE(GROUP_MEMBIT, 0x47)), + PREDEFNODE("rmb5", MERGE(GROUP_MEMBIT, 0x57)), + PREDEFNODE("rmb6", MERGE(GROUP_MEMBIT, 0x67)), + PREDEFNODE("rmb7", MERGE(GROUP_MEMBIT, 0x77)), + PREDEFNODE("smb0", MERGE(GROUP_MEMBIT, 0x87)), + PREDEFNODE("smb1", MERGE(GROUP_MEMBIT, 0x97)), + PREDEFNODE("smb2", MERGE(GROUP_MEMBIT, 0xa7)), + PREDEFNODE("smb3", MERGE(GROUP_MEMBIT, 0xb7)), + PREDEFNODE("smb4", MERGE(GROUP_MEMBIT, 0xc7)), + PREDEFNODE("smb5", MERGE(GROUP_MEMBIT, 0xd7)), + PREDEFNODE("smb6", MERGE(GROUP_MEMBIT, 0xe7)), + PREDEFNODE("smb7", MERGE(GROUP_MEMBIT, 0xf7)), + PREDEFNODE("bbr0", MERGE(GROUP_BITBRANCH, 0x0f)), + PREDEFNODE("bbr1", MERGE(GROUP_BITBRANCH, 0x1f)), + PREDEFNODE("bbr2", MERGE(GROUP_BITBRANCH, 0x2f)), + PREDEFNODE("bbr3", MERGE(GROUP_BITBRANCH, 0x3f)), + PREDEFNODE("bbr4", MERGE(GROUP_BITBRANCH, 0x4f)), + PREDEFNODE("bbr5", MERGE(GROUP_BITBRANCH, 0x5f)), + PREDEFNODE("bbr6", MERGE(GROUP_BITBRANCH, 0x6f)), + PREDEFNODE("bbr7", MERGE(GROUP_BITBRANCH, 0x7f)), + PREDEFNODE("bbs0", MERGE(GROUP_BITBRANCH, 0x8f)), + PREDEFNODE("bbs1", MERGE(GROUP_BITBRANCH, 0x9f)), + PREDEFNODE("bbs2", MERGE(GROUP_BITBRANCH, 0xaf)), + PREDEFNODE("bbs3", MERGE(GROUP_BITBRANCH, 0xbf)), + PREDEFNODE("bbs4", MERGE(GROUP_BITBRANCH, 0xcf)), + PREDEFNODE("bbs5", MERGE(GROUP_BITBRANCH, 0xdf)), + PREDEFNODE("bbs6", MERGE(GROUP_BITBRANCH, 0xef)), + PREDEFLAST("bbs7", MERGE(GROUP_BITBRANCH, 0xff)), + // ^^^^ this marks the last element +}; -static struct ronode mnemos_WDC65c02[] = { +// "stp" and "wai" extensions by WDC: +static struct ronode mnemos_stp_wai[] = { PREDEFNODE("stp", MERGE(GROUP_IMPLIEDONLY, 219)), PREDEFLAST("wai", MERGE(GROUP_IMPLIEDONLY, 203)), // ^^^^ this marks the last element }; +// most of the 65816 stuff static struct ronode mnemos_65816[] = { - PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX816ORA | IMM_ACCU)), - PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDX816AND | IMM_ACCU)), - PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDX816EOR | IMM_ACCU)), - PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX816ADC | IMM_ACCU)), + // 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)), + PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX | IM_INDEXREGS)), + PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY | IM_INDEXREGS)), + PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX | IM_INDEXREGS)), + PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IM_ACCUMULATOR)), + // more addressing modes for some mnemonics: + PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX816ORA | IM_ACCUMULATOR)), + PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDX816AND | IM_ACCUMULATOR)), + PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDX816EOR | IM_ACCUMULATOR)), + PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX816ADC | IM_ACCUMULATOR)), PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX816STA)), - PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX816LDA | IMM_ACCU)), - PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX816CMP | IMM_ACCU)), - PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX816SBC | IMM_ACCU)), - PREDEFNODE("pei", MERGE(GROUP_ACCU, IDX816PEI)), + PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX816LDA | IM_ACCUMULATOR)), + PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX816CMP | IM_ACCUMULATOR)), + PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX816SBC | IM_ACCUMULATOR)), PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDX816JMP)), PREDEFNODE("jsr", MERGE(GROUP_ALLJUMPS, IDX816JSR)), + // + PREDEFNODE("pei", MERGE(GROUP_ACCU, IDX816PEI)), PREDEFNODE("jml", MERGE(GROUP_ALLJUMPS, IDX816JML)), PREDEFNODE("jsl", MERGE(GROUP_ALLJUMPS, IDX816JSL)), PREDEFNODE("mvp", MERGE(GROUP_BOTHMOVES, 0x44)), PREDEFNODE("mvn", MERGE(GROUP_BOTHMOVES, 0x54)), - PREDEFNODE("per", MERGE(GROUP_RELATIVE16, 98)), - PREDEFNODE(s_brl, MERGE(GROUP_RELATIVE16, 130)), + PREDEFNODE("per", MERGE(GROUP_REL16_3, 98)), + PREDEFNODE(s_brl, MERGE(GROUP_REL16_3, 130)), PREDEFNODE("cop", MERGE(GROUP_MISC, IDX816COP)), PREDEFNODE("rep", MERGE(GROUP_MISC, IDX816REP)), PREDEFNODE("sep", MERGE(GROUP_MISC, IDX816SEP)), @@ -367,6 +392,72 @@ static struct ronode mnemos_65816[] = { // ^^^^ this marks the last element }; +// 65ce02 has 46 new opcodes and a few changes: +static struct ronode mnemos_65ce02[] = { + // 65ce02 changes (zp) addressing of 65c02 to (zp),z addressing: + PREDEFNODE("ora", MERGE(GROUP_ACCU, IDXeORA)), + PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDXeAND)), + PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDXeEOR)), + PREDEFNODE("adc", MERGE(GROUP_ACCU, IDXeADC)), + PREDEFNODE("sta", MERGE(GROUP_ACCU, IDXeSTA)), // +1 for (8,s),y + PREDEFNODE("lda", MERGE(GROUP_ACCU, IDXeLDA)), // +1 for (8,s),y + PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDXeCMP)), + PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDXeSBC)), + // more addressing modes: + PREDEFNODE("jsr", MERGE(GROUP_ALLJUMPS, IDXeJSR)), // +2 + PREDEFNODE("stx", MERGE(GROUP_MISC, IDXeSTX)), // +1 + PREDEFNODE("sty", MERGE(GROUP_MISC, IDXeSTY)), // +1 + // +10 long branches (8 normal, 1 unconditional, BSR uncond to subroutine)) + PREDEFNODE("lbpl", MERGE(GROUP_REL16_2, 0x13)), + PREDEFNODE("lbmi", MERGE(GROUP_REL16_2, 0x33)), + PREDEFNODE("lbvc", MERGE(GROUP_REL16_2, 0x53)), + PREDEFNODE("lbvs", MERGE(GROUP_REL16_2, 0x73)), + PREDEFNODE("lbcc", MERGE(GROUP_REL16_2, 0x93)), + PREDEFNODE("lbcs", MERGE(GROUP_REL16_2, 0xb3)), + PREDEFNODE("lbne", MERGE(GROUP_REL16_2, 0xd3)), + PREDEFNODE("lbeq", MERGE(GROUP_REL16_2, 0xf3)), + PREDEFNODE("bru", MERGE(GROUP_RELATIVE8, 0x80)), // alias for 65c02's "bra" + PREDEFNODE("bsr", MERGE(GROUP_REL16_2, 0x63)), + PREDEFNODE("lbru", MERGE(GROUP_REL16_2, 0x83)), + PREDEFNODE("lbra", MERGE(GROUP_REL16_2, 0x83)), // alias + // new mnemonics: + 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("ldz", MERGE(GROUP_MISC, IDXeLDZ)), + PREDEFNODE("phw", MERGE(GROUP_MISC, IDXePHW | IM_FORCE16)), + PREDEFNODE("row", MERGE(GROUP_MISC, IDXeROW)), + PREDEFNODE("rtn", MERGE(GROUP_MISC, IDXeRTN)), + PREDEFNODE("cle", MERGE(GROUP_IMPLIEDONLY, 0x02)), + PREDEFNODE("see", MERGE(GROUP_IMPLIEDONLY, 0x03)), + PREDEFNODE("inz", MERGE(GROUP_IMPLIEDONLY, 0x1b)), + PREDEFNODE("dez", MERGE(GROUP_IMPLIEDONLY, 0x3b)), + PREDEFNODE("neg", MERGE(GROUP_IMPLIEDONLY, 0x42)), + PREDEFNODE("tsy", MERGE(GROUP_IMPLIEDONLY, 0x0b)), + PREDEFNODE("tys", MERGE(GROUP_IMPLIEDONLY, 0x2b)), + PREDEFNODE("taz", MERGE(GROUP_IMPLIEDONLY, 0x4b)), + PREDEFNODE("tab", MERGE(GROUP_IMPLIEDONLY, 0x5b)), + PREDEFNODE("tza", MERGE(GROUP_IMPLIEDONLY, 0x6b)), + PREDEFNODE("tba", MERGE(GROUP_IMPLIEDONLY, 0x7b)), + PREDEFNODE("phz", MERGE(GROUP_IMPLIEDONLY, 0xdb)), + PREDEFLAST("plz", MERGE(GROUP_IMPLIEDONLY, 0xfb)), + // ^^^^ this marks the last element +}; + +// 65ce02's "aug" opcode: +static struct ronode mnemos_aug[] = { + PREDEFLAST("aug", MERGE(GROUP_IMPLIEDONLY, 0x5c)), // actually a "4-byte NOP reserved for future expansion" + // ^^^^ this marks the last element +}; + +// 4502's "map" and "eom" opcodes: +static struct ronode mnemos_map_eom[] = { + PREDEFNODE("map", MERGE(GROUP_IMPLIEDONLY, 0x5c)), // change memory mapping + PREDEFLAST("eom", MERGE(GROUP_IMPLIEDONLY, 0xea)), // actually the NOP opcode + // ^^^^ this marks the last element +}; // Functions @@ -379,43 +470,53 @@ void Mnemo_init(void) Tree_add_table(&mnemo_6502undoc2_tree, mnemos_6502undoc2); Tree_add_table(&mnemo_c64dtv2_tree, mnemos_c64dtv2); Tree_add_table(&mnemo_65c02_tree, mnemos_65c02); -// Tree_add_table(&mnemo_Rockwell65c02_tree, mnemos_Rockwell65c02); - Tree_add_table(&mnemo_WDC65c02_tree, mnemos_WDC65c02); + Tree_add_table(&mnemo_bitmanips_tree, mnemos_bitmanips); + Tree_add_table(&mnemo_stp_wai_tree, mnemos_stp_wai); Tree_add_table(&mnemo_65816_tree, mnemos_65816); + Tree_add_table(&mnemo_65ce02_tree, mnemos_65ce02); + Tree_add_table(&mnemo_aug_tree, mnemos_aug); + Tree_add_table(&mnemo_map_eom_tree, mnemos_map_eom); } // Address mode parsing -// Utility function for parsing indices. +// utility function for parsing indices. result must be processed via AMB_PREINDEX() or AMB_INDEX() macro! static int get_index(int next) { - int addressing_mode = HAM__; - if (next) GetByte(); if (!Input_accept_comma()) - return addressing_mode; + return INDEX_NONE; + // there was a comma, so check next character (spaces will have been skipped): switch (GotByte) { case 's': case 'S': - addressing_mode = HAM_S; - break; + // if next character is 'p' or 'P', eat that as well, so ",sp" works just like ",s" + GetByte(); + if ((GotByte == 'p') || (GotByte == 'P')) + GetByte(); + SKIPSPACE(); + return INDEX_S; + case 'x': case 'X': - addressing_mode = HAM_X; - break; + NEXTANDSKIPSPACE(); + return INDEX_X; + case 'y': case 'Y': - addressing_mode = HAM_Y; - break; - default: - Throw_error(exception_syntax); - } - if (addressing_mode != HAM__) NEXTANDSKIPSPACE(); - return addressing_mode; + return INDEX_Y; + + case 'z': + case 'Z': + NEXTANDSKIPSPACE(); + return INDEX_Z; + } + Throw_error(exception_syntax); + return INDEX_NONE; } // This function stores the command's argument in the given result @@ -423,7 +524,7 @@ static int get_index(int next) static int get_argument(struct result *result) { int open_paren, - addressing_mode = HAM_ABS; + address_mode_bits = 0; SKIPSPACE(); switch (GotByte) { @@ -432,15 +533,15 @@ static int get_argument(struct result *result) ALU_int_result(result); typesystem_want_addr(result); if (GotByte == ']') - addressing_mode |= HAM_LIND | get_index(TRUE); + address_mode_bits |= AMB_LONGINDIRECT | AMB_INDEX(get_index(TRUE)); else Throw_error(exception_syntax); break; case '#': GetByte(); // proceed with next char - addressing_mode |= HAM_IMM; + address_mode_bits |= AMB_IMMEDIATE; ALU_int_result(result); - typesystem_want_imm(result); + typesystem_want_imm(result); // FIXME - this is wrong for 65ce02's PHW# break; default: // liberal, to allow for "(...," @@ -448,27 +549,27 @@ static int get_argument(struct result *result) typesystem_want_addr(result); // check for implied addressing if ((result->flags & MVALUE_EXISTS) == 0) - addressing_mode |= HAM_IMP; + address_mode_bits |= AMB_IMPLIED; // check for indirect addressing if (result->flags & MVALUE_INDIRECT) - addressing_mode |= HAM_IND; + address_mode_bits |= AMB_INDIRECT; // check for internal index (before closing parenthesis) if (open_paren) { // in case there are still open parentheses, // read internal index - addressing_mode |= (get_index(FALSE) << 2); + address_mode_bits |= AMB_PREINDEX(get_index(FALSE)); if (GotByte == ')') GetByte(); // go on with next char else Throw_error(exception_syntax); } // check for external index (after closing parenthesis) - addressing_mode |= get_index(FALSE); + address_mode_bits |= AMB_INDEX(get_index(FALSE)); } // ensure end of line Input_ensure_EOS(); //printf("AM: %x\n", addressing_mode); - return addressing_mode; + return address_mode_bits; } // Helper function for calc_arg_size() @@ -594,6 +695,9 @@ static int calc_arg_size(int force_bit, struct result *argument, int addressing_ // Mnemonics using only implied addressing. static void group_only_implied_addressing(int opcode) { + // for 65ce02 and 4502, warn about buggy decimal mode + if ((opcode == 248) && (CPU_state.type->flags & CPUFLAG_DECIMALSUBTRACTBUGGY)) + Throw_first_pass_warning("Found SED instruction for CPU with known decimal SBC bug."); Output_byte(opcode); Input_ensure_EOS(); } @@ -607,8 +711,8 @@ static void not_in_bank(intval_t target) Throw_error(buffer); } -// Mnemonics using only 8bit relative addressing (short branch instructions). -static void group_only_relative8_addressing(int opcode) +// helper function for branches with 8-bit offset (including bbr0..7/bbs0..7) +static void near_branch(int preoffset) { struct result target; intval_t offset = 0; // dummy value, to not throw more errors than necessary @@ -620,7 +724,7 @@ static void group_only_relative8_addressing(int opcode) if ((target.val.intval | 0xffff) != 0xffff) { not_in_bank(target.val.intval); } else { - offset = (target.val.intval - (CPU_state.pc.val.intval + 2)) & 0xffff; // clip to 16 bit offset + offset = (target.val.intval - (CPU_state.pc.val.intval + preoffset)) & 0xffff; // clip to 16 bit offset // fix sign if (offset & 0x8000) offset -= 0x10000; @@ -633,7 +737,6 @@ static void group_only_relative8_addressing(int opcode) } } } - Output_byte(opcode); // this fn has its own range check (see above). // No reason to irritate the user with another error message, // so use Output_byte() instead of output_8() @@ -642,8 +745,8 @@ static void group_only_relative8_addressing(int opcode) Input_ensure_EOS(); } -// Mnemonics using only 16bit relative addressing (BRL and PER). -static void group_only_relative16_addressing(int opcode) +// helper function for relative addressing with 16-bit offset +static void far_branch(int preoffset) { struct result target; intval_t offset = 0; // dummy value, to not throw more errors than necessary @@ -655,11 +758,10 @@ static void group_only_relative16_addressing(int opcode) if ((target.val.intval | 0xffff) != 0xffff) { not_in_bank(target.val.intval); } else { - offset = (target.val.intval - (CPU_state.pc.val.intval + 3)) & 0xffff; + offset = (target.val.intval - (CPU_state.pc.val.intval + preoffset)) & 0xffff; // no further checks necessary, 16-bit branches can access whole bank } } - Output_byte(opcode); output_le16(offset); Input_ensure_EOS(); } @@ -694,67 +796,83 @@ static void make_command(int force_bit, struct result *result, unsigned long opc // check whether 16bit immediate addressing is allowed. If not, return given // opcode. If it is allowed, set force bits according to CPU register length // and return given opcode for both 8- and 16-bit mode. -static unsigned int imm_ops(int *force_bit, unsigned char opcode, int imm_flag) +static unsigned int imm_ops(int *force_bit, unsigned char opcode, int immediate_mode) { - // if the CPU does not allow 16bit immediate addressing (or if the - // opcode does not allow it), return immediately. - if (((CPU_state.type->flags & CPUFLAG_SUPPORTSLONGREGS) == 0) || (imm_flag == 0)) - return opcode; + int long_register = 0; - // check force bits (if no force bits given, use relevant flag) + switch (immediate_mode) { + case IM_FORCE8: + return opcode; // result in bits 0..7 forces single-byte argument + + case IM_FORCE16: // currently only for 65ce02's PHW# + return ((unsigned int) opcode) << 8; // opcode in bits8.15 forces two-byte argument + + case IM_ACCUMULATOR: // for 65816 + long_register = CPU_state.a_is_long; + break; + case IM_INDEXREGS: // for 65816 + long_register = CPU_state.xy_are_long; + break; + default: + Bug_found("IllegalImmediateMode", immediate_mode); + } + // if the CPU does not support long registers... + if ((CPU_state.type->flags & CPUFLAG_SUPPORTSLONGREGS) == 0) + return opcode; // result in bits 0..7 forces single-byte argument + + // check force bits - if no force bits given, use cpu state and convert to force bit if (*force_bit == 0) - *force_bit = ((imm_flag & IMM_ACCU) ? - CPU_state.a_is_long : - CPU_state.xy_are_long) ? - MVALUE_FORCE16 : - MVALUE_FORCE08; - // return identical opcodes for 8bit and 16bit args! + *force_bit = long_register ? MVALUE_FORCE16 : MVALUE_FORCE08; + // return identical opcodes for single-byte and two-byte arguments: return (((unsigned int) opcode) << 8) | opcode; } // The main accumulator stuff (ADC, AND, CMP, EOR, LDA, ORA, SBC, STA) // plus PEI. -static void group_main(int index, int imm_flag) +static void group_main(int index, int immediate_mode) { - unsigned long imm_opcodes; + unsigned long immediate_opcodes; struct result result; int force_bit = Input_get_force_bit(); // skips spaces after switch (get_argument(&result)) { - case HAM_IMM: // #$ff or #$ffff (depending on accu length) - imm_opcodes = imm_ops(&force_bit, accu_imm[index], imm_flag); + case IMMEDIATE_ADDRESSING: // #$ff or #$ffff (depending on accu length) + immediate_opcodes = imm_ops(&force_bit, accu_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, imm_opcodes); + make_command(force_bit, &result, immediate_opcodes); break; - case HAM_ABS: // $ff, $ffff, $ffffff + case ABSOLUTE_ADDRESSING: // $ff, $ffff, $ffffff make_command(force_bit, &result, accu_abs[index]); break; - case HAM_ABSX: // $ff,x, $ffff,x, $ffffff,x + case X_INDEXED_ADDRESSING: // $ff,x, $ffff,x, $ffffff,x make_command(force_bit, &result, accu_xabs[index]); break; - case HAM_ABSY: // $ffff,y (in theory, "$ff,y" as well) + case Y_INDEXED_ADDRESSING: // $ffff,y (in theory, "$ff,y" as well) make_command(force_bit, &result, accu_yabs[index]); break; - case HAM_ABSS: // $ff,s + case STACK_INDEXED_ADDRESSING: // $ff,s make_command(force_bit, &result, accu_sabs8[index]); break; - case HAM_XIND: // ($ff,x) + case X_INDEXED_INDIRECT_ADDRESSING: // ($ff,x) make_command(force_bit, &result, accu_xind8[index]); break; - case HAM_IND: // ($ff) + case INDIRECT_ADDRESSING: // ($ff) make_command(force_bit, &result, accu_ind8[index]); break; - case HAM_INDY: // ($ff),y + case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y make_command(force_bit, &result, accu_indy8[index]); break; - case HAM_LIND: // [$ff] + case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z + make_command(force_bit, &result, accu_indz8[index]); + break; + case LONG_INDIRECT_ADDRESSING: // [$ff] make_command(force_bit, &result, accu_lind8[index]); break; - case HAM_LINDY: // [$ff],y + case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y make_command(force_bit, &result, accu_lindy8[index]); break; - case HAM_SINDY: // ($ff,s),y + case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y make_command(force_bit, &result, accu_sindy8[index]); break; default: // other combinations are illegal @@ -763,41 +881,41 @@ static void group_main(int index, int imm_flag) } // Various mnemonics with different addressing modes. -static void group_misc(int index, int imm_flag) +static void group_misc(int index, int immediate_mode) { - unsigned long imm_opcodes; + unsigned long immediate_opcodes; struct result result; int force_bit = Input_get_force_bit(); // skips spaces after switch (get_argument(&result)) { - case HAM_IMP: // implied addressing + case IMPLIED_ADDRESSING: // implied addressing if (misc_impl[index]) Output_byte(misc_impl[index]); else Throw_error(exception_illegal_combination); break; - case HAM_IMM: // #$ff or #$ffff (depending on index register length) - imm_opcodes = imm_ops(&force_bit, misc_imm[index], imm_flag); + case IMMEDIATE_ADDRESSING: // #$ff or #$ffff (depending on index register length) + 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, imm_opcodes); + make_command(force_bit, &result, immediate_opcodes); // check whether to warn about 6510's unstable ANE/LXA if ((CPU_state.type->flags & CPUFLAG_8B_AND_AB_NEED_0_ARG) && ((result.val.intval & 0xff) != 0x00) && (result.flags & MVALUE_DEFINED)) { - if (imm_opcodes == 0x8b) + if (immediate_opcodes == 0x8b) Throw_warning("Assembling unstable ANE #NONZERO instruction"); - else if (imm_opcodes == 0xab) + else if (immediate_opcodes == 0xab) Throw_warning("Assembling unstable LXA #NONZERO instruction"); } break; - case HAM_ABS: // $ff or $ffff + case ABSOLUTE_ADDRESSING: // $ff or $ffff make_command(force_bit, &result, misc_abs[index]); break; - case HAM_ABSX: // $ff,x or $ffff,x + case X_INDEXED_ADDRESSING: // $ff,x or $ffff,x make_command(force_bit, &result, misc_xabs[index]); break; - case HAM_ABSY: // $ff,y or $ffff,y + case Y_INDEXED_ADDRESSING: // $ff,y or $ffff,y make_command(force_bit, &result, misc_yabs[index]); break; default: // other combinations are illegal @@ -805,25 +923,70 @@ static void group_misc(int index, int imm_flag) } } -// Mnemonics using "8bit, 8bit" addressing. Only applies to "MVN" and "MVP". -static void group_move(int opcode) +// mnemonics using only 8bit relative addressing (short branch instructions). +static void group_std_branches(int opcode) { - intval_t source, + Output_byte(opcode); + near_branch(2); +} + +// "bbr0..7" and "bbs0..7" +static void group_bbr_bbs(int opcode) +{ + struct result zpmem; + + ALU_int_result(&zpmem); + typesystem_want_addr(&zpmem); + if (Input_accept_comma()) { + Output_byte(opcode); + Output_byte(zpmem.val.intval); + near_branch(3); + } else { + Throw_error(exception_syntax); + } +} + +// mnemonics using only 16bit relative addressing (BRL and PER of 65816, and the long branches of 65ce02) +static void group_relative16(int opcode, int preoffset) +{ + Output_byte(opcode); + far_branch(preoffset); +} + +// "mvn" and "mvp" +static void group_mvn_mvp(int opcode) +{ + struct result source, target; - // assembler syntax: "opcode source, target" - source = ALU_any_int(); + // assembler syntax: "mnemonic source, target" + ALU_int_result(&source); + typesystem_want_imm(&source); if (Input_accept_comma()) { - target = ALU_any_int(); // machine language: - Output_byte(opcode); // opcode - output_8(target); // target - output_8(source); // source + ALU_int_result(&target); + typesystem_want_imm(&target); + // machine language order: "opcode target source" + Output_byte(opcode); + output_8(target.val.intval); + output_8(source.val.intval); Input_ensure_EOS(); } else { Throw_error(exception_syntax); } } +// "rmb0..7" and "smb0..7" +static void group_rmb_smb(int opcode) +{ + struct result target; + + ALU_int_result(&target); + typesystem_want_addr(&target); + Output_byte(opcode); + output_8(target.val.intval); + Input_ensure_EOS(); +} + // The jump instructions. static void group_jump(int index) { @@ -831,10 +994,10 @@ static void group_jump(int index) int force_bit = Input_get_force_bit(); // skips spaces after switch (get_argument(&result)) { - case HAM_ABS: // absolute16 or absolute24 + case ABSOLUTE_ADDRESSING: // absolute16 or absolute24 make_command(force_bit, &result, jump_abs[index]); break; - case HAM_IND: // ($ffff) + case INDIRECT_ADDRESSING: // ($ffff) make_command(force_bit, &result, jump_ind[index]); // check whether to warn about 6502's JMP() bug if (((result.val.intval & 0xff) == 0xff) @@ -842,10 +1005,10 @@ static void group_jump(int index) && (CPU_state.type->flags & CPUFLAG_INDIRECTJMPBUGGY)) Throw_warning("Assembling buggy JMP($xxff) instruction"); break; - case HAM_XIND: // ($ffff,x) + case X_INDEXED_INDIRECT_ADDRESSING: // ($ffff,x) make_command(force_bit, &result, jump_xind[index]); break; - case HAM_LIND: // [$ffff] + case LONG_INDIRECT_ADDRESSING: // [$ffff] make_command(force_bit, &result, jump_lind[index]); break; default: // other combinations are illegal @@ -858,20 +1021,20 @@ static int check_mnemo_tree(struct ronode *tree, struct dynabuf *dyna_buf) { void *node_body; int code, - imm_flag; // flag for immediate addressing + immediate_mode; // size of immediate argument // search for tree item if (!Tree_easy_scan(tree, &node_body, dyna_buf)) return FALSE; code = ((int) node_body) & CODEMASK; // get opcode or table index - imm_flag = ((int) node_body) & FLAGSMASK; // get flag - switch (((long) node_body) >> GROUPSHIFT) { + immediate_mode = ((int) node_body) & IMMASK; // get immediate mode + switch (GROUP((long) node_body)) { case GROUP_ACCU: // main accumulator stuff - group_main(code, imm_flag); + group_main(code, immediate_mode); break; case GROUP_MISC: // misc - group_misc(code, imm_flag); + group_misc(code, immediate_mode); break; case GROUP_ALLJUMPS: // the jump instructions group_jump(code); @@ -880,13 +1043,22 @@ static int check_mnemo_tree(struct ronode *tree, struct dynabuf *dyna_buf) group_only_implied_addressing(code); break; case GROUP_RELATIVE8: // short relative - group_only_relative8_addressing(code); + group_std_branches(code); break; - case GROUP_RELATIVE16: // long relative - group_only_relative16_addressing(code); + case GROUP_BITBRANCH: // "bbr0..7" and "bbs0..7" + group_bbr_bbs(code); + break; + case GROUP_REL16_2: // long relative to pc+2 + group_relative16(code, 2); + break; + case GROUP_REL16_3: // long relative to pc+3 + group_relative16(code, 3); break; case GROUP_BOTHMOVES: // "mvp" and "mvn" - group_move(code); + group_mvn_mvp(code); + break; + case GROUP_MEMBIT: // "rmb0..7" and "smb0..7" + group_rmb_smb(code); break; default: // others indicate bugs Bug_found("IllegalGroupIndex", code); @@ -894,8 +1066,8 @@ static int check_mnemo_tree(struct ronode *tree, struct dynabuf *dyna_buf) return TRUE; } -// Check whether mnemonic in GlobalDynaBuf is supported by 6502 cpu. -int keyword_is_6502mnemo(int length) +// check whether mnemonic in GlobalDynaBuf is supported by 6502 cpu. +int keyword_is_6502_mnemo(int length) { if (length != 3) return FALSE; @@ -905,8 +1077,8 @@ int keyword_is_6502mnemo(int length) return check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf) ? TRUE : FALSE; } -// Check whether mnemonic in GlobalDynaBuf is supported by 6510 cpu. -int keyword_is_6510mnemo(int length) +// check whether mnemonic in GlobalDynaBuf is supported by 6510 cpu. +int keyword_is_6510_mnemo(int length) { if (length != 3) return FALSE; @@ -925,8 +1097,8 @@ int keyword_is_6510mnemo(int length) return check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf) ? TRUE : FALSE; } -// Check whether mnemonic in GlobalDynaBuf is supported by C64DTV2 cpu. -int keyword_is_c64dtv2mnemo(int length) +// check whether mnemonic in GlobalDynaBuf is supported by C64DTV2 cpu. +int keyword_is_c64dtv2_mnemo(int length) { if (length != 3) return FALSE; @@ -945,15 +1117,15 @@ int keyword_is_c64dtv2mnemo(int length) return check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf) ? TRUE : FALSE; } -// Check whether mnemonic in GlobalDynaBuf is supported by 65c02 cpu. -int keyword_is_65c02mnemo(int length) +// check whether mnemonic in GlobalDynaBuf is supported by 65c02 cpu. +int keyword_is_65c02_mnemo(int length) { if (length != 3) return FALSE; // make lower case version of mnemonic in local dynamic buffer DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); - // first check extensions... + // first check extensions because some mnemonics gained new addressing modes... if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) return TRUE; @@ -961,63 +1133,119 @@ int keyword_is_65c02mnemo(int length) return check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf) ? TRUE : FALSE; } -//// Check whether mnemonic in GlobalDynaBuf is supported by Rockwell 65c02 cpu. -//int keyword_is_Rockwell65c02mnemo(int length) -//{ -// if ((length != 3) && (length != 4)) -// return FALSE; -// -// // make lower case version of mnemonic in local dynamic buffer -// DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); -// // first check 65c02 extensions... -// if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) -// return TRUE; -// -// // ...then check original opcodes... -// if (check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf)) -// return TRUE; -// -// // ...then check Rockwell/WDC extensions (rmb, smb, bbr, bbs) -// return check_mnemo_tree(mnemo_Rockwell65c02_tree, mnemo_dyna_buf) ? TRUE : FALSE; -//} +// check whether mnemonic in GlobalDynaBuf is supported by Rockwell 65c02 cpu. +int keyword_is_r65c02_mnemo(int length) +{ + if ((length != 3) && (length != 4)) + return FALSE; -//// Check whether mnemonic in GlobalDynaBuf is supported by WDC 65c02 cpu. -//int keyword_is_WDC65c02mnemo(int length) -//{ -// if ((length != 3) && (length != 4)) -// return FALSE; -// -// // make lower case version of mnemonic in local dynamic buffer -// DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); -// // first check 65c02 extensions... -// if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) -// return TRUE; -// -// // ...then check original opcodes... -// if (check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf)) -// return TRUE; -// -// // ...then check Rockwell/WDC extensions (rmb, smb, bbr, bbs)... -// if (check_mnemo_tree(mnemo_Rockwell65c02_tree, mnemo_dyna_buf)) -// return TRUE; -// -// // ...then check WDC extensions (only two mnemonics, so do last) -// return check_mnemo_tree(mnemo_WDC65c02_tree, mnemo_dyna_buf) ? TRUE : FALSE; -//} + // make lower case version of mnemonic in local dynamic buffer + DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); + // first check 65c02 extensions because some mnemonics gained new addressing modes... + if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) + return TRUE; -// Check whether mnemonic in GlobalDynaBuf is supported by 65816 cpu. -int keyword_is_65816mnemo(int length) + // ...then check original opcodes... + if (check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check Rockwell extensions (rmb, smb, bbr, bbs) + return check_mnemo_tree(mnemo_bitmanips_tree, mnemo_dyna_buf) ? TRUE : FALSE; +} + +// check whether mnemonic in GlobalDynaBuf is supported by WDC w65c02 cpu. +int keyword_is_w65c02_mnemo(int length) +{ + if ((length != 3) && (length != 4)) + return FALSE; + + // make lower case version of mnemonic in local dynamic buffer + DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); + // first check 65c02 extensions because some mnemonics gained new addressing modes... + if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check original opcodes... + if (check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check Rockwell extensions (rmb, smb, bbr, bbs)... + if (check_mnemo_tree(mnemo_bitmanips_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check WDC extensions "stp" and "wai" + return check_mnemo_tree(mnemo_stp_wai_tree, mnemo_dyna_buf) ? TRUE : FALSE; +} + +// check whether mnemonic in GlobalDynaBuf is supported by CSG 65CE02 cpu. +int keyword_is_65ce02_mnemo(int length) +{ + if ((length != 3) && (length != 4)) + return FALSE; + + // make lower case version of mnemonic in local dynamic buffer + DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); + // first check 65ce02 extensions because some mnemonics gained new addressing modes... + if (check_mnemo_tree(mnemo_65ce02_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check 65c02 extensions because of the same reason... + if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check original opcodes... + if (check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check Rockwell extensions (rmb, smb, bbr, bbs)... + if (check_mnemo_tree(mnemo_bitmanips_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check "aug" + return check_mnemo_tree(mnemo_aug_tree, mnemo_dyna_buf) ? TRUE : FALSE; +} + +// check whether mnemonic in GlobalDynaBuf is supported by CSG 4502 cpu. +int keyword_is_4502_mnemo(int length) +{ + if ((length != 3) && (length != 4)) + return FALSE; + + // make lower case version of mnemonic in local dynamic buffer + DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); + // first check 65ce02 extensions because some mnemonics gained new addressing modes... + if (check_mnemo_tree(mnemo_65ce02_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check 65c02 extensions because of the same reason... + if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check original opcodes... + if (check_mnemo_tree(mnemo_6502_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check Rockwell extensions (rmb, smb, bbr, bbs)... + if (check_mnemo_tree(mnemo_bitmanips_tree, mnemo_dyna_buf)) + return TRUE; + + // ...then check "map" and "eom" + return check_mnemo_tree(mnemo_map_eom_tree, mnemo_dyna_buf) ? TRUE : FALSE; +} + +// check whether mnemonic in GlobalDynaBuf is supported by 65816 cpu. +int keyword_is_65816_mnemo(int length) { if (length != 3) return FALSE; // make lower case version of mnemonic in local dynamic buffer DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf); - // first check "new" extensions... + // first check 65816 extensions because some mnemonics gained new addressing modes... if (check_mnemo_tree(mnemo_65816_tree, mnemo_dyna_buf)) return TRUE; - // ...then "old" extensions... + // ...then check 65c02 extensions because of the same reason... if (check_mnemo_tree(mnemo_65c02_tree, mnemo_dyna_buf)) return TRUE; @@ -1026,5 +1254,5 @@ int keyword_is_65816mnemo(int length) return TRUE; // ...then check WDC extensions "stp" and "wai" - return check_mnemo_tree(mnemo_WDC65c02_tree, mnemo_dyna_buf) ? TRUE : FALSE; + return check_mnemo_tree(mnemo_stp_wai_tree, mnemo_dyna_buf) ? TRUE : FALSE; } diff --git a/src/mnemo.h b/src/mnemo.h index edf1af4..5abb7b1 100644 --- a/src/mnemo.h +++ b/src/mnemo.h @@ -1,30 +1,32 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // -// Mnemonic definitions +// mnemonic definitions #ifndef mnemo_H #define mnemo_H -// Prototypes - // create dynamic buffer, build keyword trees extern void Mnemo_init(void); -// Check whether mnemonic in GlobalDynaBuf is supported by 6502 cpu. -extern int keyword_is_6502mnemo(int length); -// Check whether mnemonic in GlobalDynaBuf is supported by 6510 cpu. -extern int keyword_is_6510mnemo(int length); -// Check whether mnemonic in GlobalDynaBuf is supported by C64DTV2 cpu. -extern int keyword_is_c64dtv2mnemo(int length); -// Check whether mnemonic in GlobalDynaBuf is supported by 65c02 cpu. -extern int keyword_is_65c02mnemo(int length); -// Check whether mnemonic in GlobalDynaBuf is supported by Rockwell 65c02 cpu. -//extern int keyword_is_Rockwell65c02mnemo(int length); -// Check whether mnemonic in GlobalDynaBuf is supported by WDC 65c02 cpu. -//extern int keyword_is_WDC65c02mnemo(int length); -// Check whether mnemonic in GlobalDynaBuf is supported by 65816 cpu. -extern int keyword_is_65816mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by 6502 cpu. +extern int keyword_is_6502_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by 6510 cpu. +extern int keyword_is_6510_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by C64DTV2 cpu. +extern int keyword_is_c64dtv2_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by 65c02 cpu. +extern int keyword_is_65c02_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by Rockwell 65c02 cpu. +extern int keyword_is_r65c02_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by WDC 65c02 cpu. +extern int keyword_is_w65c02_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by 65816 cpu. +extern int keyword_is_65816_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by CSG 65ce02 cpu. +extern int keyword_is_65ce02_mnemo(int length); +// check whether mnemonic in GlobalDynaBuf is supported by CSG 4502 cpu. +extern int keyword_is_4502_mnemo(int length); #endif diff --git a/src/output.c b/src/output.c index ed1ce0f..67c372e 100644 --- a/src/output.c +++ b/src/output.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/output.h b/src/output.h index f29a47c..965319b 100644 --- a/src/output.h +++ b/src/output.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/platform.c b/src/platform.c index 726447a..f9155a4 100644 --- a/src/platform.c +++ b/src/platform.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff diff --git a/src/platform.h b/src/platform.h index 760238a..063ee66 100644 --- a/src/platform.h +++ b/src/platform.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2009 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Platform specific stuff diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index e213ea7..002fc91 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/pseudoopcodes.h b/src/pseudoopcodes.h index b61a2b3..7b6047e 100644 --- a/src/pseudoopcodes.h +++ b/src/pseudoopcodes.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // pseudo opcode stuff diff --git a/src/section.c b/src/section.c index 6d71fd6..1e6df0f 100644 --- a/src/section.c +++ b/src/section.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/section.h b/src/section.h index 768e434..7bf3812 100644 --- a/src/section.h +++ b/src/section.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/symbol.c b/src/symbol.c index e542738..f85d69a 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/symbol.h b/src/symbol.h index 2cf1d8e..7e443e0 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/tree.c b/src/tree.c index d4be38e..adf65b9 100644 --- a/src/tree.c +++ b/src/tree.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // tree stuff diff --git a/src/tree.h b/src/tree.h index e38622d..d4290da 100644 --- a/src/tree.h +++ b/src/tree.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // diff --git a/src/typesystem.c b/src/typesystem.c index 66913ce..8206d8e 100644 --- a/src/typesystem.c +++ b/src/typesystem.c @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // type system stuff diff --git a/src/typesystem.h b/src/typesystem.h index 590fd5a..bc46fd2 100644 --- a/src/typesystem.h +++ b/src/typesystem.h @@ -1,5 +1,5 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. -// Copyright (C) 1998-2014 Marco Baye +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. +// Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // // Type system stuff diff --git a/src/version.h b/src/version.h index e1595b6..69e2c0a 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ -// ACME - a crossassembler for producing 6502/65c02/65816 code. +// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code. // Copyright (C) 1998-2016 Marco Baye // Have a look at "acme.c" for further info // @@ -7,9 +7,9 @@ #define version_H -#define RELEASE "0.95.8" // update before release (FIXME) +#define RELEASE "0.96" // update before release (FIXME) #define CODENAME "Fenchurch" // update before release -#define CHANGE_DATE "8 Oct" // update before release +#define CHANGE_DATE "28 Dec" // update before release #define CHANGE_YEAR "2016" // update before release //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME