990 lines
35 KiB
C++
990 lines
35 KiB
C++
|
|
#include "m7700.hpp"
|
|
|
|
// 7700 operation codes :
|
|
struct opcode
|
|
{
|
|
uint16 insn; // instruction
|
|
uint16 code; // code of opcode
|
|
m7700_addr_mode_t mode; // addressing mode
|
|
};
|
|
|
|
// 7700 instructions
|
|
static const struct opcode opcodes_7700[] =
|
|
{
|
|
// ADC
|
|
{ m7700_adc, 0x69, A_IMM },
|
|
{ m7700_adc, 0x65, A_DIR },
|
|
{ m7700_adc, 0x75, A_DIR_IND_X },
|
|
{ m7700_adc, 0x72, A_DIR_INDI },
|
|
{ m7700_adc, 0x61, A_DIR_IND_X_INDI },
|
|
{ m7700_adc, 0x71, A_DIR_INDI_IND_Y },
|
|
{ m7700_adc, 0x67, A_DIR_INDI_LONG },
|
|
{ m7700_adc, 0x77, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_adc, 0x6D, A_ABS },
|
|
{ m7700_adc, 0x7D, A_ABS_IND_X },
|
|
{ m7700_adc, 0x79, A_ABS_IND_Y },
|
|
{ m7700_adc, 0x6F, A_ABS_LONG },
|
|
{ m7700_adc, 0x7F, A_ABS_LONG_IND_X },
|
|
{ m7700_adc, 0x63, A_STACK_PTR_REL },
|
|
{ m7700_adc, 0x73, A_STACK_PTR_REL_IIY },
|
|
// AND
|
|
{ m7700_and, 0x29, A_IMM },
|
|
{ m7700_and, 0x25, A_DIR },
|
|
{ m7700_and, 0x35, A_DIR_IND_X },
|
|
{ m7700_and, 0x32, A_DIR_INDI },
|
|
{ m7700_and, 0x21, A_DIR_IND_X_INDI },
|
|
{ m7700_and, 0x31, A_DIR_INDI_IND_Y },
|
|
{ m7700_and, 0x27, A_DIR_INDI_LONG },
|
|
{ m7700_and, 0x37, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_and, 0x2D, A_ABS },
|
|
{ m7700_and, 0x3D, A_ABS_IND_X },
|
|
{ m7700_and, 0x39, A_ABS_IND_Y },
|
|
{ m7700_and, 0x2F, A_ABS_LONG },
|
|
{ m7700_and, 0x3F, A_ABS_LONG_IND_X },
|
|
{ m7700_and, 0x23, A_STACK_PTR_REL },
|
|
{ m7700_and, 0x33, A_STACK_PTR_REL_IIY },
|
|
// ASL
|
|
{ m7700_asl, 0x0A, A_ACC_A },
|
|
{ m7700_asl, 0x420A, A_ACC_B },
|
|
{ m7700_asl, 0x06, A_DIR },
|
|
{ m7700_asl, 0x16, A_DIR_IND_X },
|
|
{ m7700_asl, 0x0E, A_ABS },
|
|
{ m7700_asl, 0x1E, A_ABS_IND_X },
|
|
// BBC
|
|
{ m7700_bbc, 0x34, A_DIR_BIT_REL },
|
|
{ m7700_bbc, 0x3C, A_ABS_BIT_REL },
|
|
// BBS
|
|
{ m7700_bbs, 0x24, A_DIR_BIT_REL },
|
|
{ m7700_bbs, 0x2C, A_ABS_BIT_REL },
|
|
// BCC
|
|
{ m7700_bcc, 0x90, A_REL },
|
|
// BCS
|
|
{ m7700_bcs, 0xB0, A_REL },
|
|
// BEQ
|
|
{ m7700_beq, 0xF0, A_REL },
|
|
// BMI
|
|
{ m7700_bmi, 0x30, A_REL },
|
|
// BNE
|
|
{ m7700_bne, 0xD0, A_REL },
|
|
// BPL
|
|
{ m7700_bpl, 0x10, A_REL },
|
|
// BRA
|
|
{ m7700_bra, 0x80, A_REL },
|
|
{ m7700_bra, 0x82, A_REL_LONG },
|
|
#if 0 /* detected as a special insn */
|
|
// BRK
|
|
{ m7700_brk, 0x00EA, A_IMPL },
|
|
#endif
|
|
// BVC
|
|
{ m7700_bvc, 0x50, A_REL },
|
|
// BVS
|
|
{ m7700_bvs, 0x70, A_REL },
|
|
// CLB
|
|
{ m7700_clb, 0x14, A_DIR_BIT },
|
|
{ m7700_clb, 0x1C, A_ABS_BIT },
|
|
// CLC
|
|
{ m7700_clc, 0x18, A_IMPL },
|
|
// CLI
|
|
{ m7700_cli, 0x58, A_IMPL },
|
|
// CLM
|
|
{ m7700_clm, 0xD8, A_IMPL },
|
|
// CLP
|
|
{ m7700_clp, 0xC2, A_IMM },
|
|
// CLV
|
|
{ m7700_clv, 0xB8, A_IMPL },
|
|
// CMP
|
|
{ m7700_cmp, 0xC9, A_IMM },
|
|
{ m7700_cmp, 0xC5, A_DIR },
|
|
{ m7700_cmp, 0xD5, A_DIR_IND_X },
|
|
{ m7700_cmp, 0xD2, A_DIR_INDI },
|
|
{ m7700_cmp, 0xC1, A_DIR_IND_X_INDI },
|
|
{ m7700_cmp, 0xD1, A_DIR_INDI_IND_Y },
|
|
{ m7700_cmp, 0xC7, A_DIR_INDI_LONG },
|
|
{ m7700_cmp, 0xD7, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_cmp, 0xCD, A_ABS },
|
|
{ m7700_cmp, 0xDD, A_ABS_IND_X },
|
|
{ m7700_cmp, 0xD9, A_ABS_IND_Y },
|
|
{ m7700_cmp, 0xCF, A_ABS_LONG },
|
|
{ m7700_cmp, 0xDF, A_ABS_LONG_IND_X },
|
|
{ m7700_cmp, 0xC3, A_STACK_PTR_REL },
|
|
{ m7700_cmp, 0xD3, A_STACK_PTR_REL_IIY },
|
|
// CPX
|
|
{ m7700_cpx, 0xE0, A_IMM },
|
|
{ m7700_cpx, 0xE4, A_DIR },
|
|
{ m7700_cpx, 0xEC, A_ABS },
|
|
// CPY
|
|
{ m7700_cpy, 0xC0, A_IMM },
|
|
{ m7700_cpy, 0xC4, A_DIR },
|
|
{ m7700_cpy, 0xCC, A_ABS },
|
|
// DEC
|
|
{ m7700_dec, 0x1A, A_ACC_A },
|
|
{ m7700_dec, 0x421A, A_ACC_B },
|
|
{ m7700_dec, 0xC6, A_DIR },
|
|
{ m7700_dec, 0xD6, A_DIR_IND_X },
|
|
{ m7700_dec, 0xCE, A_ABS },
|
|
{ m7700_dec, 0xDE, A_ABS_IND_X },
|
|
// DEX
|
|
{ m7700_dex, 0xCA, A_IMPL },
|
|
// DEY
|
|
{ m7700_dey, 0x88, A_IMPL },
|
|
// DIV
|
|
{ m7700_div, 0x8929, A_IMM },
|
|
{ m7700_div, 0x8925, A_DIR },
|
|
{ m7700_div, 0x8935, A_DIR_IND_X },
|
|
{ m7700_div, 0x8932, A_DIR_INDI },
|
|
{ m7700_div, 0x8921, A_DIR_IND_X_INDI },
|
|
{ m7700_div, 0x8931, A_DIR_INDI_IND_Y },
|
|
{ m7700_div, 0x8927, A_DIR_INDI_LONG },
|
|
{ m7700_div, 0x8937, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_div, 0x892D, A_ABS },
|
|
{ m7700_div, 0x893D, A_ABS_IND_X },
|
|
{ m7700_div, 0x8939, A_ABS_IND_Y },
|
|
{ m7700_div, 0x892F, A_ABS_LONG },
|
|
{ m7700_div, 0x893F, A_ABS_LONG_IND_X },
|
|
{ m7700_div, 0x8923, A_STACK_PTR_REL },
|
|
{ m7700_div, 0x8933, A_STACK_PTR_REL_IIY },
|
|
// EOR
|
|
{ m7700_eor, 0x49, A_IMM },
|
|
{ m7700_eor, 0x45, A_DIR },
|
|
{ m7700_eor, 0x55, A_DIR_IND_X },
|
|
{ m7700_eor, 0x52, A_DIR_INDI },
|
|
{ m7700_eor, 0x41, A_DIR_IND_X_INDI },
|
|
{ m7700_eor, 0x51, A_DIR_INDI_IND_Y },
|
|
{ m7700_eor, 0x47, A_DIR_INDI_LONG },
|
|
{ m7700_eor, 0x57, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_eor, 0x4D, A_ABS },
|
|
{ m7700_eor, 0x5D, A_ABS_IND_X },
|
|
{ m7700_eor, 0x59, A_ABS_IND_Y },
|
|
{ m7700_eor, 0x4F, A_ABS_LONG },
|
|
{ m7700_eor, 0x5F, A_ABS_LONG_IND_X },
|
|
{ m7700_eor, 0x43, A_STACK_PTR_REL },
|
|
{ m7700_eor, 0x53, A_STACK_PTR_REL_IIY },
|
|
// INC
|
|
{ m7700_inc, 0x3A, A_ACC_A },
|
|
{ m7700_inc, 0x423A, A_ACC_B },
|
|
{ m7700_inc, 0xE6, A_DIR },
|
|
{ m7700_inc, 0xF6, A_DIR_IND_X },
|
|
{ m7700_inc, 0xEE, A_ABS },
|
|
{ m7700_inc, 0xFE, A_ABS_IND_X },
|
|
// INX
|
|
{ m7700_inx, 0xE8, A_IMPL },
|
|
// INY
|
|
{ m7700_iny, 0xC8, A_IMPL },
|
|
// JMP
|
|
{ m7700_jmp, 0x4C, A_ABS },
|
|
{ m7700_jmp, 0x5C, A_ABS_LONG },
|
|
{ m7700_jmp, 0x6C, A_ABS_INDI },
|
|
{ m7700_jmp, 0xDC, A_ABS_INDI_LONG },
|
|
{ m7700_jmp, 0x7C, A_ABS_IND_X_INDI },
|
|
// JSR
|
|
{ m7700_jsr, 0x20, A_ABS },
|
|
{ m7700_jsr, 0x22, A_ABS_LONG },
|
|
{ m7700_jsr, 0xFC, A_ABS_IND_X_INDI },
|
|
// LDA
|
|
{ m7700_lda, 0xA9, A_IMM },
|
|
{ m7700_lda, 0xA5, A_DIR },
|
|
{ m7700_lda, 0xB5, A_DIR_IND_X },
|
|
{ m7700_lda, 0xB2, A_DIR_INDI },
|
|
{ m7700_lda, 0xA1, A_DIR_IND_X_INDI },
|
|
{ m7700_lda, 0xB1, A_DIR_INDI_IND_Y },
|
|
{ m7700_lda, 0xA7, A_DIR_INDI_LONG },
|
|
{ m7700_lda, 0xB7, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_lda, 0xAD, A_ABS },
|
|
{ m7700_lda, 0xBD, A_ABS_IND_X },
|
|
{ m7700_lda, 0xB9, A_ABS_IND_Y },
|
|
{ m7700_lda, 0xAF, A_ABS_LONG },
|
|
{ m7700_lda, 0xBF, A_ABS_LONG_IND_X },
|
|
{ m7700_lda, 0xA3, A_STACK_PTR_REL },
|
|
{ m7700_lda, 0xB3, A_STACK_PTR_REL_IIY },
|
|
// LDM
|
|
{ m7700_ldm, 0x64, A_DIR },
|
|
{ m7700_ldm, 0x74, A_DIR_IND_X },
|
|
{ m7700_ldm, 0x9C, A_ABS },
|
|
{ m7700_ldm, 0x9E, A_ABS_IND_X },
|
|
// LDT
|
|
{ m7700_ldt, 0x89C2, A_IMM },
|
|
// LDX
|
|
{ m7700_ldx, 0xA2, A_IMM },
|
|
{ m7700_ldx, 0xA6, A_DIR },
|
|
{ m7700_ldx, 0xB6, A_DIR_IND_Y },
|
|
{ m7700_ldx, 0xAE, A_ABS },
|
|
{ m7700_ldx, 0xBE, A_ABS_IND_Y },
|
|
// LDY
|
|
{ m7700_ldy, 0xA0, A_IMM },
|
|
{ m7700_ldy, 0xA4, A_DIR },
|
|
{ m7700_ldy, 0xB4, A_DIR_IND_X },
|
|
{ m7700_ldy, 0xAC, A_ABS },
|
|
{ m7700_ldy, 0xBC, A_ABS_IND_X },
|
|
// LSR
|
|
{ m7700_lsr, 0x4A, A_ACC_A },
|
|
{ m7700_lsr, 0x424A, A_ACC_B },
|
|
{ m7700_lsr, 0x46, A_DIR },
|
|
{ m7700_lsr, 0x56, A_DIR_IND_X },
|
|
{ m7700_lsr, 0x4E, A_ABS },
|
|
{ m7700_lsr, 0x5E, A_ABS_IND_X },
|
|
// MPY
|
|
{ m7700_mpy, 0x8909, A_IMM },
|
|
{ m7700_mpy, 0x8905, A_DIR },
|
|
{ m7700_mpy, 0x8915, A_DIR_IND_X },
|
|
{ m7700_mpy, 0x8912, A_DIR_INDI },
|
|
{ m7700_mpy, 0x8901, A_DIR_IND_X_INDI },
|
|
{ m7700_mpy, 0x8911, A_DIR_INDI_IND_Y },
|
|
{ m7700_mpy, 0x8907, A_DIR_INDI_LONG },
|
|
{ m7700_mpy, 0x8917, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_mpy, 0x890D, A_ABS },
|
|
{ m7700_mpy, 0x891D, A_ABS_IND_X },
|
|
{ m7700_mpy, 0x8919, A_ABS_IND_Y },
|
|
{ m7700_mpy, 0x890F, A_ABS_LONG },
|
|
{ m7700_mpy, 0x891F, A_ABS_LONG_IND_X },
|
|
{ m7700_mpy, 0x8903, A_STACK_PTR_REL },
|
|
{ m7700_mpy, 0x8913, A_STACK_PTR_REL_IIY },
|
|
// MVN
|
|
{ m7700_mvn, 0x54, A_BT },
|
|
// MVP
|
|
{ m7700_mvp, 0x44, A_BT },
|
|
// NOP
|
|
{ m7700_nop, 0xEA, A_IMPL },
|
|
// ORA
|
|
{ m7700_ora, 0x09, A_IMM },
|
|
{ m7700_ora, 0x05, A_DIR },
|
|
{ m7700_ora, 0x15, A_DIR_IND_X },
|
|
{ m7700_ora, 0x12, A_DIR_INDI },
|
|
{ m7700_ora, 0x01, A_DIR_IND_X_INDI },
|
|
{ m7700_ora, 0x11, A_DIR_INDI_IND_Y },
|
|
{ m7700_ora, 0x07, A_DIR_INDI_LONG },
|
|
{ m7700_ora, 0x17, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_ora, 0x0D, A_ABS },
|
|
{ m7700_ora, 0x1D, A_ABS_IND_X },
|
|
{ m7700_ora, 0x19, A_ABS_IND_Y },
|
|
{ m7700_ora, 0x0F, A_ABS_LONG },
|
|
{ m7700_ora, 0x1F, A_ABS_LONG_IND_X },
|
|
{ m7700_ora, 0x03, A_STACK_PTR_REL },
|
|
{ m7700_ora, 0x13, A_STACK_PTR_REL_IIY },
|
|
// PEA
|
|
{ m7700_pea, 0xF4, A_STACK_L },
|
|
// PEI
|
|
{ m7700_pei, 0xD4, A_STACK_S },
|
|
// PER
|
|
{ m7700_per, 0x62, A_STACK_L },
|
|
// PHA
|
|
{ m7700_pha, 0x48, A_STACK },
|
|
// PHB
|
|
{ m7700_phb, 0x4248, A_STACK },
|
|
// PHD
|
|
{ m7700_phd, 0x0B, A_STACK },
|
|
// PHG
|
|
{ m7700_phg, 0x4B, A_STACK },
|
|
// PHP
|
|
{ m7700_php, 0x08, A_STACK },
|
|
// PHT
|
|
{ m7700_pht, 0x8B, A_STACK },
|
|
// PHX
|
|
{ m7700_phx, 0xDA, A_STACK },
|
|
// PHY
|
|
{ m7700_phy, 0x5A, A_STACK },
|
|
// PLA
|
|
{ m7700_pla, 0x68, A_STACK },
|
|
// PLB
|
|
{ m7700_plb, 0x4268, A_STACK },
|
|
// PLD
|
|
{ m7700_pld, 0x2B, A_STACK },
|
|
// PLP
|
|
{ m7700_plp, 0x28, A_STACK },
|
|
// PLT
|
|
{ m7700_plt, 0xAB, A_STACK },
|
|
// PLX
|
|
{ m7700_plx, 0xFA, A_STACK },
|
|
// PLY
|
|
{ m7700_ply, 0x7A, A_STACK },
|
|
// PSH
|
|
{ m7700_psh, 0xEB, A_STACK_S },
|
|
// PUL
|
|
{ m7700_pul, 0xFB, A_STACK_S },
|
|
// RLA
|
|
{ m7700_rla, 0x8949, A_IMM },
|
|
// ROL
|
|
{ m7700_rol, 0x2A, A_ACC_A },
|
|
{ m7700_rol, 0x422A, A_ACC_B },
|
|
{ m7700_rol, 0x26, A_DIR },
|
|
{ m7700_rol, 0x36, A_DIR_IND_X },
|
|
{ m7700_rol, 0x2E, A_ABS },
|
|
{ m7700_rol, 0x3E, A_ABS_IND_X },
|
|
// ROR
|
|
{ m7700_ror, 0x6A, A_ACC_A },
|
|
{ m7700_ror, 0x426A, A_ACC_B },
|
|
{ m7700_ror, 0x66, A_DIR },
|
|
{ m7700_ror, 0x76, A_DIR_IND_X },
|
|
{ m7700_ror, 0x6E, A_ABS },
|
|
{ m7700_ror, 0x7E, A_ABS_IND_X },
|
|
// RTI
|
|
{ m7700_rti, 0x40, A_IMPL },
|
|
// RTL
|
|
{ m7700_rtl, 0x6B, A_IMPL },
|
|
// RTS
|
|
{ m7700_rts, 0x60, A_IMPL },
|
|
// SBC
|
|
{ m7700_sbc, 0xE9, A_IMM },
|
|
{ m7700_sbc, 0xE5, A_DIR },
|
|
{ m7700_sbc, 0xF5, A_DIR_IND_X },
|
|
{ m7700_sbc, 0xF2, A_DIR_INDI },
|
|
{ m7700_sbc, 0xE1, A_DIR_IND_X_INDI },
|
|
{ m7700_sbc, 0xF1, A_DIR_INDI_IND_Y },
|
|
{ m7700_sbc, 0xE7, A_DIR_INDI_LONG },
|
|
{ m7700_sbc, 0xF7, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_sbc, 0xED, A_ABS },
|
|
{ m7700_sbc, 0xFD, A_ABS_IND_X },
|
|
{ m7700_sbc, 0xF9, A_ABS_IND_Y },
|
|
{ m7700_sbc, 0xEF, A_ABS_LONG },
|
|
{ m7700_sbc, 0xFF, A_ABS_LONG_IND_X },
|
|
{ m7700_sbc, 0xE3, A_STACK_PTR_REL },
|
|
{ m7700_sbc, 0xF3, A_STACK_PTR_REL_IIY },
|
|
// SEB
|
|
{ m7700_seb, 0x04, A_DIR_BIT },
|
|
{ m7700_seb, 0x0C, A_ABS_BIT },
|
|
// SEC
|
|
{ m7700_sec, 0x38, A_IMPL },
|
|
// SEI
|
|
{ m7700_sei, 0x78, A_IMPL },
|
|
// SEM
|
|
{ m7700_sem, 0xF8, A_IMPL },
|
|
// SEP
|
|
{ m7700_sep, 0xE2, A_IMM },
|
|
// STA
|
|
{ m7700_sta, 0x85, A_DIR },
|
|
{ m7700_sta, 0x95, A_DIR_IND_X },
|
|
{ m7700_sta, 0x92, A_DIR_INDI },
|
|
{ m7700_sta, 0x81, A_DIR_IND_X_INDI },
|
|
{ m7700_sta, 0x91, A_DIR_INDI_IND_Y },
|
|
{ m7700_sta, 0x87, A_DIR_INDI_LONG },
|
|
{ m7700_sta, 0x97, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7700_sta, 0x8D, A_ABS },
|
|
{ m7700_sta, 0x9D, A_ABS_IND_X },
|
|
{ m7700_sta, 0x99, A_ABS_IND_Y },
|
|
{ m7700_sta, 0x8F, A_ABS_LONG },
|
|
{ m7700_sta, 0x9F, A_ABS_LONG_IND_X },
|
|
{ m7700_sta, 0x83, A_STACK_PTR_REL },
|
|
{ m7700_sta, 0x93, A_STACK_PTR_REL_IIY },
|
|
// STP
|
|
{ m7700_stp, 0xDB, A_IMPL },
|
|
// STX
|
|
{ m7700_stx, 0x86, A_DIR },
|
|
{ m7700_stx, 0x96, A_DIR_IND_Y },
|
|
{ m7700_stx, 0x8E, A_ABS },
|
|
// STY
|
|
{ m7700_sty, 0x84, A_DIR },
|
|
{ m7700_sty, 0x94, A_DIR_IND_X },
|
|
{ m7700_sty, 0x8C, A_ABS },
|
|
// TAD
|
|
{ m7700_tad, 0x5B, A_IMPL },
|
|
// TAS
|
|
{ m7700_tas, 0x1B, A_IMPL },
|
|
// TAX
|
|
{ m7700_tax, 0xAA, A_IMPL },
|
|
// TAY
|
|
{ m7700_tay, 0xA8, A_IMPL },
|
|
// TBD
|
|
{ m7700_tbd, 0x425B, A_IMPL },
|
|
// TBS
|
|
{ m7700_tbs, 0x421B, A_IMPL },
|
|
// TBX
|
|
{ m7700_tbx, 0x42AA, A_IMPL },
|
|
// TBY
|
|
{ m7700_tby, 0x42A8, A_IMPL },
|
|
// TDA
|
|
{ m7700_tda, 0x7B, A_IMPL },
|
|
// TDB
|
|
{ m7700_tdb, 0x427B, A_IMPL },
|
|
// TSA
|
|
{ m7700_tsa, 0x3B, A_IMPL },
|
|
// TSB
|
|
{ m7700_tsb, 0x423B, A_IMPL },
|
|
// TSX
|
|
{ m7700_tsx, 0xBA, A_IMPL },
|
|
// TXA
|
|
{ m7700_txa, 0x8A, A_IMPL },
|
|
// TXB
|
|
{ m7700_txb, 0x428A, A_IMPL },
|
|
// TXS
|
|
{ m7700_txs, 0x9A, A_IMPL },
|
|
// TXY
|
|
{ m7700_txy, 0x9B, A_IMPL },
|
|
// TYA
|
|
{ m7700_tya, 0x98, A_IMPL },
|
|
// TYB
|
|
{ m7700_tyb, 0x4298, A_IMPL },
|
|
// TYX
|
|
{ m7700_tyx, 0xBB, A_IMPL },
|
|
// WIT
|
|
{ m7700_wit, 0xCB, A_IMPL },
|
|
// XAB
|
|
{ m7700_xab, 0x8928, A_IMPL }
|
|
};
|
|
|
|
// 7750 instructions
|
|
static const struct opcode opcodes_7750[] =
|
|
{
|
|
// ASR
|
|
{ m7750_asr, 0x8908, A_ACC_A },
|
|
{ m7750_asr, 0x4208, A_ACC_B },
|
|
{ m7750_asr, 0x8906, A_DIR },
|
|
{ m7750_asr, 0x8916, A_DIR_IND_X },
|
|
{ m7750_asr, 0x890E, A_ABS },
|
|
{ m7750_asr, 0x891E, A_ABS_IND_X },
|
|
// DIVS
|
|
{ m7750_divs, 0x89A9, A_IMM },
|
|
{ m7750_divs, 0x89A5, A_DIR },
|
|
{ m7750_divs, 0x89B5, A_DIR_IND_X },
|
|
{ m7750_divs, 0x89B2, A_DIR_INDI },
|
|
{ m7750_divs, 0x89A1, A_DIR_IND_X_INDI },
|
|
{ m7750_divs, 0x89B1, A_DIR_INDI_IND_Y },
|
|
{ m7750_divs, 0x89A7, A_DIR_INDI_LONG },
|
|
{ m7750_divs, 0x89B7, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7750_divs, 0x89AD, A_ABS },
|
|
{ m7750_divs, 0x89BD, A_ABS_IND_X },
|
|
{ m7750_divs, 0x89B9, A_ABS_IND_Y },
|
|
{ m7750_divs, 0x89AF, A_ABS_LONG },
|
|
{ m7750_divs, 0x89BF, A_ABS_LONG_IND_X },
|
|
{ m7750_divs, 0x89A3, A_STACK_PTR_REL },
|
|
{ m7750_divs, 0x89B3, A_STACK_PTR_REL_IIY },
|
|
// EXTS
|
|
{ m7750_exts, 0x898B, A_ACC_A },
|
|
{ m7750_exts, 0x428B, A_ACC_B },
|
|
// EXTZ
|
|
{ m7750_extz, 0x89AB, A_ACC_A },
|
|
{ m7750_extz, 0x42AB, A_ACC_B },
|
|
// MPYS
|
|
{ m7750_mpys, 0x8989, A_IMM },
|
|
{ m7750_mpys, 0x8985, A_DIR },
|
|
{ m7750_mpys, 0x8995, A_DIR_IND_X },
|
|
{ m7750_mpys, 0x8992, A_DIR_INDI },
|
|
{ m7750_mpys, 0x8981, A_DIR_IND_X_INDI },
|
|
{ m7750_mpys, 0x8991, A_DIR_INDI_IND_Y },
|
|
{ m7750_mpys, 0x8987, A_DIR_INDI_LONG },
|
|
{ m7750_mpys, 0x8997, A_DIR_INDI_LONG_IND_Y },
|
|
{ m7750_mpys, 0x898D, A_ABS },
|
|
{ m7750_mpys, 0x899D, A_ABS_IND_X },
|
|
{ m7750_mpys, 0x8999, A_ABS_IND_Y },
|
|
{ m7750_mpys, 0x898F, A_ABS_LONG },
|
|
{ m7750_mpys, 0x899F, A_ABS_LONG_IND_X },
|
|
{ m7750_mpys, 0x8983, A_STACK_PTR_REL },
|
|
{ m7750_mpys, 0x8993, A_STACK_PTR_REL_IIY }
|
|
};
|
|
|
|
struct opcode_flag
|
|
{
|
|
int insn;
|
|
int flags;
|
|
#define MEM_R OP_ADDR_R // read access
|
|
#define MEM_W OP_ADDR_W // write access
|
|
};
|
|
|
|
static const struct opcode_flag opcodes_flags[] =
|
|
{
|
|
{ m7700_adc, MEM_R },
|
|
{ m7700_and, MEM_R },
|
|
{ m7700_asl, MEM_W },
|
|
{ m7750_asr, MEM_W },
|
|
{ m7700_bbc, MEM_R },
|
|
{ m7700_bbs, MEM_R },
|
|
{ m7700_clb, MEM_W },
|
|
{ m7700_cmp, MEM_R },
|
|
{ m7700_cpx, MEM_R },
|
|
{ m7700_cpy, MEM_R },
|
|
{ m7700_dec, MEM_W },
|
|
{ m7700_div, MEM_R },
|
|
{ m7750_divs, MEM_R },
|
|
{ m7700_eor, MEM_R },
|
|
{ m7700_inc, MEM_W },
|
|
{ m7700_jmp, MEM_R },
|
|
{ m7700_jsr, MEM_R },
|
|
{ m7700_lda, MEM_R },
|
|
{ m7700_ldm, MEM_W },
|
|
{ m7700_ldx, MEM_R },
|
|
{ m7700_ldy, MEM_R },
|
|
{ m7700_lsr, MEM_W },
|
|
{ m7700_mpy, MEM_R },
|
|
{ m7750_mpys, MEM_R },
|
|
{ m7700_ora, MEM_R },
|
|
{ m7700_rol, MEM_W },
|
|
{ m7700_ror, MEM_W },
|
|
{ m7700_sbc, MEM_R },
|
|
{ m7700_seb, MEM_W },
|
|
{ m7700_sta, MEM_W },
|
|
{ m7700_stx, MEM_W },
|
|
{ m7700_sty, MEM_W }
|
|
};
|
|
|
|
static bool with_acc(const insn_t &insn)
|
|
{
|
|
switch ( insn.itype )
|
|
{
|
|
case m7700_adc:
|
|
case m7700_and:
|
|
case m7700_cmp:
|
|
case m7700_eor:
|
|
case m7700_lda:
|
|
case m7700_sta:
|
|
case m7700_ora:
|
|
case m7700_sbc:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool imm_read_another_byte(const insn_t &insn)
|
|
{
|
|
bool m16 = get_sreg(insn.ea, rfM) == 0;
|
|
bool x16 = get_sreg(insn.ea, rfX) == 0;
|
|
|
|
// if insn are using X flag and this flag is set to 0
|
|
switch ( insn.itype )
|
|
{
|
|
case m7700_cpx:
|
|
case m7700_cpy:
|
|
case m7700_ldx:
|
|
case m7700_ldy:
|
|
if ( x16 )
|
|
return true;
|
|
}
|
|
|
|
// if insn is not using M flag
|
|
switch ( insn.itype )
|
|
{
|
|
case m7700_clp:
|
|
case m7700_ldt:
|
|
case m7700_pea:
|
|
case m7700_pei:
|
|
case m7700_per:
|
|
case m7700_psh:
|
|
case m7700_pul:
|
|
case m7700_sep:
|
|
case m7700_mvn:
|
|
case m7700_mvp:
|
|
return false;
|
|
}
|
|
// return true if M flag is set to 0
|
|
return m16;
|
|
}
|
|
|
|
inline static void set_flag(op_t &x, int flag)
|
|
{
|
|
x.specflag1 |= flag;
|
|
}
|
|
|
|
inline static void set_flag(insn_t &insn, int flag)
|
|
{
|
|
insn.auxpref |= flag;
|
|
}
|
|
|
|
inline static void set_op_reg(op_t &op, uint16 reg)
|
|
{
|
|
op.type = o_reg;
|
|
op.reg = reg;
|
|
op.dtype = dt_word; // XXX not sure
|
|
}
|
|
|
|
// shortcuts
|
|
#define set_op_acc_a(op) set_op_reg(op, rA)
|
|
#define set_op_acc_b(op) set_op_reg(op, rB)
|
|
//#define set_op_ind_x(op) set_op_reg(op, rX)
|
|
#define set_op_ind_y(op) set_op_reg(op, rY)
|
|
|
|
static uint16 my_next_word(insn_t &insn)
|
|
{
|
|
uchar b1 = insn.get_next_byte();
|
|
uchar b2 = insn.get_next_byte();
|
|
return b1 | (b2 << 8);
|
|
}
|
|
|
|
static uint32 my_next_3bytes(insn_t &insn)
|
|
{
|
|
uchar b1 = insn.get_next_byte();
|
|
uchar b2 = insn.get_next_byte();
|
|
uchar b3 = insn.get_next_byte();
|
|
return b1 | (b2 << 8) | (b3 << 16);
|
|
}
|
|
|
|
inline static int d_typ2addr(insn_t &insn, char d_typ)
|
|
{
|
|
switch ( d_typ )
|
|
{
|
|
default:
|
|
INTERR(10026);
|
|
case dt_byte: return insn.get_next_byte();
|
|
case dt_word: return my_next_word(insn);
|
|
|
|
// special case: dt_dword is 3 bytes long here
|
|
case dt_dword: return my_next_3bytes(insn);
|
|
}
|
|
}
|
|
|
|
inline static void set_op_imm(insn_t &insn, op_t &op, char d_typ)
|
|
{
|
|
op.type = o_imm;
|
|
op.value = d_typ2addr(insn, d_typ);
|
|
op.dtype = d_typ;
|
|
// when operating on 16-bit data in immediate addressing
|
|
// mode with data lenght selection flag set to 0, the
|
|
// bytes-count increases by 1
|
|
if ( imm_read_another_byte(insn) )
|
|
{
|
|
op.value |= insn.get_next_byte() << 8;
|
|
op.dtype = dt_word;
|
|
}
|
|
}
|
|
|
|
inline static void set_op_bit(insn_t &insn, op_t &op)
|
|
{
|
|
set_op_imm(insn, op, dt_byte);
|
|
op.type = o_bit;
|
|
}
|
|
|
|
inline static void set_op_addr(insn_t &insn, op_t &op, char d_typ)
|
|
{
|
|
op.type = o_near;
|
|
op.dtype = with_acc(insn) ? dt_word : d_typ;
|
|
op.addr = d_typ2addr(insn, d_typ);
|
|
}
|
|
|
|
inline static void set_op_mem(insn_t &insn, op_t &op, char d_typ, int flags)
|
|
{
|
|
op.type = o_mem;
|
|
op.dtype = with_acc(insn) ? dt_word : d_typ;
|
|
op.addr = d_typ2addr(insn, d_typ);
|
|
set_flag(op, flags);
|
|
}
|
|
|
|
inline static void set_op_displ(insn_t &insn, op_t &op, char d_typ, uint16 reg)
|
|
{
|
|
op.type = o_displ;
|
|
op.dtype = with_acc(insn) ? dt_word : d_typ;
|
|
op.addr = d_typ2addr(insn, d_typ);
|
|
op.reg = reg;
|
|
}
|
|
|
|
#define x insn.ops[n]
|
|
#define next_x insn.ops[n + 1]
|
|
|
|
// get an opcode flags struct from insn
|
|
static int get_opcode_flags(const int insn)
|
|
{
|
|
for ( int i = 0; i < qnumber(opcodes_flags); i++ )
|
|
{
|
|
if ( opcodes_flags[i].insn != insn )
|
|
continue;
|
|
|
|
return opcodes_flags[i].flags;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline bool is_jmp(const insn_t &insn)
|
|
{
|
|
return insn.itype == m7700_jmp || insn.itype == m7700_jsr;
|
|
}
|
|
|
|
static void set_op_mem_dr_rel(const insn_t &insn, op_t &op)
|
|
{
|
|
sel_t s = get_sreg(insn.ea, rDR);
|
|
// if the value of the DR register is known,
|
|
// we can compute the absolute address
|
|
if ( s != BADSEL )
|
|
{
|
|
op.addr += s;
|
|
// set operand type according to the M bit
|
|
bool m16 = get_sreg(insn.ea, rfM) == 0;
|
|
op.dtype = m16 ? dt_word : dt_byte;
|
|
}
|
|
set_flag(op, OP_ADDR_DR_REL);
|
|
}
|
|
|
|
// fill insn struct according to the specified addressing mode
|
|
void m7700_t::fill_insn(insn_t &insn, m7700_addr_mode_t mode)
|
|
{
|
|
int n = 0; // current operand
|
|
const int curflags = get_opcode_flags(insn.itype); // current flags
|
|
|
|
// if the first operand should be an accumulator (either A or B),
|
|
// just fill accordingly the insn structure
|
|
if ( with_acc(insn) )
|
|
{
|
|
if ( with_acc_b )
|
|
set_op_acc_b(x);
|
|
else
|
|
set_op_acc_a(x);
|
|
n++;
|
|
}
|
|
|
|
// the LDM instruction operands are always preceded by an immediate value,
|
|
// but this immediate value is always at the end of the operation code.
|
|
if ( insn.itype == m7700_ldm )
|
|
n++;
|
|
|
|
switch ( mode )
|
|
{
|
|
case A_IMPL: // implied
|
|
// nothing to do !
|
|
break;
|
|
|
|
case A_IMM: // immediate
|
|
set_op_imm(insn, x, dt_byte);
|
|
break;
|
|
|
|
case A_ACC_A: // accumulator A
|
|
set_op_acc_a(x);
|
|
break;
|
|
|
|
case A_ACC_B: // accumulator B
|
|
set_op_acc_b(x);
|
|
break;
|
|
|
|
case A_DIR: // direct
|
|
set_op_mem(insn, x, dt_byte, curflags);
|
|
set_op_mem_dr_rel(insn, x);
|
|
break;
|
|
|
|
case A_DIR_BIT: // direct bit
|
|
set_op_mem(insn, next_x, dt_byte, curflags);
|
|
set_op_mem_dr_rel(insn, next_x);
|
|
set_op_bit(insn, x);
|
|
break;
|
|
|
|
case A_DIR_IND_X: // direct indexed X
|
|
set_op_displ(insn, x, dt_byte, rX);
|
|
set_op_mem_dr_rel(insn, x);
|
|
break;
|
|
|
|
case A_DIR_IND_Y: // direct indexed Y
|
|
set_op_displ(insn, x, dt_byte, rY);
|
|
set_op_mem_dr_rel(insn, x);
|
|
break;
|
|
|
|
case A_DIR_INDI: // direct indirect
|
|
set_op_mem(insn, x, dt_byte, curflags);
|
|
set_flag(x, OP_ADDR_IND);
|
|
set_op_mem_dr_rel(insn, x);
|
|
break;
|
|
|
|
case A_DIR_IND_X_INDI: // direct indexed X indirect
|
|
set_op_displ(insn, x, dt_byte, rX);
|
|
set_flag(x, OP_DISPL_IND);
|
|
set_op_mem_dr_rel(insn, x);
|
|
break;
|
|
|
|
case A_DIR_INDI_IND_Y: // direct indirect indexed Y
|
|
set_op_displ(insn, x, dt_byte, rY);
|
|
set_flag(x, OP_DISPL_IND_P1);
|
|
set_op_mem_dr_rel(insn, x);
|
|
break;
|
|
|
|
case A_DIR_INDI_LONG: // direct indirect long
|
|
set_op_mem(insn, x, dt_byte, curflags);
|
|
set_flag(x, OP_ADDR_IND);
|
|
set_op_mem_dr_rel(insn, x);
|
|
set_flag(insn, INSN_LONG_FORMAT);
|
|
break;
|
|
|
|
case A_DIR_INDI_LONG_IND_Y: // direct indirect long indexed Y
|
|
set_op_displ(insn, x, dt_byte, rY);
|
|
set_flag(x, OP_DISPL_IND_P1);
|
|
set_op_mem_dr_rel(insn, x);
|
|
set_flag(insn, INSN_LONG_FORMAT);
|
|
break;
|
|
|
|
case A_ABS: // absolute
|
|
if ( is_jmp(insn) )
|
|
set_op_addr(insn, x, dt_word);
|
|
else
|
|
set_op_mem(insn, x, dt_word, curflags);
|
|
break;
|
|
|
|
case A_ABS_BIT: // absolute bit
|
|
set_op_mem(insn, next_x, dt_word, curflags);
|
|
set_op_bit(insn, x);
|
|
break;
|
|
|
|
case A_ABS_IND_X: // absolute indexed X
|
|
set_op_displ(insn, x, dt_word, rX);
|
|
break;
|
|
|
|
case A_ABS_IND_Y: // absolute indexed Y
|
|
set_op_displ(insn, x, dt_word, rY);
|
|
break;
|
|
|
|
case A_ABS_LONG: // absolute long
|
|
if ( is_jmp(insn) )
|
|
{
|
|
set_op_addr(insn, x, dt_dword);
|
|
set_flag(insn, INSN_LONG_FORMAT);
|
|
}
|
|
else
|
|
set_op_mem(insn, x, dt_dword, curflags);
|
|
break;
|
|
|
|
case A_ABS_LONG_IND_X: // absolute long indexed X
|
|
set_op_displ(insn, x, dt_dword, rX);
|
|
break;
|
|
|
|
case A_ABS_INDI: // absolute indirect
|
|
set_op_mem(insn, x, dt_word, curflags);
|
|
set_flag(x, OP_ADDR_IND);
|
|
break;
|
|
|
|
case A_ABS_INDI_LONG: // absolute indirect long
|
|
set_op_mem(insn, x, dt_word, curflags);
|
|
set_flag(x, OP_ADDR_IND);
|
|
if ( is_jmp(insn) )
|
|
set_flag(insn, INSN_LONG_FORMAT);
|
|
break;
|
|
|
|
case A_ABS_IND_X_INDI: // absolute indexed X indirect
|
|
set_op_displ(insn, x, dt_word, rX);
|
|
set_flag(x, OP_DISPL_IND);
|
|
break;
|
|
|
|
case A_STACK: // stack
|
|
// nothing to do !
|
|
break;
|
|
|
|
case A_STACK_S: // stack short
|
|
set_op_imm(insn, x, dt_byte);
|
|
break;
|
|
|
|
case A_STACK_L: // stack long
|
|
set_op_imm(insn, x, dt_word);
|
|
break;
|
|
|
|
case A_REL: // relative
|
|
set_op_addr(insn, x, dt_byte);
|
|
x.addr = (signed char) x.addr + insn.ip + insn.size;
|
|
break;
|
|
|
|
case A_REL_LONG: // relative long
|
|
set_op_addr(insn, x, dt_word);
|
|
x.addr = (signed short) x.addr + insn.ip + insn.size;
|
|
set_flag(insn, INSN_LONG_FORMAT);
|
|
break;
|
|
|
|
case A_DIR_BIT_REL: // direct bit relative
|
|
set_op_mem(insn, next_x, dt_byte, curflags);
|
|
set_op_mem_dr_rel(insn, x);
|
|
set_op_bit(insn, x);
|
|
n += 2;
|
|
set_op_addr(insn, x, dt_byte);
|
|
x.addr = (signed char) x.addr + insn.ip + insn.size;
|
|
break;
|
|
|
|
case A_ABS_BIT_REL: // absolute bit relative
|
|
set_op_mem(insn, next_x, dt_word, curflags);
|
|
set_op_bit(insn, x);
|
|
n += 2;
|
|
set_op_addr(insn, x, dt_byte);
|
|
x.addr = (signed char) x.addr + insn.ip + insn.size;
|
|
break;
|
|
|
|
case A_STACK_PTR_REL: // stack pointer relative
|
|
set_op_displ(insn, x, dt_byte, rS);
|
|
break;
|
|
|
|
case A_STACK_PTR_REL_IIY: // stack pointer relative indirect indexed Y
|
|
set_op_displ(insn, x, dt_byte, rS);
|
|
set_flag(x, OP_DISPL_IND);
|
|
set_op_ind_y(next_x);
|
|
break;
|
|
|
|
case A_BT: // block transfer
|
|
set_op_imm(insn, x, dt_byte);
|
|
set_flag(x, OP_IMM_WITHOUT_SHARP);
|
|
n += 2;
|
|
set_op_imm(insn, x, dt_byte);
|
|
set_flag(x, OP_IMM_WITHOUT_SHARP);
|
|
break;
|
|
|
|
default:
|
|
INTERR(10027);
|
|
}
|
|
|
|
// now we can read immediate from operation code, and fill the first operand
|
|
// as it should be
|
|
if ( insn.itype == m7700_ldm )
|
|
{
|
|
n = 0;
|
|
set_op_imm(insn, x, dt_byte);
|
|
/*
|
|
if ( x.dtype == dt_word )
|
|
set_flag(insn, INSN_LONG_FORMAT);
|
|
*/
|
|
}
|
|
}
|
|
|
|
// get an opcode struct from code
|
|
const struct opcode *m7700_t::get_opcode(uint16 code)
|
|
{
|
|
// check in the 7700 opcodes
|
|
for ( int i = 0; i < qnumber(opcodes_7700); i++ )
|
|
{
|
|
if ( opcodes_7700[i].code != code )
|
|
continue;
|
|
return &opcodes_7700[i];
|
|
}
|
|
// check in the 7750 opcodes
|
|
if ( ptype == prc_m7750 )
|
|
{
|
|
for ( int i = 0; i < qnumber(opcodes_7750); i++ )
|
|
{
|
|
if ( opcodes_7750[i].code != code )
|
|
continue;
|
|
|
|
return &opcodes_7750[i];
|
|
}
|
|
}
|
|
// check in the 7700 opcodes with a FF00 mask if equals to 4200
|
|
if ( ((code & 0xFF00) >> 8) == 0x42 )
|
|
{
|
|
code &= 0x00FF;
|
|
with_acc_b = true;
|
|
return get_opcode(code & 0x00FF);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// analyze an instruction
|
|
int m7700_t::ana(insn_t *_insn)
|
|
{
|
|
insn_t &insn = *_insn;
|
|
|
|
const struct opcode *op;
|
|
uint16 code;
|
|
|
|
with_acc_b = false;
|
|
|
|
// read a byte
|
|
code = insn.get_next_byte();
|
|
|
|
// detect BRK insn
|
|
if ( code == 0x00 && get_byte(insn.ea + 1) == 0xEA )
|
|
{
|
|
insn.itype = m7700_brk;
|
|
insn.size += 1;
|
|
goto ana_finished;
|
|
}
|
|
|
|
// some instructions have their opcodes represented in 2 bytes,
|
|
// so we need to pick an another byte
|
|
if ( code == 0x42 || code == 0x89 )
|
|
code = (code << 8) + insn.get_next_byte();
|
|
|
|
// analyze and return corresponding opcode struct
|
|
op = get_opcode(code);
|
|
if ( op == NULL ) // no instruction was found..
|
|
return 0;
|
|
|
|
// fill the insn struct
|
|
insn.itype = op->insn;
|
|
fill_insn(insn, op->mode);
|
|
|
|
ana_finished:
|
|
return insn.size;
|
|
}
|