2016-12-28 20:32:00 +00:00
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
2020-04-14 00:28:31 +00:00
// Copyright (C) 1998-2020 Marco Baye
2012-02-27 21:14:46 +00:00
// Have a look at "acme.c" for further info
//
// Mnemonics stuff
2014-12-22 00:47:52 +00:00
# include "mnemo.h"
2012-02-27 21:14:46 +00:00
# include "config.h"
# include "alu.h"
# include "cpu.h"
# include "dynabuf.h"
# include "global.h"
# include "input.h"
# include "output.h"
# include "tree.h"
2014-06-02 00:47:46 +00:00
# include "typesystem.h"
2012-02-27 21:14:46 +00:00
2020-07-12 18:46:06 +00:00
// constants
2020-08-16 17:39:13 +00:00
# define MNEMO_INITIALSIZE 8 // 4 + terminator should suffice
2012-02-27 21:14:46 +00:00
2016-12-28 20:32:00 +00:00
// 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")
2020-05-21 19:36:59 +00:00
# define INDEX_Z 4 // z-indexed (",z"), only for 65ce02/4502/m65
2016-12-28 20:32:00 +00:00
// 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
// 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))
2020-05-21 19:36:59 +00:00
// only for 65ce02/4502/m65:
2016-12-28 20:32:00 +00:00
# define INDIRECT_Z_INDEXED_ADDRESSING (AMB_INDIRECT | AMB_INDEX(INDEX_Z))
2020-05-21 19:36:59 +00:00
// for 65816 and 65ce02/4502:
2016-12-28 20:32:00 +00:00
# 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))
2020-05-21 19:36:59 +00:00
// only for m65:
# define LONG_INDIRECT_Z_INDEXED_ADDRESSING (AMB_LONGINDIRECT | AMB_INDEX(INDEX_Z))
2012-02-27 21:14:46 +00:00
2020-07-18 13:50:46 +00:00
// constant values, used to mark the possible parameter lengths of instructions.
2020-04-28 16:02:09 +00:00
// 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
# define MAYBE___2__ NUMBER_FORCES_16
# define MAYBE_____3 NUMBER_FORCES_24
2012-02-27 21:14:46 +00:00
// The mnemonics are split up into groups, each group has its own function to be dealt with:
2014-11-25 16:15:22 +00:00
enum mnemogroup {
2012-02-27 21:14:46 +00:00
GROUP_ACCU , // main accumulator stuff, plus PEI Byte value = table index
GROUP_MISC , // read-modify-write and others Byte value = table index
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
2016-12-28 20:32:00 +00:00
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
2020-07-18 13:50:46 +00:00
GROUP_BOTHMOVES , // the "move" instructions MVP and MVN Byte value = opcode
GROUP_ZPONLY , // rmb0..7, smb0..7, inw, dew Byte value = opcode
2020-06-03 11:02:16 +00:00
GROUP_PREFIX , // NOP on m65 (throws error) Byte value = opcode
2012-02-27 21:14:46 +00:00
} ;
2020-07-18 13:50:46 +00:00
// TODO: make sure groups like IMPLIEDONLY and ZPONLY output
// "Mnemonic does not support this addressing mode" instead of
// "Garbage data at end of statement".
2020-07-29 23:30:33 +00:00
// TODO: maybe add GROUP_IMMEDIATEONLY?
// (for RTN, REP, SEP, ANC, ALR, ARR, SBX, LXA, ANE, SAC, SIR)
2012-02-27 21:14:46 +00:00
// save some space
# define SCB static const unsigned char
# define SCS static const unsigned short
# define SCL static const unsigned long
// Code tables for group GROUP_ACCU:
// These tables are used for the main accumulator-related mnemonics. By reading
// the mnemonic's byte value (from the 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.
2020-05-29 13:04:28 +00:00
// | 6502/65c02/65816/65ce02/4502/m65 | 65816 | NMOS 6502 undocumented opcodes |
2020-06-02 15:09:36 +00:00
enum { IDX_ORA , IDXcORA , IDX16ORA , IDXeORA , IDXmORA , IDXmORQ , IDX_AND , IDXcAND , IDX16AND , IDXeAND , IDXmAND , IDXmANDQ , IDX_EOR , IDXcEOR , IDX16EOR , IDXeEOR , IDXmEOR , IDXmEORQ , IDX_ADC , IDXcADC , IDX16ADC , IDXeADC , IDXmADC , IDXmADCQ , IDX_STA , IDXcSTA , IDX16STA , IDXeSTA , IDXmSTA , IDXmSTQ , IDX_LDA , IDXcLDA , IDX16LDA , IDXeLDA , IDXmLDA , IDXmLDQ , IDX_CMP , IDXcCMP , IDX16CMP , IDXeCMP , IDXmCMP , IDXmCPQ , IDX_SBC , IDXcSBC , IDX16SBC , IDXeSBC , IDXmSBC , IDXmSBCQ , IDX16PEI , IDXuSLO , IDXuRLA , IDXuSRE , IDXuRRA , IDXuSAX , IDXuLAX , IDXuDCP , IDXuISC , IDXuSHA } ;
2020-05-21 23:46:11 +00:00
SCB accu_imm [ ] = { 0x09 , 0x09 , 0x09 , 0x09 , 0x09 , 0 , 0x29 , 0x29 , 0x29 , 0x29 , 0x29 , 0 , 0x49 , 0x49 , 0x49 , 0x49 , 0x49 , 0 , 0x69 , 0x69 , 0x69 , 0x69 , 0x69 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xa9 , 0xa9 , 0xa9 , 0xa9 , 0xa9 , 0 , 0xc9 , 0xc9 , 0xc9 , 0xc9 , 0xc9 , 0 , 0xe9 , 0xe9 , 0xe9 , 0xe9 , 0xe9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // #$ff #$ffff
SCL accu_abs [ ] = { 0x0d05 , 0x0d05 , 0x0f0d05 , 0x0d05 , 0x0d05 , 0x0d05 , 0x2d25 , 0x2d25 , 0x2f2d25 , 0x2d25 , 0x2d25 , 0x2d25 , 0x4d45 , 0x4d45 , 0x4f4d45 , 0x4d45 , 0x4d45 , 0x4d45 , 0x6d65 , 0x6d65 , 0x6f6d65 , 0x6d65 , 0x6d65 , 0x6d65 , 0x8d85 , 0x8d85 , 0x8f8d85 , 0x8d85 , 0x8d85 , 0x8d85 , 0xada5 , 0xada5 , 0xafada5 , 0xada5 , 0xada5 , 0xada5 , 0xcdc5 , 0xcdc5 , 0xcfcdc5 , 0xcdc5 , 0xcdc5 , 0xcdc5 , 0xede5 , 0xede5 , 0xefede5 , 0xede5 , 0xede5 , 0xede5 , 0 , 0x0f07 , 0x2f27 , 0x4f47 , 0x6f67 , 0x8f87 , 0xafa7 , 0xcfc7 , 0xefe7 , 0 } ; // $ff $ffff $ffffff
2020-07-29 23:30:33 +00:00
SCL accu_xabs [ ] = { 0x1d15 , 0x1d15 , 0x1f1d15 , 0x1d15 , 0x1d15 , 0 , 0x3d35 , 0x3d35 , 0x3f3d35 , 0x3d35 , 0x3d35 , 0 , 0x5d55 , 0x5d55 , 0x5f5d55 , 0x5d55 , 0x5d55 , 0 , 0x7d75 , 0x7d75 , 0x7f7d75 , 0x7d75 , 0x7d75 , 0 , 0x9d95 , 0x9d95 , 0x9f9d95 , 0x9d95 , 0x9d95 , 0 , 0xbdb5 , 0xbdb5 , 0xbfbdb5 , 0xbdb5 , 0xbdb5 , 0xbdb5 , 0xddd5 , 0xddd5 , 0xdfddd5 , 0xddd5 , 0xddd5 , 0 , 0xfdf5 , 0xfdf5 , 0xfffdf5 , 0xfdf5 , 0xfdf5 , 0 , 0 , 0x1f17 , 0x3f37 , 0x5f57 , 0x7f77 , 0 , 0 , 0xdfd7 , 0xfff7 , 0 } ; // $ff,x $ffff,x $ffffff,x
SCS accu_yabs [ ] = { 0x1900 , 0x1900 , 0x1900 , 0x1900 , 0x1900 , 0 , 0x3900 , 0x3900 , 0x3900 , 0x3900 , 0x3900 , 0 , 0x5900 , 0x5900 , 0x5900 , 0x5900 , 0x5900 , 0 , 0x7900 , 0x7900 , 0x7900 , 0x7900 , 0x7900 , 0 , 0x9900 , 0x9900 , 0x9900 , 0x9900 , 0x9900 , 0 , 0xb900 , 0xb900 , 0xb900 , 0xb900 , 0xb900 , 0xb900 , 0xd900 , 0xd900 , 0xd900 , 0xd900 , 0xd900 , 0 , 0xf900 , 0xf900 , 0xf900 , 0xf900 , 0xf900 , 0 , 0 , 0x1b00 , 0x3b00 , 0x5b00 , 0x7b00 , 0x97 , 0xbfb7 , 0xdb00 , 0xfb00 , 0x9f00 } ; // $ff,y $ffff,y
SCB accu_xind8 [ ] = { 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0 , 0x41 , 0x41 , 0x41 , 0x41 , 0x41 , 0 , 0x61 , 0x61 , 0x61 , 0x61 , 0x61 , 0 , 0x81 , 0x81 , 0x81 , 0x81 , 0x81 , 0 , 0xa1 , 0xa1 , 0xa1 , 0xa1 , 0xa1 , 0 , 0xc1 , 0xc1 , 0xc1 , 0xc1 , 0xc1 , 0 , 0xe1 , 0xe1 , 0xe1 , 0xe1 , 0xe1 , 0 , 0 , 0x03 , 0x23 , 0x43 , 0x63 , 0x83 , 0xa3 , 0xc3 , 0xe3 , 0 } ; // ($ff,x)
SCB accu_indy8 [ ] = { 0x11 , 0x11 , 0x11 , 0x11 , 0x11 , 0 , 0x31 , 0x31 , 0x31 , 0x31 , 0x31 , 0 , 0x51 , 0x51 , 0x51 , 0x51 , 0x51 , 0 , 0x71 , 0x71 , 0x71 , 0x71 , 0x71 , 0 , 0x91 , 0x91 , 0x91 , 0x91 , 0x91 , 0 , 0xb1 , 0xb1 , 0xb1 , 0xb1 , 0xb1 , 0xb1 , 0xd1 , 0xd1 , 0xd1 , 0xd1 , 0xd1 , 0 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0xf1 , 0 , 0 , 0x13 , 0x33 , 0x53 , 0x73 , 0 , 0xb3 , 0xd3 , 0xf3 , 0x93 } ; // ($ff),y
2020-05-21 23:46:11 +00:00
SCB accu_ind8 [ ] = { 0 , 0x12 , 0x12 , 0 , 0 , 0x12 , 0 , 0x32 , 0x32 , 0 , 0 , 0x32 , 0 , 0x52 , 0x52 , 0 , 0 , 0x52 , 0 , 0x72 , 0x72 , 0 , 0 , 0x72 , 0 , 0x92 , 0x92 , 0 , 0 , 0x92 , 0 , 0xb2 , 0xb2 , 0 , 0 , 0xb2 , 0 , 0xd2 , 0xd2 , 0 , 0 , 0xd2 , 0 , 0xf2 , 0xf2 , 0 , 0 , 0xf2 , 0xd4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // ($ff)
SCB accu_sabs8 [ ] = { 0 , 0 , 0x03 , 0 , 0 , 0 , 0 , 0 , 0x23 , 0 , 0 , 0 , 0 , 0 , 0x43 , 0 , 0 , 0 , 0 , 0 , 0x63 , 0 , 0 , 0 , 0 , 0 , 0x83 , 0 , 0 , 0 , 0 , 0 , 0xa3 , 0 , 0 , 0 , 0 , 0 , 0xc3 , 0 , 0 , 0 , 0 , 0 , 0xe3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // $ff,s
2020-07-29 23:30:33 +00:00
SCB accu_sindy8 [ ] = { 0 , 0 , 0x13 , 0 , 0 , 0 , 0 , 0 , 0x33 , 0 , 0 , 0 , 0 , 0 , 0x53 , 0 , 0 , 0 , 0 , 0 , 0x73 , 0 , 0 , 0 , 0 , 0 , 0x93 , 0x82 , 0x82 , 0 , 0 , 0 , 0xb3 , 0xe2 , 0xe2 , 0xe2 , 0 , 0 , 0xd3 , 0 , 0 , 0 , 0 , 0 , 0xf3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // ($ff,s),y
2020-05-21 23:46:11 +00:00
SCB accu_lind8 [ ] = { 0 , 0 , 0x07 , 0 , 0 , 0x12 , 0 , 0 , 0x27 , 0 , 0 , 0x32 , 0 , 0 , 0x47 , 0 , 0 , 0x52 , 0 , 0 , 0x67 , 0 , 0 , 0x72 , 0 , 0 , 0x87 , 0 , 0 , 0x92 , 0 , 0 , 0xa7 , 0 , 0 , 0xb2 , 0 , 0 , 0xc7 , 0 , 0 , 0xd2 , 0 , 0 , 0xe7 , 0 , 0 , 0xf2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // [$ff]
SCB accu_lindy8 [ ] = { 0 , 0 , 0x17 , 0 , 0 , 0 , 0 , 0 , 0x37 , 0 , 0 , 0 , 0 , 0 , 0x57 , 0 , 0 , 0 , 0 , 0 , 0x77 , 0 , 0 , 0 , 0 , 0 , 0x97 , 0 , 0 , 0 , 0 , 0 , 0xb7 , 0 , 0 , 0 , 0 , 0 , 0xd7 , 0 , 0 , 0 , 0 , 0 , 0xf7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // [$ff],y
SCB accu_indz8 [ ] = { 0 , 0 , 0 , 0x12 , 0x12 , 0 , 0 , 0 , 0 , 0x32 , 0x32 , 0 , 0 , 0 , 0 , 0x52 , 0x52 , 0 , 0 , 0 , 0 , 0x72 , 0x72 , 0 , 0 , 0 , 0 , 0x92 , 0x92 , 0 , 0 , 0 , 0 , 0xb2 , 0xb2 , 0 , 0 , 0 , 0 , 0xd2 , 0xd2 , 0 , 0 , 0 , 0 , 0xf2 , 0xf2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // ($ff),z
SCB accu_lindz8 [ ] = { 0 , 0 , 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0x32 , 0 , 0 , 0 , 0 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0x72 , 0 , 0 , 0 , 0 , 0 , 0x92 , 0 , 0 , 0 , 0 , 0 , 0xb2 , 0 , 0 , 0 , 0 , 0 , 0xd2 , 0 , 0 , 0 , 0 , 0 , 0xf2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // [$ff],z (encoded as a NOP plus ($ff),z)
2012-02-27 21:14:46 +00:00
// Code tables for group GROUP_MISC:
// These tables are needed for finding out the correct code in cases when
// there are no general rules. By reading the mnemonic's byte value (from the
// 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.
2020-07-27 23:37:36 +00:00
// | 6502 | 6502/65c02/65ce02/m65 | 65c02 | 65ce02 | 65816 | NMOS 6502 undocumented opcodes | C64DTV2 |
2020-07-28 23:08:07 +00:00
enum { IDX_ASL , IDX_ROL , IDX_LSR , IDX_ROR , IDX_LDY , IDX_LDX , IDX_CPY , IDX_CPX , IDX_BIT , IDXcBIT , IDXmBITQ , 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 , IDXuALR , IDXuARR , IDXuSBX , IDXuNOP , IDXuDOP , IDXuTOP , IDXuLXA , IDXuANE , IDXuLAS , IDXuTAS , IDXuSHX , IDXuSHY , IDX_SAC , IDX_SIR } ;
2020-07-27 23:37:36 +00:00
SCB misc_impl [ ] = { 0x0a , 0x2a , 0x4a , 0x6a , 0 , 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 , 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 , 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
2020-07-29 23:30:33 +00:00
SCS misc_xabs [ ] = { 0x1e16 , 0x3e36 , 0x5e56 , 0x7e76 , 0xbcb4 , 0 , 0 , 0 , 0 , 0x3c34 , 0 , 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
2020-07-27 23:37:36 +00:00
SCS misc_yabs [ ] = { 0 , 0 , 0 , 0 , 0 , 0xbeb6 , 0 , 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
2012-02-27 21:14:46 +00:00
// Code tables for group GROUP_ALLJUMPS:
// These tables are needed for finding out the correct code when the mnemonic
// is "jmp" or "jsr" (or the long versions "jml" and "jsl").
// By reading the mnemonic's byte value (from the 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.
2020-05-21 19:36:59 +00:00
// | 6502/65c02/65816/65ce02 | 65816 |
enum { IDX_JMP , IDXcJMP , IDX16JMP , IDX_JSR , IDXeJSR , IDX16JSR , IDX16JML , IDX16JSL } ;
SCL jump_abs [ ] = { 0x4c00 , 0x4c00 , 0x5c4c00 , 0x2000 , 0x2000 , 0x222000 , 0x5c0000 , 0x220000 } ; // $ffff $ffffff
SCS jump_ind [ ] = { 0x6c00 , 0x6c00 , 0x6c00 , 0 , 0x2200 , 0 , 0 , 0 } ; // ($ffff)
SCS jump_xind [ ] = { 0 , 0x7c00 , 0x7c00 , 0 , 0x2300 , 0xfc00 , 0 , 0 } ; // ($ffff,x)
SCS jump_lind [ ] = { 0 , 0 , 0xdc00 , 0 , 0 , 0 , 0xdc00 , 0 } ; // [$ffff]
2012-02-27 21:14:46 +00:00
# undef SCB
# undef SCS
# undef SCL
// error message strings
2020-07-18 13:50:46 +00:00
static const char exception_illegal_combination [ ] = " CPU does not support this addressing mode for this mnemonic. " ;
2017-10-21 19:59:56 +00:00
static const char exception_oversized_addrmode [ ] = " Using oversized addressing mode. " ;
2012-02-27 21:14:46 +00:00
// Variables
2020-08-16 17:39:13 +00:00
static STRUCT_DYNABUF_REF ( mnemo_dyna_buf , MNEMO_INITIALSIZE ) ; // for mnemonics
2012-02-27 21:14:46 +00:00
2020-07-18 13:50:46 +00:00
// mnemonic's code, flags and group values are stored together in a single integer.
2020-05-21 23:46:11 +00:00
// ("code" is either a table index or the opcode itself, depending on group value)
2012-02-27 21:14:46 +00:00
// To extract the code, use "& CODEMASK".
2020-05-21 23:46:11 +00:00
// To extract the flags, use "& FLAGSMASK".
// To extract only the immediate mode flags, use "& IMMASK".
2016-12-28 20:32:00 +00:00
// 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
2020-05-21 23:46:11 +00:00
# define IMMASK 0x300 // mask for immediate mode flags
# define PREFIX_NEGNEG 0x400 // output NEG:NEG before actual opcode
# define LI_PREFIX_NOP 0x800 // when using long indirect addressing, output NOP before actual opcode
# define FLAGSMASK 0xf00 // mask for all four flags
# define MERGE(g, v) (((g) << 12) | (v))
# define GROUP(v) ((v) >> 12)
2012-02-27 21:14:46 +00:00
2020-08-15 14:55:22 +00:00
// 6502 mnemonics
static struct ronode mnemo_6502_tree [ ] = {
PREDEF_START ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " ora " , MERGE ( GROUP_ACCU , IDX_ORA ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " and " , MERGE ( GROUP_ACCU , IDX_AND ) ) ,
PREDEFNODE ( " eor " , MERGE ( GROUP_ACCU , IDX_EOR ) ) ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " adc " , MERGE ( GROUP_ACCU , IDX_ADC ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " sta " , MERGE ( GROUP_ACCU , IDX_STA ) ) ,
2016-12-28 20:32:00 +00:00
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 ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " asl " , MERGE ( GROUP_MISC , IDX_ASL ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " rol " , MERGE ( GROUP_MISC , IDX_ROL ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " lsr " , MERGE ( GROUP_MISC , IDX_LSR ) ) ,
PREDEFNODE ( " ror " , MERGE ( GROUP_MISC , IDX_ROR ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " sty " , MERGE ( GROUP_MISC , IDX_STY ) ) ,
PREDEFNODE ( " stx " , MERGE ( GROUP_MISC , IDX_STX ) ) ,
2016-12-28 20:32:00 +00:00
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 ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " dec " , MERGE ( GROUP_MISC , IDX_DEC ) ) ,
PREDEFNODE ( " inc " , MERGE ( GROUP_MISC , IDX_INC ) ) ,
2016-12-28 20:32:00 +00:00
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 ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " jmp " , MERGE ( GROUP_ALLJUMPS , IDX_JMP ) ) ,
PREDEFNODE ( " jsr " , MERGE ( GROUP_ALLJUMPS , IDX_JSR ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " brk " , MERGE ( GROUP_IMPLIEDONLY , 0x00 ) ) ,
PREDEFNODE ( " php " , MERGE ( GROUP_IMPLIEDONLY , 0x08 ) ) ,
PREDEFNODE ( " clc " , MERGE ( GROUP_IMPLIEDONLY , 0x18 ) ) ,
PREDEFNODE ( " plp " , MERGE ( GROUP_IMPLIEDONLY , 0x28 ) ) ,
PREDEFNODE ( " sec " , MERGE ( GROUP_IMPLIEDONLY , 0x38 ) ) ,
PREDEFNODE ( " rti " , MERGE ( GROUP_IMPLIEDONLY , 0x40 ) ) ,
PREDEFNODE ( " pha " , MERGE ( GROUP_IMPLIEDONLY , 0x48 ) ) ,
PREDEFNODE ( " cli " , MERGE ( GROUP_IMPLIEDONLY , 0x58 ) ) ,
PREDEFNODE ( " rts " , MERGE ( GROUP_IMPLIEDONLY , 0x60 ) ) ,
PREDEFNODE ( " pla " , MERGE ( GROUP_IMPLIEDONLY , 0x68 ) ) ,
PREDEFNODE ( " sei " , MERGE ( GROUP_IMPLIEDONLY , 0x78 ) ) ,
PREDEFNODE ( " dey " , MERGE ( GROUP_IMPLIEDONLY , 0x88 ) ) ,
PREDEFNODE ( " txa " , MERGE ( GROUP_IMPLIEDONLY , 0x8a ) ) ,
PREDEFNODE ( " tya " , MERGE ( GROUP_IMPLIEDONLY , 0x98 ) ) ,
PREDEFNODE ( " txs " , MERGE ( GROUP_IMPLIEDONLY , 0x9a ) ) ,
PREDEFNODE ( " tay " , MERGE ( GROUP_IMPLIEDONLY , 0xa8 ) ) ,
PREDEFNODE ( " tax " , MERGE ( GROUP_IMPLIEDONLY , 0xaa ) ) ,
PREDEFNODE ( " clv " , MERGE ( GROUP_IMPLIEDONLY , 0xb8 ) ) ,
PREDEFNODE ( " tsx " , MERGE ( GROUP_IMPLIEDONLY , 0xba ) ) ,
PREDEFNODE ( " iny " , MERGE ( GROUP_IMPLIEDONLY , 0xc8 ) ) ,
PREDEFNODE ( " dex " , MERGE ( GROUP_IMPLIEDONLY , 0xca ) ) ,
PREDEFNODE ( " cld " , MERGE ( GROUP_IMPLIEDONLY , 0xd8 ) ) ,
PREDEFNODE ( " inx " , MERGE ( GROUP_IMPLIEDONLY , 0xe8 ) ) ,
PREDEFNODE ( " nop " , MERGE ( GROUP_IMPLIEDONLY , 0xea ) ) ,
2020-08-15 14:55:22 +00:00
PREDEF_END ( " sed " , MERGE ( GROUP_IMPLIEDONLY , 0xf8 ) ) ,
2012-02-27 21:14:46 +00:00
// ^^^^ this marks the last element
} ;
2016-12-28 20:32:00 +00:00
// undocumented opcodes of the NMOS 6502 that are also supported by c64dtv2:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_6502undoc1_tree [ ] = {
PREDEF_START ,
2020-06-02 15:09:36 +00:00
PREDEFNODE ( " slo " , MERGE ( GROUP_ACCU , IDXuSLO ) ) , // ASL + ORA (aka ASO)
2020-07-28 23:08:07 +00:00
PREDEFNODE ( " rla " , MERGE ( GROUP_ACCU , IDXuRLA ) ) , // ROL + AND (aka RLN)
2020-06-02 15:09:36 +00:00
PREDEFNODE ( " sre " , MERGE ( GROUP_ACCU , IDXuSRE ) ) , // LSR + EOR (aka LSE)
2020-07-28 23:08:07 +00:00
PREDEFNODE ( " rra " , MERGE ( GROUP_ACCU , IDXuRRA ) ) , // ROR + ADC (aka RRD)
PREDEFNODE ( " sax " , MERGE ( GROUP_ACCU , IDXuSAX ) ) , // store A & X (aka AXS/AAX)
2020-06-02 15:09:36 +00:00
PREDEFNODE ( " lax " , MERGE ( GROUP_ACCU , IDXuLAX ) ) , // LDX + LDA
PREDEFNODE ( " dcp " , MERGE ( GROUP_ACCU , IDXuDCP ) ) , // DEC + CMP (aka DCM)
2020-07-28 23:08:07 +00:00
PREDEFNODE ( " isc " , MERGE ( GROUP_ACCU , IDXuISC ) ) , // INC + SBC (aka ISB/INS)
PREDEFNODE ( " las " , MERGE ( GROUP_MISC , IDXuLAS ) ) , // A,X,S = {addr} & S (aka LAR/LAE)
PREDEFNODE ( " tas " , MERGE ( GROUP_MISC , IDXuTAS ) ) , // S = A & X {addr} = A&X& {H+1} (aka SHS/XAS)
PREDEFNODE ( " sha " , MERGE ( GROUP_ACCU , IDXuSHA ) ) , // {addr} = A & X & {H+1} (aka AXA/AHX)
PREDEFNODE ( " shx " , MERGE ( GROUP_MISC , IDXuSHX ) ) , // {addr} = X & {H+1} (aka XAS/SXA)
PREDEFNODE ( " shy " , MERGE ( GROUP_MISC , IDXuSHY ) ) , // {addr} = Y & {H+1} (aka SAY/SYA)
PREDEFNODE ( " alr " , MERGE ( GROUP_MISC , IDXuALR ) ) , // A = A & arg, then LSR (aka ASR)
PREDEFNODE ( " asr " , MERGE ( GROUP_MISC , IDXuALR ) ) , // A = A & arg, then LSR (aka ALR)
PREDEFNODE ( " arr " , MERGE ( GROUP_MISC , IDXuARR ) ) , // A = A & arg, then ROR
PREDEFNODE ( " sbx " , MERGE ( GROUP_MISC , IDXuSBX ) ) , // X = (A & X) - arg (aka AXS/SAX)
2020-06-02 15:09:36 +00:00
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)
2020-07-28 23:08:07 +00:00
PREDEFNODE ( " ane " , MERGE ( GROUP_MISC , IDXuANE ) ) , // A = (A | ??) & X & arg (aka XAA/AXM)
PREDEFNODE ( " lxa " , MERGE ( GROUP_MISC , IDXuLXA ) ) , // A,X = (A | ??) & arg (aka LAX/ATX/OAL)
2020-08-15 14:55:22 +00:00
PREDEF_END ( " jam " , MERGE ( GROUP_IMPLIEDONLY , 0x02 ) ) , // jam/crash/kill/halt-and-catch-fire
2012-02-27 21:14:46 +00:00
// ^^^^ this marks the last element
} ;
2016-12-28 20:32:00 +00:00
// undocumented opcodes of the NMOS 6502 that are _not_ supported by c64dtv2:
2020-08-15 14:55:22 +00:00
// (currently ANC only, maybe more will get moved)
static struct ronode mnemo_6502undoc2_tree [ ] = {
PREDEF_START ,
PREDEF_END ( " anc " , MERGE ( GROUP_MISC , IDXuANC ) ) , // A = A & arg, then C=N (aka ANA, ANB)
2015-06-14 23:16:23 +00:00
// ^^^^ this marks the last element
} ;
2016-12-28 20:32:00 +00:00
// additional opcodes of c64dtv2:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_c64dtv2_tree [ ] = {
PREDEF_START ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " bra " , MERGE ( GROUP_RELATIVE8 , 0x12 ) ) , // branch always
2014-11-23 23:40:01 +00:00
PREDEFNODE ( " sac " , MERGE ( GROUP_MISC , IDX_SAC ) ) , // set accumulator mapping
2020-08-15 14:55:22 +00:00
PREDEF_END ( " sir " , MERGE ( GROUP_MISC , IDX_SIR ) ) , // set index register mapping
2014-11-23 23:40:01 +00:00
// ^^^^ this marks the last element
} ;
2016-12-28 20:32:00 +00:00
// new stuff in CMOS re-design:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_65c02_tree [ ] = {
PREDEF_START ,
2016-12-28 20:32:00 +00:00
// more addressing modes for some mnemonics:
PREDEFNODE ( " ora " , MERGE ( GROUP_ACCU , IDXcORA ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " and " , MERGE ( GROUP_ACCU , IDXcAND ) ) ,
PREDEFNODE ( " eor " , MERGE ( GROUP_ACCU , IDXcEOR ) ) ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " adc " , MERGE ( GROUP_ACCU , IDXcADC ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " sta " , MERGE ( GROUP_ACCU , IDXcSTA ) ) ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " lda " , MERGE ( GROUP_ACCU , IDXcLDA ) ) ,
PREDEFNODE ( " cmp " , MERGE ( GROUP_ACCU , IDXcCMP ) ) ,
PREDEFNODE ( " sbc " , MERGE ( GROUP_ACCU , IDXcSBC ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " jmp " , MERGE ( GROUP_ALLJUMPS , IDXcJMP ) ) ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " bit " , MERGE ( GROUP_MISC , IDXcBIT ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " dec " , MERGE ( GROUP_MISC , IDXcDEC ) ) ,
PREDEFNODE ( " inc " , MERGE ( GROUP_MISC , IDXcINC ) ) ,
2016-12-28 20:32:00 +00:00
// and eight new mnemonics:
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " bra " , MERGE ( GROUP_RELATIVE8 , 0x80 ) ) ,
PREDEFNODE ( " phy " , MERGE ( GROUP_IMPLIEDONLY , 0x5a ) ) ,
PREDEFNODE ( " ply " , MERGE ( GROUP_IMPLIEDONLY , 0x7a ) ) ,
PREDEFNODE ( " phx " , MERGE ( GROUP_IMPLIEDONLY , 0xda ) ) ,
PREDEFNODE ( " plx " , MERGE ( GROUP_IMPLIEDONLY , 0xfa ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " tsb " , MERGE ( GROUP_MISC , IDXcTSB ) ) ,
PREDEFNODE ( " trb " , MERGE ( GROUP_MISC , IDXcTRB ) ) ,
2020-08-15 14:55:22 +00:00
PREDEF_END ( " stz " , MERGE ( GROUP_MISC , IDXcSTZ ) ) ,
2012-02-27 21:14:46 +00:00
// ^^^^ this marks the last element
} ;
2016-12-28 20:32:00 +00:00
// bit-manipulation extensions (by Rockwell?)
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_bitmanips_tree [ ] = {
PREDEF_START ,
2017-01-08 22:16:43 +00:00
PREDEFNODE ( " rmb0 " , MERGE ( GROUP_ZPONLY , 0x07 ) ) ,
PREDEFNODE ( " rmb1 " , MERGE ( GROUP_ZPONLY , 0x17 ) ) ,
PREDEFNODE ( " rmb2 " , MERGE ( GROUP_ZPONLY , 0x27 ) ) ,
PREDEFNODE ( " rmb3 " , MERGE ( GROUP_ZPONLY , 0x37 ) ) ,
PREDEFNODE ( " rmb4 " , MERGE ( GROUP_ZPONLY , 0x47 ) ) ,
PREDEFNODE ( " rmb5 " , MERGE ( GROUP_ZPONLY , 0x57 ) ) ,
PREDEFNODE ( " rmb6 " , MERGE ( GROUP_ZPONLY , 0x67 ) ) ,
PREDEFNODE ( " rmb7 " , MERGE ( GROUP_ZPONLY , 0x77 ) ) ,
PREDEFNODE ( " smb0 " , MERGE ( GROUP_ZPONLY , 0x87 ) ) ,
PREDEFNODE ( " smb1 " , MERGE ( GROUP_ZPONLY , 0x97 ) ) ,
PREDEFNODE ( " smb2 " , MERGE ( GROUP_ZPONLY , 0xa7 ) ) ,
PREDEFNODE ( " smb3 " , MERGE ( GROUP_ZPONLY , 0xb7 ) ) ,
PREDEFNODE ( " smb4 " , MERGE ( GROUP_ZPONLY , 0xc7 ) ) ,
PREDEFNODE ( " smb5 " , MERGE ( GROUP_ZPONLY , 0xd7 ) ) ,
PREDEFNODE ( " smb6 " , MERGE ( GROUP_ZPONLY , 0xe7 ) ) ,
PREDEFNODE ( " smb7 " , MERGE ( GROUP_ZPONLY , 0xf7 ) ) ,
2016-12-28 20:32:00 +00:00
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 ) ) ,
2020-08-15 14:55:22 +00:00
PREDEF_END ( " bbs7 " , MERGE ( GROUP_BITBRANCH , 0xff ) ) ,
2016-12-28 20:32:00 +00:00
// ^^^^ this marks the last element
} ;
// "stp" and "wai" extensions by WDC:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_stp_wai_tree [ ] = {
PREDEF_START ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " wai " , MERGE ( GROUP_IMPLIEDONLY , 0xcb ) ) ,
2020-08-15 14:55:22 +00:00
PREDEF_END ( " stp " , MERGE ( GROUP_IMPLIEDONLY , 0xdb ) ) ,
2012-02-27 21:14:46 +00:00
// ^^^^ this marks the last element
} ;
2020-07-18 13:50:46 +00:00
// the 65816 stuff
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_65816_tree [ ] = {
PREDEF_START ,
2016-12-28 20:32:00 +00:00
// 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:
2020-05-21 19:36:59 +00:00
PREDEFNODE ( " ora " , MERGE ( GROUP_ACCU , IDX16ORA | IM_ACCUMULATOR ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " and " , MERGE ( GROUP_ACCU , IDX16AND | IM_ACCUMULATOR ) ) ,
PREDEFNODE ( " eor " , MERGE ( GROUP_ACCU , IDX16EOR | IM_ACCUMULATOR ) ) ,
2020-05-21 19:36:59 +00:00
PREDEFNODE ( " adc " , MERGE ( GROUP_ACCU , IDX16ADC | IM_ACCUMULATOR ) ) ,
PREDEFNODE ( " sta " , MERGE ( GROUP_ACCU , IDX16STA ) ) ,
PREDEFNODE ( " lda " , MERGE ( GROUP_ACCU , IDX16LDA | IM_ACCUMULATOR ) ) ,
PREDEFNODE ( " cmp " , MERGE ( GROUP_ACCU , IDX16CMP | IM_ACCUMULATOR ) ) ,
PREDEFNODE ( " sbc " , MERGE ( GROUP_ACCU , IDX16SBC | IM_ACCUMULATOR ) ) ,
PREDEFNODE ( " jmp " , MERGE ( GROUP_ALLJUMPS , IDX16JMP ) ) ,
PREDEFNODE ( " jsr " , MERGE ( GROUP_ALLJUMPS , IDX16JSR ) ) ,
2016-12-28 20:32:00 +00:00
//
2020-05-21 19:36:59 +00:00
PREDEFNODE ( " pei " , MERGE ( GROUP_ACCU , IDX16PEI ) ) ,
PREDEFNODE ( " jml " , MERGE ( GROUP_ALLJUMPS , IDX16JML ) ) ,
PREDEFNODE ( " jsl " , MERGE ( GROUP_ALLJUMPS , IDX16JSL ) ) ,
2012-02-27 21:14:46 +00:00
PREDEFNODE ( " mvp " , MERGE ( GROUP_BOTHMOVES , 0x44 ) ) ,
PREDEFNODE ( " mvn " , MERGE ( GROUP_BOTHMOVES , 0x54 ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " per " , MERGE ( GROUP_REL16_3 , 0x62 ) ) ,
PREDEFNODE ( " brl " , MERGE ( GROUP_REL16_3 , 0x82 ) ) ,
2020-05-21 19:36:59 +00:00
PREDEFNODE ( " cop " , MERGE ( GROUP_MISC , IDX16COP ) ) ,
PREDEFNODE ( " rep " , MERGE ( GROUP_MISC , IDX16REP ) ) ,
PREDEFNODE ( " sep " , MERGE ( GROUP_MISC , IDX16SEP ) ) ,
PREDEFNODE ( " pea " , MERGE ( GROUP_MISC , IDX16PEA ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " phd " , MERGE ( GROUP_IMPLIEDONLY , 0x0b ) ) ,
PREDEFNODE ( " tcs " , MERGE ( GROUP_IMPLIEDONLY , 0x1b ) ) ,
PREDEFNODE ( " pld " , MERGE ( GROUP_IMPLIEDONLY , 0x2b ) ) ,
PREDEFNODE ( " tsc " , MERGE ( GROUP_IMPLIEDONLY , 0x3b ) ) ,
PREDEFNODE ( " phk " , MERGE ( GROUP_IMPLIEDONLY , 0x4b ) ) ,
PREDEFNODE ( " tcd " , MERGE ( GROUP_IMPLIEDONLY , 0x5b ) ) ,
PREDEFNODE ( " rtl " , MERGE ( GROUP_IMPLIEDONLY , 0x6b ) ) ,
PREDEFNODE ( " tdc " , MERGE ( GROUP_IMPLIEDONLY , 0x7b ) ) ,
PREDEFNODE ( " phb " , MERGE ( GROUP_IMPLIEDONLY , 0x8b ) ) ,
PREDEFNODE ( " txy " , MERGE ( GROUP_IMPLIEDONLY , 0x9b ) ) ,
PREDEFNODE ( " plb " , MERGE ( GROUP_IMPLIEDONLY , 0xab ) ) ,
PREDEFNODE ( " tyx " , MERGE ( GROUP_IMPLIEDONLY , 0xbb ) ) ,
// 0xcb is WAI
// 0xdb is STP
PREDEFNODE ( " xba " , MERGE ( GROUP_IMPLIEDONLY , 0xeb ) ) ,
PREDEFNODE ( " xce " , MERGE ( GROUP_IMPLIEDONLY , 0xfb ) ) ,
2020-08-15 14:55:22 +00:00
PREDEF_END ( " wdm " , MERGE ( GROUP_IMPLIEDONLY , 0x42 ) ) ,
2012-02-27 21:14:46 +00:00
// ^^^^ this marks the last element
} ;
2016-12-28 20:32:00 +00:00
// 65ce02 has 46 new opcodes and a few changes:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_65ce02_tree [ ] = {
PREDEF_START ,
2016-12-28 20:32:00 +00:00
// 65ce02 changes (zp) addressing of 65c02 to (zp),z addressing:
PREDEFNODE ( " ora " , MERGE ( GROUP_ACCU , IDXeORA ) ) ,
2020-07-12 18:46:06 +00:00
PREDEFNODE ( " and " , MERGE ( GROUP_ACCU , IDXeAND ) ) ,
PREDEFNODE ( " eor " , MERGE ( GROUP_ACCU , IDXeEOR ) ) ,
2016-12-28 20:32:00 +00:00
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 ) ) ,
2020-07-18 13:50:46 +00:00
PREDEFNODE ( " dew " , MERGE ( GROUP_ZPONLY , 0xc3 ) ) ,
PREDEFNODE ( " inw " , MERGE ( GROUP_ZPONLY , 0xe3 ) ) ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " ldz " , MERGE ( GROUP_MISC , IDXeLDZ ) ) ,
2020-04-14 00:28:31 +00:00
PREDEFNODE ( " phw " , MERGE ( GROUP_MISC , IDXePHW | IM_FORCE16 ) ) , // when using immediate addressing, arg is 16 bit
2016-12-28 20:32:00 +00:00
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 ) ) ,
2020-08-15 14:55:22 +00:00
PREDEF_END ( " plz " , MERGE ( GROUP_IMPLIEDONLY , 0xfb ) ) ,
2016-12-28 20:32:00 +00:00
// ^^^^ this marks the last element
} ;
// 65ce02's "aug" opcode:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_aug_tree [ ] = {
PREDEF_START ,
PREDEF_END ( " aug " , MERGE ( GROUP_IMPLIEDONLY , 0x5c ) ) , // actually a "4-byte NOP reserved for future expansion"
2016-12-28 20:32:00 +00:00
// ^^^^ this marks the last element
} ;
// 4502's "map" and "eom" opcodes:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_map_eom_tree [ ] = {
PREDEF_START ,
2016-12-28 20:32:00 +00:00
PREDEFNODE ( " map " , MERGE ( GROUP_IMPLIEDONLY , 0x5c ) ) , // change memory mapping
2020-08-15 14:55:22 +00:00
PREDEF_END ( " eom " , MERGE ( GROUP_IMPLIEDONLY , 0xea ) ) , // actually the NOP opcode
2016-12-28 20:32:00 +00:00
// ^^^^ this marks the last element
} ;
2012-02-27 21:14:46 +00:00
2020-05-21 19:36:59 +00:00
// m65 has a few extensions using prefix codes:
2020-08-15 14:55:22 +00:00
static struct ronode mnemo_m65_tree [ ] = {
PREDEF_START ,
2020-05-21 23:46:11 +00:00
// extension 1:
// a NOP prefix changes ($ff),z addressing from using 16-bit pointers to
// using 32-bit pointers. I chose "[$ff],z" to indicate this.
// this applies to LDA/STA/CMP/ADC/SBC/AND/EOR/ORA
// extension 2:
// a NEG:NEG prefix causes the next instruction to use the four A/X/Y/Z
// registers as a single 32-bit register (A is the lsb, Z is the msb).
// it works with these mnemonics:
// LDA/STA/CMP/ADC/SBC/AND/EOR/ORA
// ...now LDQ/STQ/CPQ/ADCQ/SBCQ/ANDQ/EORQ/ORQ
// ASL/LSR/ROL/ROR
// ...now ASLQ/LSRQ/ROLQ/RORQ
// INC/DEC
// ...now INQ/DEQ
2020-07-27 23:37:36 +00:00
// BIT
// ...now BITQ
// ASR
// ...now ASRQ
2020-07-29 23:30:33 +00:00
// it works with most addressing modes (beware of index register usage!)
2020-05-21 23:46:11 +00:00
// except for immediate addressing and "($ff),z", which becomes "($ff)"
// extension 3:
// extensions 1 and 2 can be combined (NEG:NEG:NOP prefix), then
// "[$ff],z" becomes "[$ff]"
PREDEFNODE ( " lda " , MERGE ( GROUP_ACCU , IDXmLDA | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " sta " , MERGE ( GROUP_ACCU , IDXmSTA | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " cmp " , MERGE ( GROUP_ACCU , IDXmCMP | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " adc " , MERGE ( GROUP_ACCU , IDXmADC | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " sbc " , MERGE ( GROUP_ACCU , IDXmSBC | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " and " , MERGE ( GROUP_ACCU , IDXmAND | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " eor " , MERGE ( GROUP_ACCU , IDXmEOR | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " ora " , MERGE ( GROUP_ACCU , IDXmORA | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " ldq " , MERGE ( GROUP_ACCU , IDXmLDQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " stq " , MERGE ( GROUP_ACCU , IDXmSTQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " cpq " , MERGE ( GROUP_ACCU , IDXmCPQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " adcq " , MERGE ( GROUP_ACCU , IDXmADCQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " sbcq " , MERGE ( GROUP_ACCU , IDXmSBCQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " andq " , MERGE ( GROUP_ACCU , IDXmANDQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " eorq " , MERGE ( GROUP_ACCU , IDXmEORQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
PREDEFNODE ( " orq " , MERGE ( GROUP_ACCU , IDXmORQ | PREFIX_NEGNEG | LI_PREFIX_NOP ) ) ,
// CAUTION - these use 6502/65c02 indices, because the available addressing modes and opcodes are identical:
PREDEFNODE ( " aslq " , MERGE ( GROUP_MISC , IDX_ASL | PREFIX_NEGNEG ) ) ,
PREDEFNODE ( " lsrq " , MERGE ( GROUP_MISC , IDX_LSR | PREFIX_NEGNEG ) ) ,
PREDEFNODE ( " rolq " , MERGE ( GROUP_MISC , IDX_ROL | PREFIX_NEGNEG ) ) ,
PREDEFNODE ( " rorq " , MERGE ( GROUP_MISC , IDX_ROR | PREFIX_NEGNEG ) ) ,
PREDEFNODE ( " inq " , MERGE ( GROUP_MISC , IDXcINC | PREFIX_NEGNEG ) ) ,
2020-06-03 11:02:16 +00:00
PREDEFNODE ( " deq " , MERGE ( GROUP_MISC , IDXcDEC | PREFIX_NEGNEG ) ) ,
2020-07-27 23:37:36 +00:00
PREDEFNODE ( " bitq " , MERGE ( GROUP_MISC , IDXmBITQ | PREFIX_NEGNEG ) ) ,
PREDEFNODE ( " asrq " , MERGE ( GROUP_MISC , IDXeASR | PREFIX_NEGNEG ) ) ,
2020-06-03 11:02:16 +00:00
// because the NOP opcode is used as a prefix code, the mnemonic was disabled:
2020-08-15 14:55:22 +00:00
PREDEF_END ( " nop " , MERGE ( GROUP_PREFIX , 0xea ) ) ,
2020-05-21 19:36:59 +00:00
// ^^^^ this marks the last element
} ;
2012-02-27 21:14:46 +00:00
// Functions
// Address mode parsing
2016-12-28 20:32:00 +00:00
// utility function for parsing indices. result must be processed via AMB_PREINDEX() or AMB_INDEX() macro!
2020-08-12 12:31:06 +00:00
// TODO: add pointer arg for result, use return value to indicate parse error!
static int get_index ( void )
2012-02-27 21:14:46 +00:00
{
if ( ! Input_accept_comma ( ) )
2016-12-28 20:32:00 +00:00
return INDEX_NONE ;
2012-02-27 21:14:46 +00:00
2016-12-28 20:32:00 +00:00
// there was a comma, so check next character (spaces will have been skipped):
2012-02-27 21:14:46 +00:00
switch ( GotByte ) {
case ' s ' :
case ' S ' :
2016-12-28 20:32:00 +00:00
// 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 ;
2012-02-27 21:14:46 +00:00
case ' x ' :
case ' X ' :
2016-12-28 20:32:00 +00:00
NEXTANDSKIPSPACE ( ) ;
return INDEX_X ;
2012-02-27 21:14:46 +00:00
case ' y ' :
case ' Y ' :
NEXTANDSKIPSPACE ( ) ;
2016-12-28 20:32:00 +00:00
return INDEX_Y ;
case ' z ' :
case ' Z ' :
NEXTANDSKIPSPACE ( ) ;
return INDEX_Z ;
}
Throw_error ( exception_syntax ) ;
return INDEX_NONE ;
2012-02-27 21:14:46 +00:00
}
2020-05-08 00:34:46 +00:00
// wrapper function to read integer argument
static void get_int_arg ( struct number * result , boolean complain_about_indirect )
{
struct expression expression ;
ALU_addrmode_int ( & expression , 0 ) ; // accept 0 parentheses still open (-> complain!)
if ( expression . is_parenthesized & & complain_about_indirect ) {
2020-05-28 18:43:49 +00:00
// TODO - raise error and be done with it?
Throw_first_pass_warning ( " There are unneeded parentheses, you know indirect addressing is impossible here, right? " ) ; // FIXME - rephrase? add to docs!
2020-05-08 00:34:46 +00:00
}
2020-05-13 23:26:40 +00:00
* result = expression . result . u . number ;
2020-05-08 00:34:46 +00:00
}
// wrapper function to detect addressing mode, and, if not IMPLIED, read arg.
// argument is stored in given result structure, addressing mode is returned.
2020-08-12 12:31:06 +00:00
// TODO: add pointer arg for result, use return value to indicate parse error!
2020-06-14 00:26:38 +00:00
static bits get_addr_mode ( struct number * result )
2012-02-27 21:14:46 +00:00
{
2020-04-26 18:53:14 +00:00
struct expression expression ;
2020-06-14 00:26:38 +00:00
bits address_mode_bits = 0 ;
2012-02-27 21:14:46 +00:00
SKIPSPACE ( ) ;
switch ( GotByte ) {
2020-04-26 16:24:34 +00:00
case CHAR_EOS :
address_mode_bits = AMB_IMPLIED ;
break ;
case ' # ' :
GetByte ( ) ; // proceed with next char
address_mode_bits = AMB_IMMEDIATE ;
2020-05-08 00:34:46 +00:00
get_int_arg ( result , FALSE ) ;
typesystem_want_nonaddr ( result ) ; // FIXME - this is wrong for 65ce02's PHW#
2020-04-26 16:24:34 +00:00
break ;
2012-02-27 21:14:46 +00:00
case ' [ ' :
GetByte ( ) ; // proceed with next char
2020-05-11 12:42:47 +00:00
get_int_arg ( result , FALSE ) ;
2014-06-02 00:47:46 +00:00
typesystem_want_addr ( result ) ;
2020-08-12 12:31:06 +00:00
if ( GotByte = = ' ] ' ) {
GetByte ( ) ;
address_mode_bits = AMB_LONGINDIRECT | AMB_INDEX ( get_index ( ) ) ;
} else {
2012-02-27 21:14:46 +00:00
Throw_error ( exception_syntax ) ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
break ;
default :
2020-08-12 12:31:06 +00:00
ALU_addrmode_int ( & expression , 1 ) ; // direct call instead of wrapper, to allow for "(EXPR,x)" where parsing stops at comma
2020-05-13 23:26:40 +00:00
* result = expression . result . u . number ;
2014-06-02 00:47:46 +00:00
typesystem_want_addr ( result ) ;
2012-02-27 21:14:46 +00:00
// check for indirect addressing
2020-04-26 20:14:39 +00:00
if ( expression . is_parenthesized )
2016-12-28 20:32:00 +00:00
address_mode_bits | = AMB_INDIRECT ;
2012-02-27 21:14:46 +00:00
// check for internal index (before closing parenthesis)
2020-04-26 18:53:14 +00:00
if ( expression . open_parentheses ) {
2012-02-27 21:14:46 +00:00
// in case there are still open parentheses,
// read internal index
2020-08-12 12:31:06 +00:00
address_mode_bits | = AMB_PREINDEX ( get_index ( ) ) ;
if ( GotByte = = ' ) ' ) {
2012-02-27 21:14:46 +00:00
GetByte ( ) ; // go on with next char
2020-08-12 12:31:06 +00:00
} else {
2012-02-27 21:14:46 +00:00
Throw_error ( exception_syntax ) ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
}
// check for external index (after closing parenthesis)
2020-08-12 12:31:06 +00:00
address_mode_bits | = AMB_INDEX ( get_index ( ) ) ;
2012-02-27 21:14:46 +00:00
}
// ensure end of line
Input_ensure_EOS ( ) ;
2020-04-26 16:24:34 +00:00
//printf("AM: %x\n", address_mode_bits);
2016-12-28 20:32:00 +00:00
return address_mode_bits ;
2012-02-27 21:14:46 +00:00
}
// Helper function for calc_arg_size()
2020-04-28 16:02:09 +00:00
// Only call with "size_bit = NUMBER_FORCES_16" or "size_bit = NUMBER_FORCES_24"
2020-06-14 00:26:38 +00:00
static bits check_oversize ( bits size_bit , struct number * argument )
2012-02-27 21:14:46 +00:00
{
// only check if value is *defined*
2020-06-16 22:44:54 +00:00
if ( argument - > ntype = = NUMTYPE_UNDEFINED )
2012-02-27 21:14:46 +00:00
return size_bit ; // pass on result
// value is defined, so check
2020-04-28 16:02:09 +00:00
if ( size_bit = = NUMBER_FORCES_16 ) {
2012-02-27 21:14:46 +00:00
// check 16-bit argument for high byte zero
2014-06-02 00:47:46 +00:00
if ( ( argument - > val . intval < = 255 ) & & ( argument - > val . intval > = - 128 ) )
2017-10-21 19:59:56 +00:00
Throw_warning ( exception_oversized_addrmode ) ;
2012-02-27 21:14:46 +00:00
} else {
// check 24-bit argument for bank byte zero
2014-06-02 00:47:46 +00:00
if ( ( argument - > val . intval < = 65535 ) & & ( argument - > val . intval > = - 32768 ) )
2017-10-21 19:59:56 +00:00
Throw_warning ( exception_oversized_addrmode ) ;
2012-02-27 21:14:46 +00:00
}
return size_bit ; // pass on result
}
// Utility function for comparing force bits, argument value, argument size,
// "unsure"-flag and possible addressing modes. Returns force bit matching
// number of parameter bytes to send. If it returns zero, an error occurred
// (and has already been delivered).
// force_bit none, 8b, 16b, 24b
// argument value and flags of parameter
// addressing_modes adressing modes (8b, 16b, 24b or any combination)
// Return value = force bit for number of parameter bytes to send (0 = error)
2020-08-12 12:31:06 +00:00
// TODO: add pointer arg for result, use return value to indicate error ONLY!
2020-06-14 00:26:38 +00:00
static bits calc_arg_size ( bits force_bit , struct number * argument , bits addressing_modes )
2012-02-27 21:14:46 +00:00
{
// if there are no possible addressing modes, complain
if ( addressing_modes = = MAYBE______ ) {
Throw_error ( exception_illegal_combination ) ;
return 0 ;
}
2020-07-18 13:50:46 +00:00
// if a force bit postfix was given, act upon it
2012-02-27 21:14:46 +00:00
if ( force_bit ) {
2020-07-18 13:50:46 +00:00
// if mnemonic supports this force bit, return it
2012-02-27 21:14:46 +00:00
if ( addressing_modes & force_bit )
return force_bit ;
// if not, complain
2020-07-18 13:50:46 +00:00
Throw_error ( " CPU does not support this postfix for this mnemonic. " ) ;
2012-02-27 21:14:46 +00:00
return 0 ;
}
2020-07-18 13:50:46 +00:00
// mnemonic did not have a force bit postfix.
2012-02-27 21:14:46 +00:00
// if value has force bit, act upon it
2020-04-28 16:02:09 +00:00
if ( argument - > flags & NUMBER_FORCEBITS ) {
2012-02-27 21:14:46 +00:00
// Value has force bit set, so return this or bigger size
2020-04-28 16:02:09 +00:00
if ( NUMBER_FORCES_8 & addressing_modes & argument - > flags )
return NUMBER_FORCES_8 ;
2012-02-27 21:14:46 +00:00
2020-04-28 16:02:09 +00:00
if ( NUMBER_FORCES_16 & addressing_modes & argument - > flags )
return NUMBER_FORCES_16 ;
2012-02-27 21:14:46 +00:00
2020-04-28 16:02:09 +00:00
if ( NUMBER_FORCES_24 & addressing_modes )
return NUMBER_FORCES_24 ;
2012-02-27 21:14:46 +00:00
Throw_error ( exception_number_out_of_range ) ; // else error
return 0 ;
}
// Value has no force bit. Check whether there's only one addr mode
// if only one addressing mode, use that
2020-04-28 16:02:09 +00:00
if ( ( addressing_modes = = NUMBER_FORCES_8 )
| | ( addressing_modes = = NUMBER_FORCES_16 )
2020-08-12 12:31:06 +00:00
| | ( addressing_modes = = NUMBER_FORCES_24 ) ) {
2012-02-27 21:14:46 +00:00
return addressing_modes ; // There's only one, so use it
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// There's more than one addressing mode. Check whether value is sure
// if value is unsure, use default size
2020-04-28 16:02:09 +00:00
if ( argument - > flags & NUMBER_EVER_UNDEFINED ) {
2012-02-27 21:14:46 +00:00
// if there is an 8-bit addressing mode *and* the value
// is sure to fit into 8 bits, use the 8-bit mode
2020-08-12 12:31:06 +00:00
if ( ( addressing_modes & NUMBER_FORCES_8 ) & & ( argument - > flags & NUMBER_FITS_BYTE ) ) {
2020-04-28 16:02:09 +00:00
return NUMBER_FORCES_8 ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// if there is a 16-bit addressing, use that
// call helper function for "oversized addr mode" warning
2020-08-12 12:31:06 +00:00
if ( NUMBER_FORCES_16 & addressing_modes ) {
2020-04-28 16:02:09 +00:00
return check_oversize ( NUMBER_FORCES_16 , argument ) ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// if there is a 24-bit addressing, use that
// call helper function for "oversized addr mode" warning
2020-08-12 12:31:06 +00:00
if ( NUMBER_FORCES_24 & addressing_modes ) {
2020-04-28 16:02:09 +00:00
return check_oversize ( NUMBER_FORCES_24 , argument ) ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// otherwise, use 8-bit-addressing, which will raise an
// error later on if the value won't fit
2020-04-28 16:02:09 +00:00
return NUMBER_FORCES_8 ;
2012-02-27 21:14:46 +00:00
}
// Value is sure, so use its own size
// if value is negative, size cannot be chosen. Complain!
2014-06-02 00:47:46 +00:00
if ( argument - > val . intval < 0 ) {
2012-02-27 21:14:46 +00:00
Throw_error ( " Negative value - cannot choose addressing mode. " ) ;
return 0 ;
}
// Value is positive or zero. Check size ranges
// if there is an 8-bit addressing mode and value fits, use 8 bits
2020-08-12 12:31:06 +00:00
if ( ( addressing_modes & NUMBER_FORCES_8 ) & & ( argument - > val . intval < 256 ) ) {
2020-04-28 16:02:09 +00:00
return NUMBER_FORCES_8 ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// if there is a 16-bit addressing mode and value fits, use 16 bits
2020-08-12 12:31:06 +00:00
if ( ( addressing_modes & NUMBER_FORCES_16 ) & & ( argument - > val . intval < 65536 ) ) {
2020-04-28 16:02:09 +00:00
return NUMBER_FORCES_16 ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// if there is a 24-bit addressing mode, use that. In case the
// value doesn't fit, the output function will do the complaining.
2020-08-12 12:31:06 +00:00
if ( addressing_modes & NUMBER_FORCES_24 ) {
2020-04-28 16:02:09 +00:00
return NUMBER_FORCES_24 ;
2020-08-12 12:31:06 +00:00
}
2012-02-27 21:14:46 +00:00
// Value is too big for all possible addressing modes
Throw_error ( exception_number_out_of_range ) ;
return 0 ;
}
// Mnemonics using only implied addressing.
static void group_only_implied_addressing ( int opcode )
{
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
// TODO - accept argument and complain about it? error message should tell more than "garbage data at end of line"!
2016-12-28 20:32:00 +00:00
// for 65ce02 and 4502, warn about buggy decimal mode
2020-07-12 18:46:06 +00:00
if ( ( opcode = = 0xf8 ) & & ( CPU_state . type - > flags & CPUFLAG_DECIMALSUBTRACTBUGGY ) )
2016-12-28 20:32:00 +00:00
Throw_first_pass_warning ( " Found SED instruction for CPU with known decimal SBC bug. " ) ;
2012-02-27 21:14:46 +00:00
Output_byte ( opcode ) ;
Input_ensure_EOS ( ) ;
}
2013-06-26 23:01:00 +00:00
// helper function to output "Target not in bank" message
static void not_in_bank ( intval_t target )
2012-03-16 20:21:09 +00:00
{
char buffer [ 60 ] ; // 640K should be enough for anybody
2014-05-28 21:39:15 +00:00
sprintf ( buffer , " Target not in bank (0x%lx). " , ( long ) target ) ;
2012-03-16 20:21:09 +00:00
Throw_error ( buffer ) ;
}
2016-12-28 20:32:00 +00:00
// helper function for branches with 8-bit offset (including bbr0..7/bbs0..7)
static void near_branch ( int preoffset )
2012-02-27 21:14:46 +00:00
{
2020-05-22 20:55:36 +00:00
struct number pc ;
2020-04-28 16:02:09 +00:00
struct number target ;
2014-06-02 00:47:46 +00:00
intval_t offset = 0 ; // dummy value, to not throw more errors than necessary
2013-06-26 23:01:00 +00:00
2020-05-22 20:55:36 +00:00
vcpu_read_pc ( & pc ) ;
2020-05-08 00:34:46 +00:00
get_int_arg ( & target , TRUE ) ;
2014-06-02 00:47:46 +00:00
typesystem_want_addr ( & target ) ;
2020-06-16 22:44:54 +00:00
if ( ( pc . ntype = = NUMTYPE_INT ) & & ( target . ntype = = NUMTYPE_INT ) ) {
2014-06-02 00:47:46 +00:00
if ( ( target . val . intval | 0xffff ) ! = 0xffff ) {
not_in_bank ( target . val . intval ) ;
2013-06-26 23:01:00 +00:00
} else {
2020-05-22 20:55:36 +00:00
offset = ( target . val . intval - ( pc . val . intval + preoffset ) ) & 0xffff ; // clip to 16 bit offset
2013-06-26 23:01:00 +00:00
// fix sign
if ( offset & 0x8000 )
offset - = 0x10000 ;
// range check
if ( ( offset < - 128 ) | | ( offset > 127 ) ) {
char buffer [ 60 ] ; // 640K should be enough for anybody
2014-05-28 21:39:15 +00:00
sprintf ( buffer , " Target out of range (%ld; %ld too far). " , ( long ) offset , ( long ) ( offset < - 128 ? - 128 - offset : offset - 127 ) ) ;
2013-06-26 23:01:00 +00:00
Throw_error ( buffer ) ;
}
}
2012-02-27 21:14:46 +00:00
}
// this fn has its own range check (see above).
// No reason to irritate the user with another error message,
2014-12-03 22:18:06 +00:00
// so use Output_byte() instead of output_8()
//output_8(offset);
2013-06-26 23:01:00 +00:00
Output_byte ( offset ) ;
2012-02-27 21:14:46 +00:00
Input_ensure_EOS ( ) ;
}
2016-12-28 20:32:00 +00:00
// helper function for relative addressing with 16-bit offset
static void far_branch ( int preoffset )
2012-02-27 21:14:46 +00:00
{
2020-05-22 20:55:36 +00:00
struct number pc ;
2020-04-28 16:02:09 +00:00
struct number target ;
2014-06-02 00:47:46 +00:00
intval_t offset = 0 ; // dummy value, to not throw more errors than necessary
2013-06-26 23:01:00 +00:00
2020-05-22 20:55:36 +00:00
vcpu_read_pc ( & pc ) ;
2020-05-08 00:34:46 +00:00
get_int_arg ( & target , TRUE ) ;
2014-06-02 00:47:46 +00:00
typesystem_want_addr ( & target ) ;
2020-06-16 22:44:54 +00:00
if ( ( pc . ntype = = NUMTYPE_INT ) & & ( target . ntype = = NUMTYPE_INT ) ) {
2014-06-02 00:47:46 +00:00
if ( ( target . val . intval | 0xffff ) ! = 0xffff ) {
not_in_bank ( target . val . intval ) ;
2013-06-26 23:01:00 +00:00
} else {
2020-05-22 20:55:36 +00:00
offset = ( target . val . intval - ( pc . val . intval + preoffset ) ) & 0xffff ;
2013-06-26 23:01:00 +00:00
// no further checks necessary, 16-bit branches can access whole bank
}
2012-02-27 21:14:46 +00:00
}
2014-12-03 22:18:06 +00:00
output_le16 ( offset ) ;
2012-02-27 21:14:46 +00:00
Input_ensure_EOS ( ) ;
}
// set addressing mode bits depending on which opcodes exist, then calculate
// argument size and output both opcode and argument
2020-07-18 13:50:46 +00:00
static void make_instruction ( bits force_bit , struct number * result , unsigned long opcodes )
2012-02-27 21:14:46 +00:00
{
int addressing_modes = MAYBE______ ;
if ( opcodes & 0x0000ff )
addressing_modes | = MAYBE_1____ ;
if ( opcodes & 0x00ff00 )
addressing_modes | = MAYBE___2__ ;
if ( opcodes & 0xff0000 )
addressing_modes | = MAYBE_____3 ;
switch ( calc_arg_size ( force_bit , result , addressing_modes ) ) {
2020-04-28 16:02:09 +00:00
case NUMBER_FORCES_8 :
2012-02-27 21:14:46 +00:00
Output_byte ( opcodes & 255 ) ;
2014-12-03 22:18:06 +00:00
output_8 ( result - > val . intval ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-04-28 16:02:09 +00:00
case NUMBER_FORCES_16 :
2012-02-27 21:14:46 +00:00
Output_byte ( ( opcodes > > 8 ) & 255 ) ;
2014-12-03 22:18:06 +00:00
output_le16 ( result - > val . intval ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-04-28 16:02:09 +00:00
case NUMBER_FORCES_24 :
2012-02-27 21:14:46 +00:00
Output_byte ( ( opcodes > > 16 ) & 255 ) ;
2014-12-03 22:18:06 +00:00
output_le24 ( result - > val . intval ) ;
2012-02-27 21:14:46 +00:00
}
}
// 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.
2020-06-14 00:26:38 +00:00
static unsigned int imm_ops ( bits * force_bit , unsigned char opcode , bits immediate_mode )
2012-02-27 21:14:46 +00:00
{
2020-06-14 00:26:38 +00:00
boolean long_register = FALSE ;
2016-12-28 20:32:00 +00:00
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
2012-02-27 21:14:46 +00:00
2016-12-28 20:32:00 +00:00
// check force bits - if no force bits given, use cpu state and convert to force bit
2012-02-27 21:14:46 +00:00
if ( * force_bit = = 0 )
2020-04-28 16:02:09 +00:00
* force_bit = long_register ? NUMBER_FORCES_16 : NUMBER_FORCES_8 ;
2016-12-28 20:32:00 +00:00
// return identical opcodes for single-byte and two-byte arguments:
2012-02-27 21:14:46 +00:00
return ( ( ( unsigned int ) opcode ) < < 8 ) | opcode ;
}
2017-10-29 23:29:07 +00:00
// helper function to warn if zp pointer wraps around
2020-04-28 16:02:09 +00:00
static void check_zp_wraparound ( struct number * result )
2017-10-29 23:29:07 +00:00
{
2020-06-16 22:44:54 +00:00
if ( ( result - > ntype = = NUMTYPE_INT )
2020-05-31 13:07:40 +00:00
& & ( result - > val . intval = = 0xff )
& & ( CPU_state . type - > flags & CPUFLAG_WARN_ABOUT_FF_PTR ) )
2017-10-29 23:29:07 +00:00
Throw_warning ( " Zeropage pointer wraps around from $ff to $00 " ) ;
}
2012-02-27 21:14:46 +00:00
// The main accumulator stuff (ADC, AND, CMP, EOR, LDA, ORA, SBC, STA)
// plus PEI.
2020-06-14 00:26:38 +00:00
static void group_main ( int index , bits flags )
2012-02-27 21:14:46 +00:00
{
2016-12-28 20:32:00 +00:00
unsigned long immediate_opcodes ;
2020-04-28 16:02:09 +00:00
struct number result ;
2020-06-14 00:26:38 +00:00
bits force_bit = Input_get_force_bit ( ) ; // skips spaces after
2012-02-27 21:14:46 +00:00
2020-05-08 00:34:46 +00:00
switch ( get_addr_mode ( & result ) ) {
2016-12-28 20:32:00 +00:00
case IMMEDIATE_ADDRESSING : // #$ff or #$ffff (depending on accu length)
2020-05-21 23:46:11 +00:00
immediate_opcodes = imm_ops ( & force_bit , accu_imm [ index ] , flags & IMMASK ) ;
2012-02-27 21:14:46 +00:00
// CAUTION - do not incorporate the line above into the line
// below - "force_bit" might be undefined (depends on compiler).
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , immediate_opcodes ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case ABSOLUTE_ADDRESSING : // $ff, $ffff, $ffffff
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_abs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case X_INDEXED_ADDRESSING : // $ff,x, $ffff,x, $ffffff,x
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_xabs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case Y_INDEXED_ADDRESSING : // $ffff,y (in theory, "$ff,y" as well)
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_yabs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case STACK_INDEXED_ADDRESSING : // $ff,s
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_sabs8 [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case X_INDEXED_INDIRECT_ADDRESSING : // ($ff,x)
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_xind8 [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case INDIRECT_ADDRESSING : // ($ff)
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_ind8 [ index ] ) ;
2017-12-22 22:55:36 +00:00
check_zp_wraparound ( & result ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case INDIRECT_Y_INDEXED_ADDRESSING : // ($ff),y
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_indy8 [ index ] ) ;
2017-12-22 22:55:36 +00:00
check_zp_wraparound ( & result ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-05-21 19:36:59 +00:00
case INDIRECT_Z_INDEXED_ADDRESSING : // ($ff),z only for 65ce02/4502/m65
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_indz8 [ index ] ) ;
2017-12-22 22:55:36 +00:00
check_zp_wraparound ( & result ) ;
2016-12-28 20:32:00 +00:00
break ;
2020-05-21 23:46:11 +00:00
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 )
2020-07-12 18:46:06 +00:00
Output_byte ( 0xea ) ;
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_lind8 [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-05-21 19:36:59 +00:00
case LONG_INDIRECT_Y_INDEXED_ADDRESSING : // [$ff],y only for 65816
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_lindy8 [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-05-21 19:36:59 +00:00
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING : // ($ff,s),y only for 65816 and 65ce02/4502/m65
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_sindy8 [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-05-21 23:46:11 +00:00
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 )
2020-07-12 18:46:06 +00:00
Output_byte ( 0xea ) ;
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , accu_lindz8 [ index ] ) ;
2020-05-21 19:36:59 +00:00
break ;
2012-02-27 21:14:46 +00:00
default : // other combinations are illegal
Throw_error ( exception_illegal_combination ) ;
}
}
// Various mnemonics with different addressing modes.
2020-06-14 00:26:38 +00:00
static void group_misc ( int index , bits immediate_mode )
2012-02-27 21:14:46 +00:00
{
2016-12-28 20:32:00 +00:00
unsigned long immediate_opcodes ;
2020-04-28 16:02:09 +00:00
struct number result ;
2020-06-14 00:26:38 +00:00
bits force_bit = Input_get_force_bit ( ) ; // skips spaces after
2012-02-27 21:14:46 +00:00
2020-05-08 00:34:46 +00:00
switch ( get_addr_mode ( & result ) ) {
2016-12-28 20:32:00 +00:00
case IMPLIED_ADDRESSING : // implied addressing
2012-02-27 21:14:46 +00:00
if ( misc_impl [ index ] )
Output_byte ( misc_impl [ index ] ) ;
else
Throw_error ( exception_illegal_combination ) ;
break ;
2016-12-28 20:32:00 +00:00
case IMMEDIATE_ADDRESSING : // #$ff or #$ffff (depending on index register length)
immediate_opcodes = imm_ops ( & force_bit , misc_imm [ index ] , immediate_mode ) ;
2012-02-27 21:14:46 +00:00
// CAUTION - do not incorporate the line above into the line
// below - "force_bit" might be undefined (depends on compiler).
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , immediate_opcodes ) ;
2020-05-29 13:04:28 +00:00
// warn about unstable ANE/LXA (undocumented opcode of NMOS 6502)?
2014-11-25 23:57:15 +00:00
if ( ( CPU_state . type - > flags & CPUFLAG_8B_AND_AB_NEED_0_ARG )
2020-06-16 22:44:54 +00:00
& & ( result . ntype = = NUMTYPE_INT )
& & ( result . val . intval ! = 0x00 ) ) {
2016-12-28 20:32:00 +00:00
if ( immediate_opcodes = = 0x8b )
2014-11-25 23:57:15 +00:00
Throw_warning ( " Assembling unstable ANE #NONZERO instruction " ) ;
2016-12-28 20:32:00 +00:00
else if ( immediate_opcodes = = 0xab )
2014-11-25 23:57:15 +00:00
Throw_warning ( " Assembling unstable LXA #NONZERO instruction " ) ;
}
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case ABSOLUTE_ADDRESSING : // $ff or $ffff
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , misc_abs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case X_INDEXED_ADDRESSING : // $ff,x or $ffff,x
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , misc_xabs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case Y_INDEXED_ADDRESSING : // $ff,y or $ffff,y
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , misc_yabs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
default : // other combinations are illegal
Throw_error ( exception_illegal_combination ) ;
}
}
2016-12-28 20:32:00 +00:00
// mnemonics using only 8bit relative addressing (short branch instructions).
static void group_std_branches ( int opcode )
{
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
2016-12-28 20:32:00 +00:00
Output_byte ( opcode ) ;
near_branch ( 2 ) ;
}
// "bbr0..7" and "bbs0..7"
static void group_bbr_bbs ( int opcode )
{
2020-04-28 16:02:09 +00:00
struct number zpmem ;
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
2016-12-28 20:32:00 +00:00
2020-05-08 00:34:46 +00:00
get_int_arg ( & zpmem , TRUE ) ;
2016-12-28 20:32:00 +00:00
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 )
2012-02-27 21:14:46 +00:00
{
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
2016-12-28 20:32:00 +00:00
Output_byte ( opcode ) ;
far_branch ( preoffset ) ;
}
// "mvn" and "mvp"
2020-06-26 10:45:20 +00:00
// TODO - allow alternative syntax with 24-bit addresses (select via CLI switch)?
2016-12-28 20:32:00 +00:00
static void group_mvn_mvp ( int opcode )
{
2020-06-26 10:45:20 +00:00
boolean unmatched_hash = FALSE ;
2020-04-28 16:02:09 +00:00
struct number source ,
2012-02-27 21:14:46 +00:00
target ;
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
2012-02-27 21:14:46 +00:00
2020-06-26 10:45:20 +00:00
// assembler syntax: "mnemonic source, target" or "mnemonic #source, #target"
// machine language order: "opcode target source"
SKIPSPACE ( ) ;
// get first arg
if ( GotByte = = ' # ' ) {
GetByte ( ) ; // eat char
unmatched_hash = ! unmatched_hash ;
}
2020-05-08 00:34:46 +00:00
get_int_arg ( & source , TRUE ) ;
typesystem_want_nonaddr ( & source ) ;
2020-06-26 10:45:20 +00:00
// get comma
if ( ! Input_accept_comma ( ) ) {
2012-02-27 21:14:46 +00:00
Throw_error ( exception_syntax ) ;
2020-06-26 10:45:20 +00:00
return ;
2012-02-27 21:14:46 +00:00
}
2020-06-26 10:45:20 +00:00
// get second arg
if ( GotByte = = ' # ' ) {
GetByte ( ) ; // eat char
unmatched_hash = ! unmatched_hash ;
}
get_int_arg ( & target , TRUE ) ;
typesystem_want_nonaddr ( & target ) ;
// output
Output_byte ( opcode ) ;
output_8 ( target . val . intval ) ;
output_8 ( source . val . intval ) ;
// sanity check
if ( unmatched_hash )
Throw_error ( exception_syntax ) ;
Input_ensure_EOS ( ) ;
2012-02-27 21:14:46 +00:00
}
2016-12-28 20:32:00 +00:00
// "rmb0..7" and "smb0..7"
2017-01-08 22:16:43 +00:00
static void group_only_zp ( int opcode )
2016-12-28 20:32:00 +00:00
{
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
2020-04-28 16:02:09 +00:00
struct number target ;
2016-12-28 20:32:00 +00:00
2020-05-08 00:34:46 +00:00
get_int_arg ( & target , TRUE ) ;
2016-12-28 20:32:00 +00:00
typesystem_want_addr ( & target ) ;
Output_byte ( opcode ) ;
output_8 ( target . val . intval ) ;
Input_ensure_EOS ( ) ;
}
2020-06-03 11:02:16 +00:00
// NOP on m65 cpu (FIXME - "!align" outputs NOPs, what about that? what if user writes NEG:NEG?)
static void group_prefix ( int opcode )
{
2020-08-12 12:31:06 +00:00
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
2020-06-03 11:02:16 +00:00
char buffer [ 100 ] ; // 640K should be enough for anybody
2020-06-30 09:24:30 +00:00
sprintf ( buffer , " The chosen CPU uses opcode 0x%02x as a prefix code, do not use this mnemonic! " , opcode ) ;
2020-06-03 11:02:16 +00:00
Throw_error ( buffer ) ;
}
2012-02-27 21:14:46 +00:00
// The jump instructions.
static void group_jump ( int index )
{
2020-04-28 16:02:09 +00:00
struct number result ;
2020-06-14 00:26:38 +00:00
bits force_bit = Input_get_force_bit ( ) ; // skips spaces after
2012-02-27 21:14:46 +00:00
2020-05-08 00:34:46 +00:00
switch ( get_addr_mode ( & result ) ) {
2016-12-28 20:32:00 +00:00
case ABSOLUTE_ADDRESSING : // absolute16 or absolute24
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , jump_abs [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case INDIRECT_ADDRESSING : // ($ffff)
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , jump_ind [ index ] ) ;
2012-02-27 21:14:46 +00:00
// check whether to warn about 6502's JMP() bug
2020-06-16 22:44:54 +00:00
if ( ( result . ntype = = NUMTYPE_INT )
& & ( ( result . val . intval & 0xff ) = = 0xff )
2014-03-10 00:17:10 +00:00
& & ( CPU_state . type - > flags & CPUFLAG_INDIRECTJMPBUGGY ) )
2012-02-27 21:14:46 +00:00
Throw_warning ( " Assembling buggy JMP($xxff) instruction " ) ;
break ;
2016-12-28 20:32:00 +00:00
case X_INDEXED_INDIRECT_ADDRESSING : // ($ffff,x)
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , jump_xind [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
case LONG_INDIRECT_ADDRESSING : // [$ffff]
2020-07-18 13:50:46 +00:00
make_instruction ( force_bit , & result , jump_lind [ index ] ) ;
2012-02-27 21:14:46 +00:00
break ;
default : // other combinations are illegal
Throw_error ( exception_illegal_combination ) ;
}
}
// Work function
2020-06-14 00:26:38 +00:00
static boolean check_mnemo_tree ( struct ronode * tree , struct dynabuf * dyna_buf )
2012-02-27 21:14:46 +00:00
{
void * node_body ;
2020-06-14 00:26:38 +00:00
int code ;
bits flags ;
2012-02-27 21:14:46 +00:00
// 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
2020-05-21 23:46:11 +00:00
flags = ( ( int ) node_body ) & FLAGSMASK ; // get immediate mode flags and prefix flags
if ( flags & PREFIX_NEGNEG ) {
Output_byte ( 0x42 ) ;
Output_byte ( 0x42 ) ;
}
2016-12-28 20:32:00 +00:00
switch ( GROUP ( ( long ) node_body ) ) {
2012-02-27 21:14:46 +00:00
case GROUP_ACCU : // main accumulator stuff
2020-05-21 23:46:11 +00:00
group_main ( code , flags ) ;
2012-02-27 21:14:46 +00:00
break ;
case GROUP_MISC : // misc
2020-05-21 23:46:11 +00:00
group_misc ( code , flags & IMMASK ) ;
2012-02-27 21:14:46 +00:00
break ;
case GROUP_ALLJUMPS : // the jump instructions
group_jump ( code ) ;
break ;
case GROUP_IMPLIEDONLY : // mnemonics with only implied addressing
group_only_implied_addressing ( code ) ;
break ;
case GROUP_RELATIVE8 : // short relative
2016-12-28 20:32:00 +00:00
group_std_branches ( code ) ;
break ;
case GROUP_BITBRANCH : // "bbr0..7" and "bbs0..7"
group_bbr_bbs ( code ) ;
2012-02-27 21:14:46 +00:00
break ;
2016-12-28 20:32:00 +00:00
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 ) ;
2012-02-27 21:14:46 +00:00
break ;
case GROUP_BOTHMOVES : // "mvp" and "mvn"
2016-12-28 20:32:00 +00:00
group_mvn_mvp ( code ) ;
break ;
2020-07-18 13:50:46 +00:00
case GROUP_ZPONLY : // "rmb0..7", "smb0..7", "inw", "dew"
2017-01-08 22:16:43 +00:00
group_only_zp ( code ) ;
2012-02-27 21:14:46 +00:00
break ;
2020-06-03 11:02:16 +00:00
case GROUP_PREFIX : // NOP for m65 cpu
group_prefix ( code ) ;
break ;
2012-02-27 21:14:46 +00:00
default : // others indicate bugs
Bug_found ( " IllegalGroupIndex " , code ) ;
}
return TRUE ;
}
2016-12-28 20:32:00 +00:00
// check whether mnemonic in GlobalDynaBuf is supported by 6502 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_6502_mnemo ( int length )
2012-02-27 21:14:46 +00:00
{
if ( length ! = 3 )
return FALSE ;
// make lower case version of mnemonic in local dynamic buffer
DynaBuf_to_lower ( mnemo_dyna_buf , GlobalDynaBuf ) ;
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_6502_tree , mnemo_dyna_buf ) ;
2012-02-27 21:14:46 +00:00
}
2020-05-29 13:04:28 +00:00
// check whether mnemonic in GlobalDynaBuf is supported by NMOS 6502 cpu.
boolean keyword_is_nmos6502_mnemo ( int length )
2012-02-27 21:14:46 +00:00
{
if ( length ! = 3 )
return FALSE ;
// make lower case version of mnemonic in local dynamic buffer
DynaBuf_to_lower ( mnemo_dyna_buf , GlobalDynaBuf ) ;
2014-11-23 23:40:01 +00:00
// first check undocumented ("illegal") opcodes...
2015-06-14 23:16:23 +00:00
if ( check_mnemo_tree ( mnemo_6502undoc1_tree , mnemo_dyna_buf ) )
return TRUE ;
// then check some more undocumented ("illegal") opcodes...
if ( check_mnemo_tree ( mnemo_6502undoc2_tree , mnemo_dyna_buf ) )
2014-11-23 23:40:01 +00:00
return TRUE ;
// ...then check original opcodes
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_6502_tree , mnemo_dyna_buf ) ;
2014-11-23 23:40:01 +00:00
}
2016-12-28 20:32:00 +00:00
// check whether mnemonic in GlobalDynaBuf is supported by C64DTV2 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_c64dtv2_mnemo ( int length )
2014-11-23 23:40:01 +00:00
{
if ( length ! = 3 )
return FALSE ;
// make lower case version of mnemonic in local dynamic buffer
DynaBuf_to_lower ( mnemo_dyna_buf , GlobalDynaBuf ) ;
// first check C64DTV2 extensions...
if ( check_mnemo_tree ( mnemo_c64dtv2_tree , mnemo_dyna_buf ) )
return TRUE ;
2015-06-14 23:16:23 +00:00
// ...then check a few undocumented ("illegal") opcodes...
if ( check_mnemo_tree ( mnemo_6502undoc1_tree , mnemo_dyna_buf ) )
2012-02-27 21:14:46 +00:00
return TRUE ;
// ...then check original opcodes
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_6502_tree , mnemo_dyna_buf ) ;
2012-02-27 21:14:46 +00:00
}
2016-12-28 20:32:00 +00:00
// check whether mnemonic in GlobalDynaBuf is supported by 65c02 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_65c02_mnemo ( int length )
2012-02-27 21:14:46 +00:00
{
if ( length ! = 3 )
return FALSE ;
// make lower case version of mnemonic in local dynamic buffer
DynaBuf_to_lower ( mnemo_dyna_buf , GlobalDynaBuf ) ;
2016-12-28 20:32:00 +00:00
// first check extensions because some mnemonics gained new addressing modes...
2012-02-27 21:14:46 +00:00
if ( check_mnemo_tree ( mnemo_65c02_tree , mnemo_dyna_buf ) )
return TRUE ;
// ...then check original opcodes
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_6502_tree , mnemo_dyna_buf ) ;
2012-02-27 21:14:46 +00:00
}
2016-12-28 20:32:00 +00:00
// check whether mnemonic in GlobalDynaBuf is supported by Rockwell 65c02 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_r65c02_mnemo ( int length )
2016-12-28 20:32:00 +00:00
{
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)
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_bitmanips_tree , mnemo_dyna_buf ) ;
2016-12-28 20:32:00 +00:00
}
// check whether mnemonic in GlobalDynaBuf is supported by WDC w65c02 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_w65c02_mnemo ( int length )
2016-12-28 20:32:00 +00:00
{
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"
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_stp_wai_tree , mnemo_dyna_buf ) ;
2016-12-28 20:32:00 +00:00
}
// check whether mnemonic in GlobalDynaBuf is supported by CSG 65CE02 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_65ce02_mnemo ( int length )
2016-12-28 20:32:00 +00:00
{
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"
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_aug_tree , mnemo_dyna_buf ) ;
2016-12-28 20:32:00 +00:00
}
// check whether mnemonic in GlobalDynaBuf is supported by CSG 4502 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_4502_mnemo ( int length )
2016-12-28 20:32:00 +00:00
{
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)...
2020-05-21 19:36:59 +00:00
if ( check_mnemo_tree ( mnemo_bitmanips_tree , mnemo_dyna_buf ) )
return TRUE ;
// ...then check "map" and "eom"
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_map_eom_tree , mnemo_dyna_buf ) ;
2020-05-21 19:36:59 +00:00
}
// check whether mnemonic in GlobalDynaBuf is supported by MEGA65 cpu.
boolean keyword_is_m65_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 m65 extensions because some mnemonics gained new addressing modes...
if ( check_mnemo_tree ( mnemo_m65_tree , mnemo_dyna_buf ) )
return TRUE ;
// ...then check 65ce02 extensions because of the same reason...
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)...
2016-12-28 20:32:00 +00:00
if ( check_mnemo_tree ( mnemo_bitmanips_tree , mnemo_dyna_buf ) )
return TRUE ;
// ...then check "map" and "eom"
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_map_eom_tree , mnemo_dyna_buf ) ;
2016-12-28 20:32:00 +00:00
}
2012-02-27 21:14:46 +00:00
2016-12-28 20:32:00 +00:00
// check whether mnemonic in GlobalDynaBuf is supported by 65816 cpu.
2020-05-06 11:40:06 +00:00
boolean keyword_is_65816_mnemo ( int length )
2012-02-27 21:14:46 +00:00
{
if ( length ! = 3 )
return FALSE ;
// make lower case version of mnemonic in local dynamic buffer
DynaBuf_to_lower ( mnemo_dyna_buf , GlobalDynaBuf ) ;
2016-12-28 20:32:00 +00:00
// first check 65816 extensions because some mnemonics gained new addressing modes...
2012-02-27 21:14:46 +00:00
if ( check_mnemo_tree ( mnemo_65816_tree , mnemo_dyna_buf ) )
return TRUE ;
2016-12-28 20:32:00 +00:00
// ...then check 65c02 extensions because of the same reason...
2012-02-27 21:14:46 +00:00
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 WDC extensions "stp" and "wai"
2020-06-14 00:26:38 +00:00
return check_mnemo_tree ( mnemo_stp_wai_tree , mnemo_dyna_buf ) ;
2012-02-27 21:14:46 +00:00
}