update
This commit is contained in:
989
idasdk75/module/m7700/ana.cpp
Normal file
989
idasdk75/module/m7700/ana.cpp
Normal file
@@ -0,0 +1,989 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
269
idasdk75/module/m7700/emu.cpp
Normal file
269
idasdk75/module/m7700/emu.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
|
||||
#include "m7700.hpp"
|
||||
|
||||
static void handle_imm(const insn_t &insn, const op_t &op, flags_t F)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(F, op.n) )
|
||||
return;
|
||||
bool in_hex = false;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case m7700_and:
|
||||
case m7700_ora:
|
||||
in_hex = true;
|
||||
break;
|
||||
}
|
||||
if ( in_hex )
|
||||
op_hex(insn.ea, op.n);
|
||||
}
|
||||
|
||||
// propagate m and x to the jump target
|
||||
static void propagate_bits_to(const insn_t &insn, ea_t ea)
|
||||
{
|
||||
if ( !is_loaded(ea) )
|
||||
return;
|
||||
split_sreg_range(ea, rfM, get_sreg(insn.ea, rfM), SR_auto);
|
||||
split_sreg_range(ea, rfX, get_sreg(insn.ea, rfX), SR_auto);
|
||||
}
|
||||
|
||||
void m7700_t::handle_operand(const insn_t &insn, const op_t &op)
|
||||
{
|
||||
flags_t F = get_flags(insn.ea);
|
||||
switch ( op.type )
|
||||
{
|
||||
// code address
|
||||
case o_near:
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, op.addr);
|
||||
cref_t mode;
|
||||
if ( insn.itype == m7700_jsr )
|
||||
{
|
||||
mode = is_insn_long_format(insn) ? fl_CF : fl_CN;
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = is_insn_long_format(insn) ? fl_JF : fl_JN;
|
||||
}
|
||||
insn.add_cref(ea, op.offb, mode);
|
||||
propagate_bits_to(insn, ea);
|
||||
}
|
||||
break;
|
||||
|
||||
// data address
|
||||
case o_mem:
|
||||
// create xref for instructions with :
|
||||
// - direct addressing mode if the value of DR is known
|
||||
// (and therefore, computed by the analyzer)
|
||||
// - other addressing modes
|
||||
if ( !is_addr_dr_rel(op) || get_sreg(insn.ea, rDR) != BADSEL )
|
||||
{
|
||||
enum dref_t mode = dr_U;
|
||||
if ( is_addr_ind(op) )
|
||||
mode = dr_R; /* NOT dr_O */
|
||||
else if ( is_addr_read(op) )
|
||||
mode = dr_R;
|
||||
else if ( is_addr_write(op) )
|
||||
mode = dr_W;
|
||||
|
||||
insn.add_dref(to_ea(insn.cs, op.addr), op.offb, mode);
|
||||
insn.create_op_data(op.addr, op);
|
||||
}
|
||||
break;
|
||||
|
||||
// immediate
|
||||
case o_imm:
|
||||
handle_imm(insn, op, F);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, dr_O, 0);
|
||||
break;
|
||||
|
||||
// bit
|
||||
case o_bit:
|
||||
handle_imm(insn, op, F);
|
||||
// create a comment if this immediate is represented in the .cfg file
|
||||
if ( op.n == 0 && (insn.Op2.type == o_near || insn.Op2.type == o_mem) )
|
||||
{
|
||||
const ioport_bit_t * port = find_bit(insn.Op2.addr, (size_t)op.value);
|
||||
|
||||
if ( port != NULL && !port->name.empty() && !has_cmt(F) )
|
||||
set_cmt(insn.ea, port->cmt.c_str(), false);
|
||||
}
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, dr_O, 0);
|
||||
break;
|
||||
|
||||
// displ
|
||||
case o_displ:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
{
|
||||
ea_t ea = insn.add_off_drefs(op, dr_O, OOF_ADDR);
|
||||
insn.create_op_data(ea, op);
|
||||
}
|
||||
break;
|
||||
|
||||
// reg - do nothing
|
||||
case o_reg:
|
||||
case o_void:
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10028);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// emulate an instruction
|
||||
int m7700_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
flow = ((feature & CF_STOP) == 0);
|
||||
|
||||
if ( insn.Op1.type != o_void ) handle_operand(insn, insn.Op1);
|
||||
if ( insn.Op2.type != o_void ) handle_operand(insn, insn.Op2);
|
||||
if ( insn.Op3.type != o_void ) handle_operand(insn, insn.Op3);
|
||||
|
||||
// we don't use CF_JUMP
|
||||
//if ( feature & CF_JUMP )
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case m7700_jmp:
|
||||
case m7700_jsr:
|
||||
if ( insn.Op1.type != o_void && is_addr_ind(insn.Op1) )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( flow )
|
||||
{
|
||||
// skip the next byte if the current insn is brk
|
||||
if ( insn.itype == m7700_brk )
|
||||
{
|
||||
add_cref(insn.ea, insn.ea + insn.size + 1, fl_JN);
|
||||
create_byte(insn.ea + insn.size, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
}
|
||||
}
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
// clear m flag
|
||||
case m7700_clm:
|
||||
split_sreg_range(insn.ea + insn.size, rfM, 0, SR_auto);
|
||||
break;
|
||||
// set m flag
|
||||
case m7700_sem:
|
||||
split_sreg_range(insn.ea + insn.size, rfM, 1, SR_auto);
|
||||
break;
|
||||
|
||||
// clear processor status
|
||||
case m7700_clp:
|
||||
// clear m flag
|
||||
if ( ((insn.Op1.value & 0x20) >> 5) == 1 )
|
||||
split_sreg_range(insn.ea + insn.size, rfM, 0, SR_auto);
|
||||
// clear x flag
|
||||
if ( ((insn.Op1.value & 0x10) >> 4) == 1 )
|
||||
split_sreg_range(insn.ea + insn.size, rfX, 0, SR_auto);
|
||||
break;
|
||||
|
||||
// set processor status
|
||||
case m7700_sep:
|
||||
// set m flag
|
||||
if ( ((insn.Op1.value & 0x20) >> 5) == 1 )
|
||||
split_sreg_range(insn.ea + insn.size, rfM, 1, SR_auto);
|
||||
// set x flag
|
||||
if ( ((insn.Op1.value & 0x10) >> 4) == 1 )
|
||||
split_sreg_range(insn.ea + insn.size, rfX, 1, SR_auto);
|
||||
break;
|
||||
|
||||
// pull processor status from stack
|
||||
case m7700_plp:
|
||||
split_sreg_range(insn.ea + insn.size, rfM, BADSEL, SR_auto);
|
||||
split_sreg_range(insn.ea + insn.size, rfX, BADSEL, SR_auto);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool is_func_far(ea_t ea)
|
||||
{
|
||||
bool func_far = false;
|
||||
insn_t insn;
|
||||
while ( true )
|
||||
{
|
||||
if ( decode_insn(&insn, ea) == 0 )
|
||||
break;
|
||||
ea += insn.size;
|
||||
|
||||
// rts = jsr
|
||||
if ( insn.itype == m7700_rts )
|
||||
break;
|
||||
|
||||
// rtl = jsrl
|
||||
if ( insn.itype == m7700_rtl )
|
||||
{
|
||||
func_far = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return func_far;
|
||||
}
|
||||
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
// PC (2 bytes long) is always pushed
|
||||
int context_size = 2;
|
||||
|
||||
// detect phd
|
||||
ea_t ea = pfn->start_ea;
|
||||
|
||||
// if far, 1 byte more on the stack (PG register)
|
||||
if ( is_func_far(ea) )
|
||||
{
|
||||
pfn->flags |= FUNC_FAR;
|
||||
context_size++;
|
||||
}
|
||||
|
||||
insn_t insn;
|
||||
decode_insn(&insn, ea);
|
||||
ea += insn.size;
|
||||
if ( insn.itype != m7700_phd )
|
||||
return 0;
|
||||
|
||||
// DR (2 bytes long) is pushed
|
||||
context_size += 2;
|
||||
|
||||
int auto_size = 0;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
ea += insn.size;
|
||||
|
||||
// A (2 bytes long) is pushed
|
||||
if ( insn.itype != m7700_pha )
|
||||
break;
|
||||
|
||||
auto_size += 2;
|
||||
}
|
||||
|
||||
// gen comment
|
||||
char b[MAXSTR];
|
||||
qsnprintf(b, sizeof b, "Auto Size (%d) - Context Size (%d)", auto_size, context_size);
|
||||
set_func_cmt(pfn, b, false);
|
||||
|
||||
return add_frame(pfn, auto_size, 0, 0);
|
||||
}
|
||||
|
||||
//lint -e{818}
|
||||
int idaapi idp_get_frame_retsize(const func_t *pfn)
|
||||
{
|
||||
return is_func_far(pfn->start_ea) ? 2 : 3;
|
||||
}
|
||||
122
idasdk75/module/m7700/ins.cpp
Normal file
122
idasdk75/module/m7700/ins.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
#include "m7700.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
// 7700 :
|
||||
|
||||
{ "", 0 }, // null instruction
|
||||
{ "adc", CF_USE1 }, // addition with carry
|
||||
{ "and", CF_USE1 }, // logical AND
|
||||
{ "asl", CF_USE1|CF_CHG1 }, // arithmetic shift left
|
||||
{ "bbc", CF_USE1|CF_USE2|CF_USE3 }, // branch on bit clear
|
||||
{ "bbs", CF_USE1|CF_USE2|CF_USE3 }, // branch on bit set
|
||||
{ "bcc", CF_USE1 }, // branch on carry clear
|
||||
{ "bcs", CF_USE1 }, // branch on carry set
|
||||
{ "beq", CF_USE1 }, // branch on equal
|
||||
{ "bmi", CF_USE1 }, // branch on result minus
|
||||
{ "bne", CF_USE1 }, // branch on not equal
|
||||
{ "bpl", CF_USE1 }, // branch on result plus
|
||||
{ "bra", CF_USE1 }, // branch always
|
||||
{ "brk", 0 }, // force break
|
||||
{ "bvc", CF_USE1 }, // branch on overflow clear
|
||||
{ "bvs", CF_USE1 }, // branch on overflow set
|
||||
{ "clb", CF_USE1|CF_USE2|CF_CHG2 }, // clear bit
|
||||
{ "clc", 0 }, // clear carry flag
|
||||
{ "cli", 0 }, // clear interrupt disable status
|
||||
{ "clm", 0 }, // clear m flag
|
||||
{ "clp", CF_USE1 }, // clear processor status
|
||||
{ "clv", 0 }, // clear overflow flag
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // compare
|
||||
{ "cpx", CF_USE1 }, // compare memory and index register X
|
||||
{ "cpy", CF_USE1 }, // compare memory and index register Y
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // decrement by one
|
||||
{ "dex", 0 }, // decrement index register X by one
|
||||
{ "dey", 0 }, // decrement index register Y by one
|
||||
{ "div", CF_USE1 }, // divide
|
||||
{ "eor", CF_USE1|CF_CHG1|CF_USE2 }, // exclusive OR memory with accumulator
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // increment by one
|
||||
{ "inx", 0 }, // increment index register X by one
|
||||
{ "iny", 0 }, // increment index register Y by one
|
||||
{ "jmp", CF_USE1 }, // jump
|
||||
{ "jsr", CF_USE1|CF_CALL }, // jump to subroutine
|
||||
{ "lda", CF_USE1|CF_CHG1|CF_USE2 }, // load accumulator from memory
|
||||
{ "ldm", CF_USE1|CF_CHG2 }, // load immediate to memory
|
||||
{ "ldt", CF_USE1 }, // load immediate to data bank register
|
||||
{ "ldx", CF_USE1 }, // load index register X from memory
|
||||
{ "ldy", CF_USE1 }, // load index register Y from memory
|
||||
{ "lsr", CF_USE1|CF_CHG1 }, // logical shift right
|
||||
{ "mpy", CF_USE1 }, // multiply
|
||||
{ "mvn", CF_USE2|CF_CHG1 }, // move negative
|
||||
{ "mvp", CF_USE2|CF_CHG1 }, // move positive
|
||||
{ "nop", 0 }, // no operation
|
||||
{ "ora", CF_USE1|CF_CHG1|CF_USE2 }, // OR memory with accumulator
|
||||
{ "pea", CF_USE1 }, // push effective address
|
||||
{ "pei", CF_USE1 }, // push effective indirect address
|
||||
{ "per", CF_USE1 }, // push effective program counter relative address
|
||||
{ "pha", 0 }, // push accumulator A on stack
|
||||
{ "phb", 0 }, // push accumulator B on stack
|
||||
{ "phd", 0 }, // push direct page register on stack
|
||||
{ "phg", 0 }, // push program bank register on stack
|
||||
{ "php", 0 }, // push processor status on stack
|
||||
{ "pht", 0 }, // push data bank register on stack
|
||||
{ "phx", 0 }, // push index register X on stack
|
||||
{ "phy", 0 }, // push index register Y on stack
|
||||
{ "pla", 0 }, // pull accumulator A from stack
|
||||
{ "plb", 0 }, // pull accumulator B from stack
|
||||
{ "pld", 0 }, // pull direct page register from stack
|
||||
{ "plp", 0 }, // pull processor status from stack
|
||||
{ "plt", 0 }, // pull data bank register from stack
|
||||
{ "plx", 0 }, // pull index register X from stack
|
||||
{ "ply", 0 }, // pull index register Y from stack
|
||||
{ "psh", CF_USE1 }, // push
|
||||
{ "pul", CF_USE1 }, // pull
|
||||
{ "rla", CF_USE1 }, // rotate left accumulator A
|
||||
{ "rol", CF_USE2|CF_CHG1 }, // rotate one bit left
|
||||
{ "ror", CF_USE2|CF_CHG1 }, // rotate one bit right
|
||||
{ "rti", CF_STOP }, // return from interrupt
|
||||
{ "rtl", CF_STOP }, // return from subroutine long
|
||||
{ "rts", CF_STOP }, // return from subroutine
|
||||
{ "sbc", CF_USE1|CF_CHG1|CF_USE2 }, // subtract with carry
|
||||
{ "seb", CF_USE1|CF_USE2|CF_CHG2 }, // set bit
|
||||
{ "sec", 0 }, // set carry flag
|
||||
{ "sei", 0 }, // set interrupt disable status
|
||||
{ "sem", 0 }, // set m flag
|
||||
{ "sep", CF_USE1 }, // set processor status
|
||||
{ "sta", CF_USE1|CF_CHG2 }, // store accumulator in memory
|
||||
{ "stp", 0 }, // stop
|
||||
{ "stx", CF_CHG1 }, // store index register X in memory
|
||||
{ "sty", CF_CHG1 }, // store index register Y in memory
|
||||
{ "tad", 0 }, // transfer accumulator A to direct page register
|
||||
{ "tas", 0 }, // transfer accumulator A to stack pointer
|
||||
{ "tax", 0 }, // transfer accumulator A to index register X
|
||||
{ "tay", 0 }, // transfer accumulator A to index register Y
|
||||
{ "tbd", 0 }, // transfer accumulator B to direct page register
|
||||
{ "tbs", 0 }, // transfer accumulator B to stack pointer
|
||||
{ "tbx", 0 }, // transfer accumulator B to index register X
|
||||
{ "tby", 0 }, // transfer accumulator B to index register Y
|
||||
{ "tda", 0 }, // transfer direct page register to accumulator A
|
||||
{ "tdb", 0 }, // transfer direct page register to accumulator B
|
||||
{ "tsa", 0 }, // transfer stack pointer to accumulator A
|
||||
{ "tsb", 0 }, // transfer stack pointer to accumulator B
|
||||
{ "tsx", 0 }, // transfer stack pointer to index register X
|
||||
{ "txa", 0 }, // transfer index register X to accumulator A
|
||||
{ "txb", 0 }, // transfer index register X to accumulator B
|
||||
{ "txs", 0 }, // transfer index register X to stack pointer
|
||||
{ "txy", 0 }, // transfer index register X to Y
|
||||
{ "tya", 0 }, // transfer index register Y to accumulator A
|
||||
{ "tyb", 0 }, // transfer index register Y to accumulator B
|
||||
{ "tyx", 0 }, // transfer index register Y to X
|
||||
{ "wit", 0 }, // wait
|
||||
{ "xab", 0 }, // exchange accumulator A and B
|
||||
|
||||
// 7750 :
|
||||
|
||||
{ "asr", CF_USE1|CF_CHG1 }, // arithmetic shift right
|
||||
{ "divs", CF_USE1 }, // divide with sign
|
||||
{ "exts", CF_USE1|CF_CHG1 }, // extention with sign
|
||||
{ "extz", CF_USE1|CF_CHG1 }, // extention zero
|
||||
{ "mpys", CF_USE1 } // multiply with sign
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == m7700_last);
|
||||
128
idasdk75/module/m7700/ins.hpp
Normal file
128
idasdk75/module/m7700/ins.hpp
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
#ifndef __INS_HPP
|
||||
#define __INS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
// 7700 :
|
||||
|
||||
m7700_null = 0, // null instruction
|
||||
m7700_adc, // addition with carry
|
||||
m7700_and, // logical AND
|
||||
m7700_asl, // arithmetic shift left
|
||||
m7700_bbc, // branch on bit clear
|
||||
m7700_bbs, // branch on bit set
|
||||
m7700_bcc, // branch on carry clear
|
||||
m7700_bcs, // branch on carry set
|
||||
m7700_beq, // branch on equal
|
||||
m7700_bmi, // branch on result minus
|
||||
m7700_bne, // branch on not equal
|
||||
m7700_bpl, // branch on result plus
|
||||
m7700_bra, // branch always
|
||||
m7700_brk, // force break
|
||||
m7700_bvc, // branch on overflow clear
|
||||
m7700_bvs, // branch on overflow set
|
||||
m7700_clb, // clear bit
|
||||
m7700_clc, // clear carry flag
|
||||
m7700_cli, // clear interrupt disable status
|
||||
m7700_clm, // clear m flag
|
||||
m7700_clp, // clear processor status
|
||||
m7700_clv, // clear overflow flag
|
||||
m7700_cmp, // compare
|
||||
m7700_cpx, // compare memory and index register X
|
||||
m7700_cpy, // compare memory and index register Y
|
||||
m7700_dec, // decrement by one
|
||||
m7700_dex, // decrement index register X by one
|
||||
m7700_dey, // decrement index register Y by one
|
||||
m7700_div, // divide
|
||||
m7700_eor, // exclusive OR memory with accumulator
|
||||
m7700_inc, // increment by one
|
||||
m7700_inx, // increment index register X by one
|
||||
m7700_iny, // increment index register Y by one
|
||||
m7700_jmp, // jump
|
||||
m7700_jsr, // jump to subroutine
|
||||
m7700_lda, // load accumulator from memory
|
||||
m7700_ldm, // load immediate to memory
|
||||
m7700_ldt, // load immediate to data bank register
|
||||
m7700_ldx, // load index register X from memory
|
||||
m7700_ldy, // load index register Y from memory
|
||||
m7700_lsr, // logical shift right
|
||||
m7700_mpy, // multiply
|
||||
m7700_mvn, // move negative
|
||||
m7700_mvp, // move positive
|
||||
m7700_nop, // no operation
|
||||
m7700_ora, // OR memory with accumulator
|
||||
m7700_pea, // push effective address
|
||||
m7700_pei, // push effective indirect address
|
||||
m7700_per, // push effective program counter relative address
|
||||
m7700_pha, // push accumulator A on stack
|
||||
m7700_phb, // push accumulator B on stack
|
||||
m7700_phd, // push direct page register on stack
|
||||
m7700_phg, // push program bank register on stack
|
||||
m7700_php, // push processor status on stack
|
||||
m7700_pht, // push data bank register on stack
|
||||
m7700_phx, // push index register X on stack
|
||||
m7700_phy, // push index register Y on stack
|
||||
m7700_pla, // pull accumulator A from stack
|
||||
m7700_plb, // pull accumulator B from stack
|
||||
m7700_pld, // pull direct page register from stack
|
||||
m7700_plp, // pull processor status from stack
|
||||
m7700_plt, // pull data bank register from stack
|
||||
m7700_plx, // pull index register X from stack
|
||||
m7700_ply, // pull index register Y from stack
|
||||
m7700_psh, // push
|
||||
m7700_pul, // pull
|
||||
m7700_rla, // rotate left accumulator A
|
||||
m7700_rol, // rotate one bit left
|
||||
m7700_ror, // rotate one bit right
|
||||
m7700_rti, // return from interrupt
|
||||
m7700_rtl, // return from subroutine long
|
||||
m7700_rts, // return from subroutine
|
||||
m7700_sbc, // subtract with carry
|
||||
m7700_seb, // set bit
|
||||
m7700_sec, // set carry flag
|
||||
m7700_sei, // set interrupt disable status
|
||||
m7700_sem, // set m flag
|
||||
m7700_sep, // set processor status
|
||||
m7700_sta, // store accumulator in memory
|
||||
m7700_stp, // stop
|
||||
m7700_stx, // store index register X in memory
|
||||
m7700_sty, // store index register Y in memory
|
||||
m7700_tad, // transfer accumulator A to direct page register
|
||||
m7700_tas, // transfer accumulator A to stack pointer
|
||||
m7700_tax, // transfer accumulator A to index register X
|
||||
m7700_tay, // transfer accumulator A to index register Y
|
||||
m7700_tbd, // transfer accumulator B to direct page register
|
||||
m7700_tbs, // transfer accumulator B to stack pointer
|
||||
m7700_tbx, // transfer accumulator B to index register X
|
||||
m7700_tby, // transfer accumulator B to index register Y
|
||||
m7700_tda, // transfer direct page register to accumulator A
|
||||
m7700_tdb, // transfer direct page register to accumulator B
|
||||
m7700_tsa, // transfer stack pointer to accumulator A
|
||||
m7700_tsb, // transfer stack pointer to accumulator B
|
||||
m7700_tsx, // transfer stack pointer to index register X
|
||||
m7700_txa, // transfer index register X to accumulator A
|
||||
m7700_txb, // transfer index register X to accumulator B
|
||||
m7700_txs, // transfer index register X to stack pointer
|
||||
m7700_txy, // transfer index register X to Y
|
||||
m7700_tya, // transfer index register Y to accumulator A
|
||||
m7700_tyb, // transfer index register Y to accumulator B
|
||||
m7700_tyx, // transfer index register Y to X
|
||||
m7700_wit, // wait
|
||||
m7700_xab, // exchange accumulator A and B
|
||||
|
||||
// 7750 :
|
||||
|
||||
m7750_asr, // arithmetic shift right
|
||||
m7750_divs, // divide with sign
|
||||
m7750_exts, // extention with sign
|
||||
m7750_extz, // extention zero
|
||||
m7750_mpys, // multiply with sign
|
||||
|
||||
m7700_last
|
||||
};
|
||||
|
||||
#endif /* __INS_HPP */
|
||||
|
||||
6357
idasdk75/module/m7700/m7700.cfg
Normal file
6357
idasdk75/module/m7700/m7700.cfg
Normal file
File diff suppressed because it is too large
Load Diff
160
idasdk75/module/m7700/m7700.hpp
Normal file
160
idasdk75/module/m7700/m7700.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
|
||||
#ifndef __M7700_HPP
|
||||
#define __M7700_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <frame.hpp>
|
||||
#include <segregs.hpp> // for get_sreg()
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
// flags for insn.op[n].specflag1
|
||||
#define OP_IMM_WITHOUT_SHARP 0x0001 // don't display the # for this immediate
|
||||
#define OP_ADDR_IND 0x0002 // this address should be printed between '(' ')'
|
||||
#define OP_DISPL_IND 0x0004 // this displacement should be printed between '(' ')'
|
||||
#define OP_DISPL_IND_P1 0x0008 // only the first parameter of the displacement
|
||||
// should be printed between '(' ')'
|
||||
#define OP_ADDR_R 0x0010 // addr operand used in 'read' context
|
||||
#define OP_ADDR_W 0x0020 // addr operand used in 'write' context
|
||||
#define OP_ADDR_DR_REL 0x0040 // addr operand is relative to DR (direct page register)
|
||||
|
||||
// specflag1 helpers
|
||||
inline bool is_imm_without_sharp(const op_t &op) { return (op.specflag1 & OP_IMM_WITHOUT_SHARP) != 0; }
|
||||
inline bool is_addr_ind(const op_t &op) { return (op.specflag1 & OP_ADDR_IND) != 0; }
|
||||
inline bool is_addr_read(const op_t &op) { return (op.specflag1 & OP_ADDR_R) != 0; }
|
||||
inline bool is_addr_write(const op_t &op) { return (op.specflag1 & OP_ADDR_W) != 0; }
|
||||
inline bool is_displ_ind(const op_t &op) { return (op.specflag1 & OP_DISPL_IND) != 0; }
|
||||
inline bool is_displ_ind_p1(const op_t &op) { return (op.specflag1 & OP_DISPL_IND_P1) != 0; }
|
||||
inline bool is_addr_dr_rel(const op_t &op) { return (op.specflag1 & OP_ADDR_DR_REL) != 0; }
|
||||
|
||||
// flags for insn.auxpref
|
||||
#define INSN_LONG_FORMAT 0x0001 // we need to write an additionnal 'l'
|
||||
// after the insn mnemonic.
|
||||
// auxpref helpers
|
||||
inline bool is_insn_long_format(const insn_t &insn) { return (insn.auxpref & INSN_LONG_FORMAT) != 0; }
|
||||
|
||||
// flags for ash.uflag
|
||||
#define UAS_SEGM 0x0001 // segments are named "segment XXX"
|
||||
#define UAS_INDX_NOSPACE 0x0002 // no spaces between operands in indirect X addressing mode
|
||||
#define UAS_END_WITHOUT_LABEL 0x0004 // do not print the entry point label after end directive
|
||||
#define UAS_DEVICE_DIR 0x0008 // supports device declaration directives
|
||||
#define UAS_BITMASK_LIST 0x0010 // supports list instead of bitmask for some special insn
|
||||
// like clp, psh...
|
||||
|
||||
// 7700 registers
|
||||
enum m7700_registers
|
||||
{
|
||||
rA, // accumulator A
|
||||
rB, // accumulator B
|
||||
rX, // index X
|
||||
rY, // index Y
|
||||
rS, // stack pointer
|
||||
rPC, // program counter
|
||||
rPG, // program bank register
|
||||
rDT, // data bank register
|
||||
rPS, // processor status register
|
||||
rDR, // direct page register
|
||||
rfM, // data length flag
|
||||
rfX, // index register length flag
|
||||
rVcs, rVds // these 2 registers are required by the IDA kernel
|
||||
};
|
||||
|
||||
// this module supports 2 processors: m7700, m7750
|
||||
enum processor_subtype_t
|
||||
{
|
||||
prc_m7700 = 0,
|
||||
prc_m7750 = 1
|
||||
};
|
||||
|
||||
// shortcut for a new operand type
|
||||
#define o_bit o_idpspec0
|
||||
|
||||
// exporting our routines
|
||||
void idaapi m7700_assumes(outctx_t &ctx);
|
||||
int idaapi ana(insn_t *_insn);
|
||||
bool idaapi create_func_frame(func_t *pfn);
|
||||
int idaapi idp_get_frame_retsize(const func_t *pfn);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 7700 addressing modes :
|
||||
enum m7700_addr_mode_t
|
||||
{
|
||||
A_IMPL, // implied
|
||||
A_IMM, // immediate
|
||||
A_ACC_A, // accumulator A
|
||||
A_ACC_B, // accumulator B
|
||||
A_DIR, // direct
|
||||
A_DIR_BIT, // direct bit
|
||||
A_DIR_IND_X, // direct indexed X
|
||||
A_DIR_IND_Y, // direct indexed Y
|
||||
A_DIR_INDI, // direct indirect
|
||||
A_DIR_IND_X_INDI, // direct indexed X indirect
|
||||
A_DIR_INDI_IND_Y, // direct indirect indexed Y
|
||||
A_DIR_INDI_LONG, // direct indirect long
|
||||
A_DIR_INDI_LONG_IND_Y, // direct indirect long indexed Y
|
||||
A_ABS, // absolute
|
||||
A_ABS_BIT, // absolute bit
|
||||
A_ABS_IND_X, // absolute indexed X
|
||||
A_ABS_IND_Y, // absolute indexed Y
|
||||
A_ABS_LONG, // absolute long
|
||||
A_ABS_LONG_IND_X, // absolute long indexed X
|
||||
A_ABS_INDI, // absolute indirect
|
||||
A_ABS_INDI_LONG, // absolute indirect long
|
||||
A_ABS_IND_X_INDI, // absolute indexed X indirect
|
||||
A_STACK, // stack
|
||||
A_STACK_S, // stack short
|
||||
A_STACK_L, // stack long
|
||||
A_REL, // relative
|
||||
A_REL_LONG, // relative long
|
||||
A_DIR_BIT_REL, // direct bit relative
|
||||
A_ABS_BIT_REL, // absolute bit relative
|
||||
A_STACK_PTR_REL, // stack pointer relative
|
||||
A_STACK_PTR_REL_IIY, // stack pointer relative indirect indexed Y
|
||||
A_BT // block transfer
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct opcode;
|
||||
struct m7700_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct m7700_t ±
|
||||
m7700_iohandler_t(m7700_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual void get_cfg_filename(char *buf, size_t bufsize) override;
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(idb_listener_t, struct m7700_t);
|
||||
|
||||
struct m7700_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
m7700_iohandler_t ioh = m7700_iohandler_t(*this, helper);
|
||||
idb_listener_t idb_listener = idb_listener_t(*this);
|
||||
// Current processor type
|
||||
processor_subtype_t ptype = prc_m7700;
|
||||
bool with_acc_b = false;
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
bool choose_device();
|
||||
const ioport_bit_t *find_bit(ea_t address, size_t bit);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/);
|
||||
|
||||
const struct opcode *get_opcode(uint16 code);
|
||||
void fill_insn(insn_t &insn, m7700_addr_mode_t mode);
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &op);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void m7700_header(outctx_t &ctx);
|
||||
void m7700_footer(outctx_t &ctx) const;
|
||||
void m7700_segstart(outctx_t &ctx, segment_t *Srange) const;
|
||||
void m7700_assumes(outctx_t &ctx) const;
|
||||
};
|
||||
#endif // __M7700_HPP
|
||||
46
idasdk75/module/m7700/makefile
Normal file
46
idasdk75/module/m7700/makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
PROC=m7700
|
||||
CONFIGS=m7700.cfg
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp ana.cpp ins.hpp m7700.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp emu.cpp ins.hpp m7700.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp ins.cpp ins.hpp m7700.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp ins.hpp m7700.hpp out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp ins.hpp m7700.hpp reg.cpp
|
||||
358
idasdk75/module/m7700/out.cpp
Normal file
358
idasdk75/module/m7700/out.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
|
||||
#include "m7700.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_m7700_t : public outctx_t
|
||||
{
|
||||
out_m7700_t(void) = delete; // not used
|
||||
m7700_t &pm() { return *static_cast<m7700_t *>(procmod); }
|
||||
public:
|
||||
void outreg(const int n) { out_register(ph.reg_names[n]); }
|
||||
void outaddr(const op_t &op, const bool replace_with_label = true);
|
||||
void outdispl(const op_t &op);
|
||||
bool bitmask2list(const op_t &op);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
};
|
||||
CASSERT(sizeof(out_m7700_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_m7700_t)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void out_m7700_t::outaddr(const op_t &op, const bool replace_with_label)
|
||||
{
|
||||
bool ind = is_addr_ind(op); // is operand indirect ?
|
||||
|
||||
if ( ind )
|
||||
out_symbol('(');
|
||||
|
||||
// if addressing mode is direct and the value of DR is unknown,
|
||||
// we have to print DR:x (where x is the "indexed" value)
|
||||
if ( is_addr_dr_rel(op) && get_sreg(insn.ea, rDR) == BADSEL )
|
||||
{
|
||||
outreg(rDR);
|
||||
out_symbol(':');
|
||||
out_value(op, OOF_ADDR | OOFS_NOSIGN);
|
||||
}
|
||||
// otherwise ...
|
||||
else if ( !replace_with_label
|
||||
|| !out_name_expr(op, to_ea(insn.cs, op.addr), op.addr) )
|
||||
{
|
||||
if ( replace_with_label )
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(op, OOF_ADDR | OOFS_NOSIGN /*| OOFW_16*/);
|
||||
if ( replace_with_label )
|
||||
out_tagoff(COLOR_ERROR);
|
||||
}
|
||||
|
||||
if ( ind )
|
||||
out_symbol(')');
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void out_m7700_t::outdispl(const op_t &op)
|
||||
{
|
||||
if ( is_displ_ind(op) )
|
||||
{
|
||||
out_symbol('(');
|
||||
outaddr(op, false);
|
||||
out_symbol(',');
|
||||
if ( !(ash.uflag & UAS_INDX_NOSPACE) )
|
||||
out_char(' ');
|
||||
outreg(op.reg);
|
||||
out_symbol(')');
|
||||
}
|
||||
else if ( is_displ_ind_p1(op) )
|
||||
{
|
||||
out_symbol('(');
|
||||
outaddr(op, false);
|
||||
out_symbol(')');
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
outreg(op.reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
outaddr(op, false);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
outreg(op.reg);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m7700_t::m7700_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
|
||||
if ( ash.uflag & UAS_DEVICE_DIR )
|
||||
{
|
||||
switch ( ptype )
|
||||
{
|
||||
case prc_m7700:
|
||||
ctx.gen_printf(DEFAULT_INDENT, ".MCU M37700");
|
||||
break;
|
||||
case prc_m7750:
|
||||
ctx.gen_printf(DEFAULT_INDENT, ".MCU M37750");
|
||||
break;
|
||||
default:
|
||||
INTERR(10029);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m7700_t::m7700_footer(outctx_t &ctx) const
|
||||
{
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
ctx.out_line(ash.end, COLOR_ASMDIR);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
ctx.out_char(' ');
|
||||
if ( ash.uflag & UAS_END_WITHOUT_LABEL )
|
||||
ctx.out_line("; ");
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool out_m7700_t::bitmask2list(const op_t &op)
|
||||
{
|
||||
static const char *const flags[] =
|
||||
{
|
||||
"N", "V", "m", "x", "D", "I", "Z", "C"
|
||||
};
|
||||
static const int regs[] =
|
||||
{
|
||||
rPS, rPG, rDT, rDR, rY, rX, rB, rA
|
||||
};
|
||||
|
||||
enum { bitFLAGS, bitREGS } t;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case m7700_psh:
|
||||
case m7700_pul:
|
||||
t = bitREGS;
|
||||
break;
|
||||
|
||||
case m7700_sep:
|
||||
case m7700_clp:
|
||||
t = bitFLAGS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( op.value == 0 )
|
||||
return false;
|
||||
|
||||
bool ok = false;
|
||||
for ( int tmp = (int)op.value, i = 1, j = 0; j < 8; i *= 2, j++ )
|
||||
{
|
||||
if ( ((tmp & i) >> j) != 1 )
|
||||
continue;
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
}
|
||||
|
||||
switch ( t )
|
||||
{
|
||||
case bitFLAGS:
|
||||
out_register(flags[7 - j]);
|
||||
break;
|
||||
case bitREGS:
|
||||
outreg(regs[7 - j]);
|
||||
break;
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool out_m7700_t::out_operand(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
// register
|
||||
case o_reg:
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
// immediate
|
||||
case o_imm:
|
||||
{
|
||||
bool list_ok = false;
|
||||
|
||||
if ( ash.uflag & UAS_BITMASK_LIST )
|
||||
list_ok = bitmask2list(x);
|
||||
|
||||
if ( !list_ok )
|
||||
{
|
||||
if ( !(is_imm_without_sharp(x)) )
|
||||
out_symbol('#');
|
||||
out_value(x, OOFW_IMM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// bit
|
||||
case o_bit:
|
||||
{
|
||||
const ioport_bit_t * port = NULL;
|
||||
|
||||
if ( x.n == 0 && (insn.Op2.type == o_near || insn.Op2.type == o_mem) )
|
||||
port = pm().find_bit(insn.Op2.addr, (size_t)x.value);
|
||||
|
||||
// this immediate is represented in the .cfg file
|
||||
if ( port != NULL && !port->name.empty() )
|
||||
{
|
||||
// output the port name instead of the numeric value
|
||||
out_line(port->name.c_str(), COLOR_IMPNAME);
|
||||
}
|
||||
// otherwise, simply print the value
|
||||
else
|
||||
{
|
||||
out_symbol('#');
|
||||
out_value(x, OOFW_IMM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// data / code memory address
|
||||
case o_near:
|
||||
case o_mem:
|
||||
outaddr(x);
|
||||
break;
|
||||
|
||||
// displ
|
||||
case o_displ:
|
||||
outdispl(x);
|
||||
break;
|
||||
|
||||
// ignore void operands
|
||||
case o_void:
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10030);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void out_m7700_t::out_proc_mnem(void)
|
||||
{
|
||||
const char *pfx = is_insn_long_format(insn) ? "l" : NULL;
|
||||
out_mnem(8, pfx);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void out_m7700_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
//
|
||||
// print insn operands
|
||||
//
|
||||
|
||||
out_one_operand(0); // output the first operand
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2);
|
||||
}
|
||||
|
||||
// output a character representation of the immediate values
|
||||
// embedded in the instruction as comments
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate segment header
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Srange) could be made const
|
||||
void m7700_t::m7700_segstart(outctx_t &ctx, segment_t *Srange) const
|
||||
{
|
||||
qstring sname;
|
||||
get_visible_segm_name(&sname, Srange);
|
||||
|
||||
if ( ash.uflag & UAS_SEGM )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("SEGMENT %s", SCOLOR_ASMDIR), sname.c_str());
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".SECTION %s", SCOLOR_ASMDIR), sname.c_str());
|
||||
|
||||
ea_t orgbase = ctx.insn_ea - get_segm_para(Srange);
|
||||
if ( orgbase != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), orgbase);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool show_assume_line(const sreg_range_t *sra, ea_t ea, int segreg)
|
||||
{
|
||||
bool show = false;
|
||||
if ( sra->start_ea == ea )
|
||||
{
|
||||
sreg_range_t prev_sra;
|
||||
if ( get_prev_sreg_range(&prev_sra, ea, segreg) )
|
||||
show = sra->val != prev_sra.val;
|
||||
}
|
||||
return show;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m7700_t::m7700_assumes(outctx_t &ctx) const
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
segment_t *seg = getseg(ea);
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || seg == NULL )
|
||||
return;
|
||||
bool seg_started = (ea == seg->start_ea);
|
||||
|
||||
sreg_range_t sra;
|
||||
if ( get_sreg_range(&sra, ea, rDR) )
|
||||
{
|
||||
if ( (seg_started && sra.val != BADSEL) || show_assume_line(&sra, ea, rDR) )
|
||||
ctx.gen_printf(-1, COLSTR("%s DPR = %a", SCOLOR_REGCMT), ash.cmnt, sra.val);
|
||||
}
|
||||
|
||||
if ( get_sreg_range(&sra, ea, rfM) )
|
||||
{
|
||||
if ( seg_started || show_assume_line(&sra, ea, rfM) )
|
||||
ctx.gen_printf(-1, COLSTR("%s m = %a", SCOLOR_REGCMT), ash.cmnt, sra.val);
|
||||
}
|
||||
|
||||
if ( get_sreg_range(&sra, ea, rfX) )
|
||||
{
|
||||
if ( seg_started || show_assume_line(&sra, ea, rfX) )
|
||||
ctx.gen_printf(-1, COLSTR("%s x = %a", SCOLOR_REGCMT), ash.cmnt, sra.val);
|
||||
}
|
||||
}
|
||||
498
idasdk75/module/m7700/reg.cpp
Normal file
498
idasdk75/module/m7700/reg.cpp
Normal file
@@ -0,0 +1,498 @@
|
||||
|
||||
#include "m7700.hpp"
|
||||
#include <segregs.hpp>
|
||||
|
||||
// 740 registers names
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"A", // accumulator A
|
||||
"B", // accumulator B
|
||||
"X", // index register X
|
||||
"Y", // index register Y
|
||||
"S", // stack pointer
|
||||
"PC", // program counter
|
||||
"PG", // program bank register
|
||||
"DT", // data bank register
|
||||
"PS", // processor status register
|
||||
"DPR", // direct page register
|
||||
"fM", // data length flag
|
||||
"fX", // index register length flag
|
||||
"cs", "ds" // these 2 registers are required by the IDA kernel
|
||||
};
|
||||
|
||||
static const char cfgname[] = "m7700.cfg";
|
||||
|
||||
void m7700_iohandler_t::get_cfg_filename(char *buf, size_t bufsize)
|
||||
{
|
||||
qstrncpy(buf, cfgname, bufsize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool m7700_t::choose_device()
|
||||
{
|
||||
bool ok = choose_ioport_device(&ioh.device, cfgname);
|
||||
if ( !ok )
|
||||
ioh.device = NONEPROC;
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const ioport_bit_t *m7700_t::find_bit(ea_t address, size_t bit)
|
||||
{
|
||||
return find_ioport_bit(ioh.ports, address, bit);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *m7700_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/)
|
||||
{
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
|
||||
if ( !choose_ioport_device(&ioh.device, cfgname)
|
||||
&& ioh.device == NONEPROC )
|
||||
{
|
||||
warning("No devices are defined in the configuration file %s", cfgname);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( helper.supstr(&ioh.device, -1) > 0 )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
}
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case idb_event::savebase:
|
||||
case idb_event::closebase:
|
||||
pm.helper.supset(-1, pm.ioh.device.c_str());
|
||||
break;
|
||||
|
||||
case idb_event::sgr_changed:
|
||||
{
|
||||
ea_t ea1 = va_arg(va, ea_t);
|
||||
ea_t ea2 = va_arg(va, ea_t);
|
||||
int reg = va_arg(va, int);
|
||||
sel_t v = va_arg(va, sel_t);
|
||||
sel_t ov = va_arg(va, sel_t);
|
||||
if ( (reg == rfM || reg == rfX) && v != ov )
|
||||
set_sreg_at_next_code(ea1, ea2, reg, ov);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const m7700_help_message =
|
||||
"AUTOHIDE REGISTRY\n"
|
||||
"You have loaded a file for the Mitsubishi 7700 family processor.\n\n"\
|
||||
"This processor can be used in two different 'length modes' : 8-bit and 16-bit.\n"\
|
||||
"IDA allows to specify the encoding mode for every single instruction.\n"\
|
||||
"For this, IDA uses two virtual segment registers : \n"\
|
||||
" - fM, used to specify the data length;\n"\
|
||||
" - fX, used to specify the index register length.\n\n"\
|
||||
"Switching their state from 0 to 1 will switch the disassembly from 16-bit to 8-bit.\n"\
|
||||
"You can change their value using the 'change segment register value' command\n"\
|
||||
"(the canonical hotkey is Alt-G).\n\n"\
|
||||
"Note : in the real design, those registers are represented as flags in the\n"\
|
||||
"processor status register.\n";
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// This old-style callback only returns the processor module object.
|
||||
static ssize_t idaapi notify(void *, int msgid, va_list)
|
||||
{
|
||||
if ( msgid == processor_t::ev_get_procmod )
|
||||
return size_t(new m7700_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t idaapi m7700_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
helper.create("$ m7700");
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
if ( choose_device() )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
else
|
||||
ioh.set_device_name(NONEPROC, IORESP_NONE);
|
||||
// Set the default segment register values :
|
||||
// -1 (badsel) for DR
|
||||
// 0 for fM and fX
|
||||
for ( segment_t *s=get_first_seg(); s != NULL; s=get_next_seg(s->start_ea) )
|
||||
{
|
||||
set_default_sreg_value(s, rDR, BADSEL);
|
||||
set_default_sreg_value(s, rfM, 0);
|
||||
set_default_sreg_value(s, rfX, 0);
|
||||
}
|
||||
info(m7700_help_message);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
ptype = processor_subtype_t(va_arg(va, int));
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
// restore ptype
|
||||
ptype = processor_subtype_t(ph.get_proc_index());
|
||||
//fall through
|
||||
case processor_t::ev_oldfile:
|
||||
ioh.restore_device(IORESP_ALL);
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_mnem(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m7700_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m7700_footer(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segstart:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
m7700_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_assumes:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m7700_assumes(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return emu(*insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_insn:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_insn(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_operand:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return out_opnd(*ctx, *op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
create_func_frame(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_get_frame_retsize:
|
||||
{
|
||||
int *frsize = va_arg(va, int *);
|
||||
const func_t *pfn = va_arg(va, const func_t *);
|
||||
*frsize = idp_get_frame_retsize(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static const asm_t as_asm =
|
||||
{
|
||||
AS_COLON
|
||||
|ASH_HEXF4 // hex $123 format
|
||||
|ASB_BINF3 // bin 0b010 format
|
||||
|ASO_OCTF5 // oct 123q format
|
||||
|AS_1TEXT, // 1 text per line, no bytes
|
||||
UAS_SEGM|UAS_INDX_NOSPACE,
|
||||
"Alfred Arnold's Macro Assembler",
|
||||
0,
|
||||
NULL, // no headers
|
||||
"ORG", // origin directive
|
||||
"END", // end directive
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
"DB", // ascii string directive
|
||||
"DB", // byte directive
|
||||
"DW", // word directive
|
||||
"DD", // dword (4 bytes)
|
||||
"DQ", // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
"DT", // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
"dfs %s", // uninited arrays
|
||||
"equ", // Equ
|
||||
NULL, // seg prefix
|
||||
"$", // current IP (instruction pointer) symbol in assembler
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"!", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
0, // flag2 ???
|
||||
NULL, // comment close string
|
||||
NULL, // low8 op
|
||||
NULL, // high8 op
|
||||
NULL, // low16 op
|
||||
NULL // high16 op
|
||||
};
|
||||
|
||||
//
|
||||
// Mitsubishi Macro Assembler for 7700 Family
|
||||
//
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// gets a function name
|
||||
//lint -e{818} could be declared const
|
||||
static bool mits_get_func_name(qstring *name, func_t *pfn)
|
||||
{
|
||||
ea_t ea = pfn->start_ea;
|
||||
if ( get_demangled_name(name, ea, inf_get_long_demnames(), DEMNAM_NAME) <= 0 )
|
||||
return false;
|
||||
|
||||
tag_addr(name, ea, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// prints function header
|
||||
static void idaapi mits_func_header(outctx_t &ctx, func_t *pfn)
|
||||
{
|
||||
ctx.gen_func_header(pfn);
|
||||
|
||||
qstring name;
|
||||
if ( mits_get_func_name(&name, pfn) )
|
||||
{
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".FUNC %s", SCOLOR_ASMDIR), name.begin());
|
||||
ctx.gen_printf(0, COLSTR("%s:", SCOLOR_ASMDIR), name.begin());
|
||||
ctx.ctxflags |= CTXF_LABEL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// prints function footer
|
||||
static void idaapi mits_func_footer(outctx_t &ctx, func_t *pfn)
|
||||
{
|
||||
qstring name;
|
||||
if ( mits_get_func_name(&name, pfn) )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".ENDFUNC %s", SCOLOR_ASMDIR), name.begin());
|
||||
}
|
||||
|
||||
static const asm_t mitsubishi_asm =
|
||||
{
|
||||
AS_COLON
|
||||
|ASH_HEXF0 // hex 123h format
|
||||
|ASB_BINF0 // bin 10100011b format
|
||||
|ASO_OCTF0 // oct 123o format
|
||||
|AS_1TEXT, // 1 text per line, no bytes
|
||||
UAS_END_WITHOUT_LABEL|UAS_DEVICE_DIR|UAS_BITMASK_LIST,
|
||||
"Mitsubishi Macro Assembler for 7700 Family",
|
||||
0,
|
||||
NULL, // no headers
|
||||
".ORG", // origin directive
|
||||
".END", // end directive
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".BYTE", // ascii string directive
|
||||
".BYTE", // byte directive
|
||||
".WORD", // word directive
|
||||
".DWORD", // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
".BLKB %s", // uninited arrays
|
||||
".EQU", // Equ
|
||||
NULL, // seg prefix
|
||||
"$", // current IP (instruction pointer) symbol in assembler
|
||||
mits_func_header, // func_header
|
||||
mits_func_footer, // func_footer
|
||||
".PUB", // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"!", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
"SIZEOF", // sizeof
|
||||
0, // flag2 ???
|
||||
NULL, // comment close string
|
||||
NULL, // low8 op
|
||||
NULL, // high8 op
|
||||
NULL, // low16 op
|
||||
NULL // high16 op
|
||||
};
|
||||
|
||||
// Supported assemblers
|
||||
static const asm_t *const asms[] = { &mitsubishi_asm, &as_asm, NULL };
|
||||
|
||||
// Short and long name for our module
|
||||
#define FAMILY "Mitsubishi 16-BIT 7700 family:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"m7700",
|
||||
"m7750",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Mitsubishi 16-BIT 7700 family",
|
||||
"Mitsubishi 16-BIT 7700 family (7750 series)",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const uchar retcode_1[] = { 0x40 }; // rti
|
||||
static const uchar retcode_2[] = { 0x60 }; // rts
|
||||
static const uchar retcode_3[] = { 0x6B }; // rtl
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ sizeof(retcode_3), retcode_3 },
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_M7700, // id
|
||||
// flag
|
||||
PR_RNAMESOK // can use register names for byte names
|
||||
| PR_BINMEM // The module creates RAM/ROM segments for binary files
|
||||
// (the kernel shouldn't ask the user about their sizes and addresses)
|
||||
| PR_SEGS // has segment registers?
|
||||
| PR_SGROTHER, // the segment registers don't contain
|
||||
// the segment selectors, something else
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // array of short processor names
|
||||
// the short names are used to specify the processor
|
||||
// with the -p command line switch)
|
||||
lnames, // array of long processor names
|
||||
// the long names are used to build the processor type
|
||||
// selection menu
|
||||
|
||||
asms, // array of target assemblers
|
||||
|
||||
notify, // the kernel event notification callback
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rDR, rVds,
|
||||
2, // size of a segment register
|
||||
rVcs, rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0, m7700_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, 7, 15, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
m7700_rts, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
Reference in New Issue
Block a user