This commit is contained in:
olari
2021-06-05 21:10:25 +03:00
parent 807cffd9de
commit e0e0f2be99
923 changed files with 911857 additions and 15 deletions

View 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;
}

View 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;
}

View 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);

View 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 */

File diff suppressed because it is too large Load Diff

View 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 &pm;
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

View 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

View 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);
}
}

View 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
};