update to ida 7.6, add builds
This commit is contained in:
581
idasdk76/module/65816/ana.cpp
Normal file
581
idasdk76/module/65816/ana.cpp
Normal file
@@ -0,0 +1,581 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
|
||||
#define DI(itype, len, addr_mode, cpus) { (itype), (addr_mode), (cpus) },
|
||||
#define DV(itype, len, addr_mode, cpus, flags) { (itype), (addr_mode), (cpus), (flags) },
|
||||
|
||||
static const struct opcode_info_t opinfos[] =
|
||||
{
|
||||
// 0x00
|
||||
DI(M65816_brk, 2, STACK_INT, M6X )
|
||||
DI(M65816_ora, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_cop, 2, STACK_INT, M65816 )
|
||||
DI(M65816_ora, 2, STACK_REL, M65816 )
|
||||
DI(M65816_tsb, 2, DP, M65C02 | M65816 )
|
||||
DI(M65816_ora, 2, DP, M6X)
|
||||
DI(M65816_asl, 2, DP, M6X)
|
||||
DI(M65816_ora, 2, DP_INDIR_LONG, M6X)
|
||||
|
||||
// 0x08
|
||||
DI(M65816_php, 1, STACK_PUSH, M6X )
|
||||
DV(M65816_ora, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_asl, 1, ACC, M6X )
|
||||
DI(M65816_phd, 1, STACK_PUSH, M65816 )
|
||||
DI(M65816_tsb, 3, ABS, M65C02 | M65816 )
|
||||
DI(M65816_ora, 3, ABS, M6X )
|
||||
DI(M65816_asl, 3, ABS, M6X )
|
||||
DI(M65816_ora, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x10
|
||||
DI(M65816_bpl, 2, PC_REL, M6X )
|
||||
DI(M65816_ora, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_ora, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_ora, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_trb, 2, DP, M65C02 | M65816 )
|
||||
DI(M65816_ora, 2, DP_IX, M6X )
|
||||
DI(M65816_asl, 2, DP_IX, M6X )
|
||||
DI(M65816_ora, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x18
|
||||
DI(M65816_clc, 1, IMPLIED, M6X )
|
||||
DI(M65816_ora, 3, ABS_IY, M6X )
|
||||
DI(M65816_inc, 1, ACC, M65C02 | M65816 )
|
||||
DI(M65816_tcs, 1, IMPLIED, M65816 )
|
||||
DI(M65816_trb, 3, ABS, M65C02 | M65816 )
|
||||
DI(M65816_ora, 3, ABS_IX, M6X )
|
||||
DI(M65816_asl, 3, ABS_IX, M6X )
|
||||
DI(M65816_ora, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0x20
|
||||
DI(M65816_jsr, 3, ABS, M6X )
|
||||
DI(M65816_and, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_jsl, 4, ABS_LONG, M65816 )
|
||||
DI(M65816_and, 2, STACK_REL, M65816 )
|
||||
DI(M65816_bit, 2, DP, M6X )
|
||||
DI(M65816_and, 2, DP, M6X )
|
||||
DI(M65816_rol, 2, DP, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x28
|
||||
DI(M65816_plp, 1, STACK_PULL, M6X )
|
||||
DV(M65816_and, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_rol, 1, ACC, M6X )
|
||||
DI(M65816_pld, 1, STACK_PULL, M65816 )
|
||||
DI(M65816_bit, 3, ABS, M6X )
|
||||
DI(M65816_and, 3, ABS, M6X )
|
||||
DI(M65816_rol, 3, ABS, M6X )
|
||||
DI(M65816_and, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x30
|
||||
DI(M65816_bmi, 2, PC_REL, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_and, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_bit, 2, DP_IX, M65C02 | M65816 )
|
||||
DI(M65816_and, 2, DP_IX, M6X )
|
||||
DI(M65816_rol, 2, DP_IX, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x38
|
||||
DI(M65816_sec, 1, IMPLIED, M6X )
|
||||
DI(M65816_and, 3, ABS_IY, M6X )
|
||||
DI(M65816_dec, 1, ACC, M65C02 | M65816 )
|
||||
DI(M65816_tsc, 1, IMPLIED, M65816 )
|
||||
DI(M65816_bit, 3, ABS_IX, M65C02 | M65816 )
|
||||
DI(M65816_and, 3, ABS_IX, M6X )
|
||||
DI(M65816_rol, 3, ABS_IX, M6X )
|
||||
DI(M65816_and, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0x40
|
||||
DI(M65816_rti, 1, STACK_RTI, M6X )
|
||||
DI(M65816_eor, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_wdm, 2, IMPLIED, M65816 )
|
||||
DI(M65816_eor, 2, STACK_REL, M65816 )
|
||||
DI(M65816_mvp, 3, BLK_MOV, M65816 )
|
||||
DI(M65816_eor, 2, DP, M6X )
|
||||
DI(M65816_lsr, 2, DP, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x48
|
||||
DI(M65816_pha, 1, STACK_PUSH, M6X )
|
||||
DV(M65816_eor, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_lsr, 1, ACC, M6X )
|
||||
DI(M65816_phk, 1, STACK_PUSH, M65816 )
|
||||
DI(M65816_jmp, 3, ABS, M6X )
|
||||
DI(M65816_eor, 3, ABS, M6X )
|
||||
DI(M65816_lsr, 3, ABS, M6X )
|
||||
DI(M65816_eor, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x50
|
||||
DI(M65816_bvc, 2, PC_REL, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_eor, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_mvn, 3, BLK_MOV, M65816 )
|
||||
DI(M65816_eor, 2, DP_IX, M6X )
|
||||
DI(M65816_lsr, 2, DP_IX, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x58
|
||||
DI(M65816_cli, 1, IMPLIED, M6X )
|
||||
DI(M65816_eor, 3, ABS_IY, M6X )
|
||||
DI(M65816_phy, 1, STACK_PUSH, M65C02 | M65816 )
|
||||
DI(M65816_tcd, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jml, 4, ABS_LONG, M65816 )
|
||||
DI(M65816_eor, 3, ABS_IX, M6X )
|
||||
DI(M65816_lsr, 3, ABS_IX, M6X )
|
||||
DI(M65816_eor, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0x60
|
||||
DI(M65816_rts, 1, STACK_RTS, M6X )
|
||||
DI(M65816_adc, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_per, 3, STACK_PC_REL, M65816 )
|
||||
DI(M65816_adc, 2, STACK_REL, M65816 )
|
||||
DI(M65816_stz, 2, DP, M65C02 | M65816 )
|
||||
DI(M65816_adc, 2, DP, M6X )
|
||||
DI(M65816_ror, 2, DP, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x68
|
||||
DI(M65816_pla, 1, STACK_PULL, M6X )
|
||||
DV(M65816_adc, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_ror, 1, ACC, M6X )
|
||||
DI(M65816_rtl, 1, STACK_RTL, M65816 )
|
||||
DI(M65816_jmp, 3, ABS_INDIR, M6X )
|
||||
DI(M65816_adc, 3, ABS, M6X )
|
||||
DI(M65816_ror, 3, ABS, M6X )
|
||||
DI(M65816_adc, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x70
|
||||
DI(M65816_bvs, 2, PC_REL, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_adc, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_stz, 2, DP_IX, M65C02 | M65816 )
|
||||
DI(M65816_adc, 2, DP_IX, M6X )
|
||||
DI(M65816_ror, 2, DP_IX, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x78
|
||||
DI(M65816_sei, 1, IMPLIED, M6X )
|
||||
DI(M65816_adc, 3, ABS_IY, M6X )
|
||||
DI(M65816_ply, 1, STACK_PULL, M65C02 | M65816 )
|
||||
DI(M65816_tdc, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jmp, 3, ABS_IX_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_adc, 3, ABS_IX, M6X )
|
||||
DI(M65816_ror, 3, ABS_IX, M6X )
|
||||
DI(M65816_adc, 4, ABS_LONG_IX, M6X )
|
||||
|
||||
// 0x80
|
||||
DI(M65816_bra, 2, PC_REL, M65C02 | M65816 )
|
||||
DI(M65816_sta, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_brl, 3, PC_REL_LONG, M65816 )
|
||||
DI(M65816_sta, 2, STACK_REL, M65816 )
|
||||
DI(M65816_sty, 2, DP, M6X )
|
||||
DI(M65816_sta, 2, DP, M6X )
|
||||
DI(M65816_stx, 2, DP, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x88
|
||||
DI(M65816_dey, 1, IMPLIED, M6X )
|
||||
DV(M65816_bit, 2, IMM, M65C02 | M65816, ACC16_INCBC)
|
||||
DI(M65816_txa, 1, IMPLIED, M6X )
|
||||
DI(M65816_phb, 1, STACK_PUSH, M65816 )
|
||||
DI(M65816_sty, 3, ABS, M6X )
|
||||
DI(M65816_sta, 3, ABS, M6X )
|
||||
DI(M65816_stx, 3, ABS, M6X )
|
||||
DI(M65816_sta, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x90
|
||||
DI(M65816_bcc, 2, PC_REL, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_sta, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_sty, 2, DP_IX, M6X )
|
||||
DI(M65816_sta, 2, DP_IX, M6X )
|
||||
DI(M65816_stx, 2, DP_IY, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x98
|
||||
DI(M65816_tya, 1, IMPLIED, M6X )
|
||||
DI(M65816_sta, 3, ABS_IY, M6X )
|
||||
DI(M65816_txs, 1, IMPLIED, M6X )
|
||||
DI(M65816_txy, 1, IMPLIED, M65816 )
|
||||
DI(M65816_stz, 3, ABS, M65C02 | M65816 )
|
||||
DI(M65816_sta, 3, ABS_IX, M6X )
|
||||
DI(M65816_stz, 3, ABS_IX, M65C02 | M65816 )
|
||||
DI(M65816_sta, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0xa0
|
||||
DV(M65816_ldy, 2, IMM, M6X, XY16_INCBC )
|
||||
DI(M65816_lda, 2, DP_IX_INDIR, M6X )
|
||||
DV(M65816_ldx, 2, IMM, M6X, XY16_INCBC )
|
||||
DI(M65816_lda, 2, STACK_REL, M65816 )
|
||||
DI(M65816_ldy, 2, DP, M6X )
|
||||
DI(M65816_lda, 2, DP, M6X )
|
||||
DI(M65816_ldx, 2, DP, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0xa8
|
||||
DI(M65816_tay, 1, IMPLIED, M6X )
|
||||
DV(M65816_lda, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_tax, 1, IMPLIED, M6X )
|
||||
DI(M65816_plb, 1, STACK_PULL, M65816 )
|
||||
DI(M65816_ldy, 3, ABS, M6X )
|
||||
DI(M65816_lda, 3, ABS, M6X )
|
||||
DI(M65816_ldx, 3, ABS, M6X )
|
||||
DI(M65816_lda, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0xb0
|
||||
DI(M65816_bcs, 2, PC_REL, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_lda, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_ldy, 2, DP_IX, M6X )
|
||||
DI(M65816_lda, 2, DP_IX, M6X )
|
||||
DI(M65816_ldx, 2, DP_IY, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0xb8
|
||||
DI(M65816_clv, 1, IMPLIED, M6X )
|
||||
DI(M65816_lda, 3, ABS_IY, M6X )
|
||||
DI(M65816_tsx, 1, IMPLIED, M6X )
|
||||
DI(M65816_tyx, 1, IMPLIED, M65816 )
|
||||
DI(M65816_ldy, 3, ABS_IX, M6X )
|
||||
DI(M65816_lda, 3, ABS_IX, M6X )
|
||||
DI(M65816_ldx, 3, ABS_IY, M6X )
|
||||
DI(M65816_lda, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0xc0
|
||||
DV(M65816_cpy, 2, IMM, M6X, XY16_INCBC)
|
||||
DI(M65816_cmp, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_rep, 2, IMM, M65816 )
|
||||
DI(M65816_cmp, 2, STACK_REL, M65816 )
|
||||
DI(M65816_cpy, 2, DP, M6X )
|
||||
DI(M65816_cmp, 2, DP, M6X )
|
||||
DI(M65816_dec, 2, DP, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0xc8
|
||||
DI(M65816_iny, 1, IMPLIED, M6X )
|
||||
DV(M65816_cmp, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_dex, 1, IMPLIED, M6X )
|
||||
DI(M65816_wai, 1, IMPLIED, M65816 )
|
||||
DI(M65816_cpy, 3, ABS, M6X )
|
||||
DI(M65816_cmp, 3, ABS, M6X )
|
||||
DI(M65816_dec, 3, ABS, M6X )
|
||||
DI(M65816_cmp, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0xd0
|
||||
DI(M65816_bne, 2, PC_REL, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_cmp, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_pei, 2, STACK_DP_INDIR, M65816 )
|
||||
DI(M65816_cmp, 2, DP_IX, M6X )
|
||||
DI(M65816_dec, 2, DP_IX, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0xd8
|
||||
DI(M65816_cld, 1, IMPLIED, M6X )
|
||||
DI(M65816_cmp, 3, ABS_IY, M6X )
|
||||
DI(M65816_phx, 1, STACK_PUSH, M65C02 | M65816 )
|
||||
DI(M65816_stp, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jmp, 3, ABS_INDIR_LONG, M65816 )
|
||||
DI(M65816_cmp, 3, ABS_IX, M6X )
|
||||
DI(M65816_dec, 3, ABS_IX, M6X )
|
||||
DI(M65816_cmp, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0xe0
|
||||
DV(M65816_cpx, 2, IMM, M6X, XY16_INCBC)
|
||||
DI(M65816_sbc, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_sep, 2, IMM, M65816 )
|
||||
DI(M65816_sbc, 2, STACK_REL, M65816 )
|
||||
DI(M65816_cpx, 2, DP, M6X )
|
||||
DI(M65816_sbc, 2, DP, M6X )
|
||||
DI(M65816_inc, 2, DP, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0xe8
|
||||
DI(M65816_inx, 1, IMPLIED, M6X )
|
||||
DV(M65816_sbc, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_nop, 1, IMPLIED, M6X )
|
||||
DI(M65816_xba, 1, IMPLIED, M65816 )
|
||||
DI(M65816_cpx, 3, ABS, M6X )
|
||||
DI(M65816_sbc, 3, ABS, M6X )
|
||||
DI(M65816_inc, 3, ABS, M6X )
|
||||
DI(M65816_sbc, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0xf0
|
||||
DI(M65816_beq, 2, PC_REL, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_sbc, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_pea, 3, STACK_ABS, M65816 )
|
||||
DI(M65816_sbc, 2, DP_IX, M6X )
|
||||
DI(M65816_inc, 2, DP_IX, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0xf8
|
||||
DI(M65816_sed, 1, IMPLIED, M6X )
|
||||
DI(M65816_sbc, 3, ABS_IY, M6X )
|
||||
DI(M65816_plx, 1, STACK_PULL, M65C02 | M65816 )
|
||||
DI(M65816_xce, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jsr, 3, ABS_IX_INDIR, M65816 )
|
||||
DI(M65816_sbc, 3, ABS_IX, M6X )
|
||||
DI(M65816_inc, 3, ABS_IX, M6X )
|
||||
DI(M65816_sbc, 4, ABS_LONG_IX, M65816 )
|
||||
};
|
||||
|
||||
#undef DI
|
||||
#undef DV
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
const struct opcode_info_t &get_opcode_info(uint8 opcode)
|
||||
{
|
||||
return opinfos[opcode];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline bool is_acc_16_sensitive_op(const struct opcode_info_t &opinfo)
|
||||
{
|
||||
return (opinfo.flags & ACC16_INCBC) == ACC16_INCBC;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline bool is_xy_16_sensitive_op(const struct opcode_info_t &opinfo)
|
||||
{
|
||||
return (opinfo.flags & XY16_INCBC) == XY16_INCBC;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
int idaapi ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
uint8 code = insn.get_next_byte();
|
||||
|
||||
// Fetch instruction info
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(code);
|
||||
insn.itype = opinfo.itype;
|
||||
|
||||
switch ( opinfo.addr )
|
||||
{
|
||||
case ACC:
|
||||
case STACK_PUSH:
|
||||
case STACK_PULL:
|
||||
case STACK_RTS:
|
||||
case STACK_RTI:
|
||||
case STACK_RTL:
|
||||
case IMPLIED:
|
||||
break;
|
||||
case STACK_INT:
|
||||
// COP & BRK; they are 1-byte, but have
|
||||
// another, signature byte.
|
||||
insn.get_next_byte();
|
||||
break;
|
||||
case STACK_ABS:
|
||||
// Always 16 bits
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case STACK_REL:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rS;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
break;
|
||||
case STACK_REL_INDIR_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rSiY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
break;
|
||||
case STACK_PC_REL:
|
||||
{
|
||||
int16 disp = insn.get_next_word();
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.addr = uint16(insn.ip + insn.size + disp);
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
break;
|
||||
case STACK_DP_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rSDi;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case IMM:
|
||||
insn.Op1.type = o_imm;
|
||||
if ( (is_acc_16_sensitive_op (opinfo) && is_acc_16_bits(insn))
|
||||
|| (is_xy_16_sensitive_op (opinfo) && is_xy_16_bits(insn)) ) //
|
||||
{
|
||||
insn.Op1.value = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
}
|
||||
break;
|
||||
case ABS:
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
if ( insn.itype == M65816_jsr || insn.itype == M65816_jmp )
|
||||
{
|
||||
insn.Op1.type = o_near;
|
||||
}
|
||||
else if ( insn.itype == M65816_stx || insn.itype == M65816_sty
|
||||
|| insn.itype == M65816_ldx || insn.itype == M65816_ldy
|
||||
|| insn.itype == M65816_cpx || insn.itype == M65816_cpy )
|
||||
{
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
break;
|
||||
case ABS_LONG:
|
||||
insn.Op1.type = o_mem_far;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.addr|= insn.get_next_byte() << 16;
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
if ( insn.itype == M65816_jsl || insn.itype == M65816_jml )
|
||||
insn.Op1.type = o_far;
|
||||
else
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case ABS_IX:
|
||||
case ABS_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = opinfo.addr == ABS_IX ? rAbsX : rAbsY;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
if ( insn.itype == M65816_ldx || insn.itype == M65816_ldy )
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
else
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case ABS_LONG_IX:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsLX;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.addr |= insn.get_next_byte() << 16;
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case ABS_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsi;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case ABS_INDIR_LONG:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsiL;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case ABS_IX_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsXi;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case DP:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rD;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
if ( insn.itype == M65816_stx || insn.itype == M65816_sty
|
||||
|| insn.itype == M65816_ldx || insn.itype == M65816_ldy
|
||||
|| insn.itype == M65816_cpx || insn.itype == M65816_cpy )
|
||||
{
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
break;
|
||||
case DP_IY:
|
||||
case DP_IX:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = opinfo.addr == DP_IX ? rDX : rDY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
if ( insn.itype == M65816_stx || insn.itype == M65816_sty
|
||||
|| insn.itype == M65816_ldx || insn.itype == M65816_ldy )
|
||||
{
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
break;
|
||||
case DP_IX_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = riDX;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDi;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR_LONG:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDiL;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDiY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR_LONG_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDiLY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case PC_REL:
|
||||
insn.Op1.type = o_near;
|
||||
{
|
||||
char x = insn.get_next_byte();
|
||||
insn.Op1.addr = uint16(insn.ip + insn.size + x);
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
break;
|
||||
case PC_REL_LONG:
|
||||
insn.Op1.type = o_far;
|
||||
{
|
||||
int16 x = insn.get_next_word();
|
||||
insn.Op1.addr = uint16(insn.ip + insn.size + x) | (insn.ea & 0xff0000);
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
break;
|
||||
case BLK_MOV:
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op2.type = o_imm;
|
||||
insn.Op2.value = insn.get_next_byte();
|
||||
insn.Op2.dtype = dt_byte;
|
||||
break;
|
||||
default:
|
||||
warning("ana: bad code 0x%x, @: 0x%a (IP=%a)", code, insn.ea, insn.ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return insn.size;
|
||||
}
|
||||
323
idasdk76/module/65816/bt.cpp
Normal file
323
idasdk76/module/65816/bt.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "bt.hpp"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
//lint -estring(823,BTWALK_PREAMBLE) definition of macro ends in semi-colon
|
||||
#define BTWALK_PREAMBLE(walker_ea, opcode_var, itype_var) \
|
||||
(walker_ea) = prev_head((walker_ea), (walker_ea) - 4); \
|
||||
if ( (walker_ea) == BADADDR ) \
|
||||
break; \
|
||||
flags_t F = get_flags(walker_ea); \
|
||||
if ( is_func(F) || !is_code(F) ) \
|
||||
break; \
|
||||
opcode_var = get_byte(walker_ea); \
|
||||
itype_var = get_opcode_info(opcode_var).itype;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FIXME: The following are lacks in implementation:
|
||||
// * If the value we asked for is 16bits, and
|
||||
// at some point we are reduced to an 8-bits one, we should
|
||||
// fail.
|
||||
int32 backtrack_value(ea_t from_ea, uint8 size, btsource_t source)
|
||||
{
|
||||
// Note: At some point, we were using:
|
||||
// ---
|
||||
// const func_t * const func = get_fchunk(from_ea);
|
||||
// if (func == NULL)
|
||||
// return -1;
|
||||
// ea_t chunk_start_ea = func->start_ea;
|
||||
// ---
|
||||
// in order to determine where we had to stop backtracking
|
||||
// values.
|
||||
// Unfortunately, that doesn't work because, during the initial
|
||||
// analysis, where functions & chunks aren't properly formed yet,
|
||||
// the 'func' ptr would always be NULL. Therefore, we wouldn't
|
||||
// be capable of backtracking a value properly; which also
|
||||
// means that wrong values were propagated to other
|
||||
// functions.
|
||||
//
|
||||
// A particularily interesting example is this: In a certain
|
||||
// rom, we had the following seq. of instructions:
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// .C0:0019 SEI
|
||||
// .C0:001A CLC
|
||||
// .C0:001B XCE
|
||||
// .C0:001C SEP #$20 ; ' ' ; .a8, .i16
|
||||
// .C0:001E REP #$10 ; .a8, .i16
|
||||
// .C0:0020 LDX #$15FF
|
||||
// .C0:0023 TXS
|
||||
// .C0:0024 LDX #0
|
||||
// .C0:0027 PHX
|
||||
// .C0:0028 PLD
|
||||
// .C0:0029 TDC
|
||||
// .C0:002A PHA
|
||||
// .C0:002B PLB
|
||||
// .C0:002C LDA #1
|
||||
// .C0:002E STA CYCLE_SPEED_DESIGNATION ; 0000000a a: 0 = 2.68 MHz, 1 = 3.58 MHz
|
||||
// .C0:0031 STZ REGULAR_DMA_CHANNEL_ENABLE ; abcdefgh a = Channel 7...h = Channel 0: 1 = Enable 0 = Disable
|
||||
// .C0:0034 STZ H_DMA_CHANNEL_ENABLE ; abcdefgh a = Channel 7 .. h = Channel 0: 1 = Enable 0 = Disable
|
||||
// .C0:0037 LDA #$8F ; ''
|
||||
// .C0:0039 STA SCREEN_DISPLAY_REGISTER ; a000bbbb a: 0=screen on 1=screen off, b = brightness
|
||||
// .C0:003C STZ NMI_V_H_COUNT_AND_JOYPAD_ENABLE ; a0bc000d a = NMI b = V-Count c = H-Count d = Joypad
|
||||
// .C0:003F JSR sub_C00525
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// And, at 0xc00525:
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// .C0:0525 sub_C00525: ; CODE XREF: sub_C00019+26p
|
||||
// .C0:0525 TDC
|
||||
// .C0:0526 TAX
|
||||
// .C0:0527 STX WRAM_ADDRESS_LOW_BYTE
|
||||
// .C0:052A STA WRAM_ADDRESS_HIGH_BYTE
|
||||
// .C0:052D LDX #$120
|
||||
// .C0:0530
|
||||
// .C0:0530 loc_C00530: ; CODE XREF: sub_C00525+3Cj
|
||||
// .C0:0530 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0533 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0536 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0539 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:053C STA WRAM_DATA_READ_WRITE
|
||||
// .C0:053F STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0542 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0545 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0548 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:054B STA WRAM_DATA_READ_WRITE
|
||||
// .C0:054E STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0551 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0554 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0557 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:055A STA WRAM_DATA_READ_WRITE
|
||||
// .C0:055D STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0560 DEX
|
||||
// .C0:0561 BNE loc_C00530
|
||||
// .C0:0563 RTS
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// What would happen is that the 'STA's starting at
|
||||
// C0:0530 would not reference the proper register:
|
||||
// The B was 0xffffffff (from a previous
|
||||
// propagation), and when a later propagation tried to set
|
||||
// the B value to 0x00, starting at C0:0525, that
|
||||
// propagation stopped at the next segment start.
|
||||
// That is, C0:0530,
|
||||
// which was established because of the BNE that
|
||||
// appears below.
|
||||
// Which also makes me think.. should we propagate from a BNE?
|
||||
|
||||
uint8 opcode;
|
||||
ea_t cur_ea = from_ea;
|
||||
uint8 itype;
|
||||
switch ( source )
|
||||
{
|
||||
case BT_STACK:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
if ( M65_ITYPE_PUSH(itype) )
|
||||
{
|
||||
switch ( itype )
|
||||
{
|
||||
case M65816_pea: // Push effective absolute address
|
||||
{
|
||||
uint16 val = get_word(cur_ea + 1);
|
||||
if ( size == 1 )
|
||||
val &= 0xff;
|
||||
return val;
|
||||
}
|
||||
case M65816_pei: // Push effective indirect address
|
||||
return -1;
|
||||
case M65816_per: // Push effective PC-relative indirect address
|
||||
{
|
||||
uint16 val = cur_ea + 3;
|
||||
val += get_word(cur_ea + 1);
|
||||
val &= (size == 1 ? 0xff : 0xffff);
|
||||
return val;
|
||||
}
|
||||
case M65816_pha: // Push A
|
||||
return backtrack_value(cur_ea, size, BT_A);
|
||||
case M65816_phb: // Push B (data bank register)
|
||||
return get_sreg(cur_ea, rB);
|
||||
case M65816_phd: // Push D (direct page register)
|
||||
return get_sreg(cur_ea, rD);
|
||||
case M65816_phk: // Push K (program bank register)
|
||||
return get_sreg(cur_ea, rPB);
|
||||
case M65816_php: // Push processor status
|
||||
return -1;
|
||||
case M65816_phx: // Push X
|
||||
return backtrack_value(cur_ea, size, BT_X);
|
||||
case M65816_phy: // Push Y
|
||||
return backtrack_value(cur_ea, size, BT_Y);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if ( M65_ITYPE_PULL(itype) )
|
||||
{
|
||||
// TODO: keep track of additional displacements in the stack
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_A:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
uint8 opsize = from_ea - cur_ea;
|
||||
uint8 cur_ea_acc_is_16 = is_acc_16_bits(cur_ea);
|
||||
uint8 new_size = cur_ea_acc_is_16 ? 2 : 1;
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify A in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_adc: // Add with carry
|
||||
case M65816_and: // AND A with memory
|
||||
case M65816_asl: // Shift memory or A left
|
||||
case M65816_dec: // Decrement
|
||||
case M65816_eor: // XOR A with M
|
||||
case M65816_inc: // Increment
|
||||
case M65816_mvn: // Block move next
|
||||
case M65816_mvp: // Block move prev
|
||||
case M65816_ora: // Or A with memory
|
||||
case M65816_sbc: // Subtract with borrow from A
|
||||
case M65816_xba: // Exchange bytes in A
|
||||
return -1;
|
||||
// For these next ones, there's hope.
|
||||
case M65816_lsr: // Logical shift memory or A right
|
||||
if ( opcode == 0x4a ) // LSR A
|
||||
return -1;
|
||||
break;
|
||||
case M65816_rol: // Rotate memory or A left
|
||||
case M65816_ror: // Rotate memory or A right
|
||||
if ( opcode == 0x30 || opcode == 0x70 )
|
||||
return -1;
|
||||
break;
|
||||
case M65816_lda: // Load A from memory
|
||||
if ( opcode == 0xa9 ) // LDA imm
|
||||
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
|
||||
else
|
||||
return -1;
|
||||
case M65816_pla: // Pull A
|
||||
return backtrack_value(cur_ea, new_size, BT_STACK);
|
||||
case M65816_tdc: // Transfer 16-bit D to A
|
||||
return get_sreg(cur_ea, rD);
|
||||
case M65816_tsc: // Transfer S to A
|
||||
return get_sreg(cur_ea, rS);
|
||||
case M65816_txa: // Transfer X to A
|
||||
return backtrack_value(cur_ea, new_size, BT_X);
|
||||
case M65816_tya: // Transfer Y to A
|
||||
return backtrack_value(cur_ea, new_size, BT_Y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_X:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
uint8 opsize = from_ea - cur_ea;
|
||||
uint8 cur_ea_xy_is_16 = is_xy_16_bits(cur_ea);
|
||||
uint8 new_size = cur_ea_xy_is_16 ? 2 : 1;
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify X in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_dex: // Decrement X
|
||||
case M65816_inx: // Increment X
|
||||
case M65816_mvn: // Block move next
|
||||
case M65816_mvp: // Block move prev
|
||||
return -1;
|
||||
case M65816_ldx: // Load X from memory
|
||||
if ( opcode == 0xa2 ) // LDX imm
|
||||
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
|
||||
else
|
||||
return -1;
|
||||
case M65816_plx: // Pull X
|
||||
return backtrack_value(cur_ea, new_size, BT_STACK);
|
||||
case M65816_tax: // Transfer A to X
|
||||
return backtrack_value(cur_ea, new_size, BT_A);
|
||||
case M65816_tsx: // Transfer S to X
|
||||
return get_sreg(cur_ea, rS);
|
||||
case M65816_tyx: // Transfer Y to X
|
||||
return backtrack_value(cur_ea, new_size, BT_Y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_Y:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
uint8 opsize = from_ea - cur_ea;
|
||||
uint8 cur_ea_xy_is_16 = is_xy_16_bits(cur_ea);
|
||||
uint8 new_size = cur_ea_xy_is_16 ? 2 : 1;
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify X in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_dey: // Decrement Y
|
||||
case M65816_iny: // Increment Y
|
||||
case M65816_mvn: // Block move next
|
||||
case M65816_mvp: // Block move prev
|
||||
return -1;
|
||||
case M65816_ldy: // Load Y from memory
|
||||
if ( opcode == 0xa0 ) // LDY imm
|
||||
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
|
||||
else
|
||||
return -1;
|
||||
case M65816_ply: // Pull Y
|
||||
return backtrack_value(cur_ea, new_size, BT_STACK);
|
||||
case M65816_tay: // Transfer A to Y
|
||||
return backtrack_value(cur_ea, new_size, BT_A);
|
||||
case M65816_txy: // Transfer X to Y
|
||||
return backtrack_value(cur_ea, new_size, BT_X);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_DP:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify D in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_pld: // Pull D
|
||||
return backtrack_value(cur_ea, size, BT_STACK);
|
||||
case M65816_tcd: // Transfer 16-bit Accumulator to Direct Page Register
|
||||
return backtrack_value(cur_ea, size, BT_A);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg("WARNING: backtrack_value() of unsupported BT-type: %d\n", source);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
ea_t backtrack_prev_ins(ea_t from_ea, m65_itype_t itype)
|
||||
{
|
||||
uint8 opcode;
|
||||
ea_t cur_ea = from_ea;
|
||||
uint8 candidate_itype;
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, candidate_itype);
|
||||
if ( candidate_itype == itype )
|
||||
return cur_ea;
|
||||
}
|
||||
|
||||
return BADADDR;
|
||||
}
|
||||
|
||||
#undef BTWALK_LOOP
|
||||
#undef BTWALK_PREAMBLE
|
||||
|
||||
|
||||
74
idasdk76/module/65816/bt.hpp
Normal file
74
idasdk76/module/65816/bt.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef __BACKTRACK_HPP__
|
||||
#define __BACKTRACK_HPP__
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
|
||||
enum btsource_t
|
||||
{
|
||||
BT_NONE = 0,
|
||||
BT_STACK,
|
||||
BT_A,
|
||||
BT_X,
|
||||
BT_Y,
|
||||
BT_DP
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Walk instructions up, and try and determine what's the
|
||||
* (size * 8)-bits value we're looking for.
|
||||
*
|
||||
* For example, let's assume we have the following sequence
|
||||
* of instructions:
|
||||
* .05:8001 PHK
|
||||
* .05:8002 PLB
|
||||
* We'll call:
|
||||
* backtrack_value(0x58002, 1, BT_STACK).
|
||||
*
|
||||
* A more complex example is this:
|
||||
* .C0:0024 A2 00 00 LDX #0
|
||||
* .C0:0027 DA PHX
|
||||
* .C0:0028 2B PLD
|
||||
* .C0:0029 7B TDC
|
||||
* .C0:002A 48 PHA
|
||||
* .C0:002B AB PLB
|
||||
* We'll call:
|
||||
* backtrack_value(0xc0002b, 1, BT_STACK), which will call
|
||||
* backtrack_value(0xc0002a, 1, BT_A), which will call
|
||||
* backtrack_value(0xc00029, 1, BT_D), which will call
|
||||
* backtrack_value(0xc00028, 2, BT_STACK), which will call
|
||||
* backtrack_value(0xc00027, 2, BT_X), which has an immediate value that we can use. Bingo.
|
||||
*
|
||||
* Backtracking will, of course, stop if we hit the top
|
||||
* of a function, as it doesn't make much sense to keep
|
||||
* moving up.
|
||||
*
|
||||
* from_ea : The address from which we'll be analyzing up.
|
||||
* size : The size, in bytes, of the data we're looking for.
|
||||
* source : The register/stack that holds the value.
|
||||
*
|
||||
* returns : The value.
|
||||
*/
|
||||
int32 backtrack_value(ea_t from_ea, uint8 size, btsource_t source);
|
||||
|
||||
|
||||
/**
|
||||
* Walk instructions up, until an instruction with the given type
|
||||
* is found.
|
||||
*
|
||||
* Backtracking will, of course, stop if we hit the top
|
||||
* of a function, as it doesn't make much sense to keep
|
||||
* moving up.
|
||||
*
|
||||
* from_ea : The address from which we'll be analyzing up.
|
||||
* itype : The instruction type.
|
||||
*
|
||||
* returns : The address of the found instruction, or BADADDR
|
||||
* if not found.
|
||||
*/
|
||||
ea_t backtrack_prev_ins(ea_t from_ea, m65_itype_t itype);
|
||||
|
||||
|
||||
#endif
|
||||
294
idasdk76/module/65816/emu.cpp
Normal file
294
idasdk76/module/65816/emu.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "bt.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void m65816_t::handle_operand(const op_t &x, bool read_access, const insn_t &insn)
|
||||
{
|
||||
ea_t ea;
|
||||
dref_t dreftype;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
QASSERT(557, read_access);
|
||||
dreftype = dr_O;
|
||||
MAKE_IMMD:
|
||||
set_immd(insn.ea);
|
||||
if ( is_off(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dreftype, x.type == o_imm ? 0 : OOF_ADDR);
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
dreftype = read_access ? dr_R : dr_W;
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case rD: // "dp"
|
||||
case rDX: // "dp, X"
|
||||
case rDY: // "dp, Y"
|
||||
case riDX: // "(dp, X)"
|
||||
case rDi: // "(dp,n)"
|
||||
case rDiL: // "long(dp,n)"
|
||||
case rDiY: // "(dp,n), Y"
|
||||
case rDiLY: // "long(dp,n), Y"
|
||||
{
|
||||
sel_t dp = get_sreg(insn.ea, rD);
|
||||
if ( dp != BADSEL )
|
||||
{
|
||||
ea_t orig_ea = dp + x.addr;
|
||||
ea = xlat(orig_ea);
|
||||
goto MAKE_DREF;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto MAKE_IMMD;
|
||||
}
|
||||
}
|
||||
|
||||
case rAbsi: // "(abs)"
|
||||
case rAbsX: // "abs, X"
|
||||
case rAbsY: // "abs, Y"
|
||||
case rAbsiL: // "long(abs)"
|
||||
ea = xlat(map_data_ea(insn, x));
|
||||
goto MAKE_DREF;
|
||||
|
||||
case rAbsXi: // "(abs,X)"
|
||||
ea = xlat(map_code_ea(insn, x)); // jmp, jsr
|
||||
goto MAKE_DREF;
|
||||
|
||||
case rAbsLX: // "long abs, X"
|
||||
ea = x.addr;
|
||||
goto MAKE_DREF;
|
||||
|
||||
default:
|
||||
goto MAKE_IMMD;
|
||||
}
|
||||
|
||||
case o_mem:
|
||||
case o_mem_far:
|
||||
ea = calc_addr(x, NULL, insn);
|
||||
MAKE_DREF:
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, read_access ? dr_R : dr_W);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
case o_far:
|
||||
{
|
||||
ea_t orig_ea;
|
||||
ea = calc_addr(x, &orig_ea, insn);
|
||||
if ( insn.itype == M65816_per )
|
||||
{
|
||||
insn.add_dref(ea, x.offb, dr_O);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
cref_t creftype = x.type == o_near
|
||||
? iscall ? fl_CN : fl_JN
|
||||
: iscall ? fl_CF : fl_JF;
|
||||
insn.add_cref(ea, x.offb, creftype);
|
||||
if ( flow && iscall )
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(558);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/**
|
||||
* Get what is known of the status flags register,
|
||||
* at address 'ea'.
|
||||
*
|
||||
* ea : The effective address.
|
||||
*
|
||||
* returns : A 9-bit value, composed with what is known of the
|
||||
* status register at the 'ea' effective address. Its
|
||||
* layout is the following:
|
||||
* +----------------------------------------------------------------+
|
||||
* | 0 | 0 | 0 | 0 | 0 | 0 | 0 | e || n | v | m | x | d | i | z | c |
|
||||
* +----------------------------------------------------------------+
|
||||
* 15 7 0
|
||||
* Note that a 16-bit value is returned, in order to
|
||||
* take the emulation-mode flag into consideration.
|
||||
*/
|
||||
static uint16 get_cpu_status(ea_t ea)
|
||||
{
|
||||
return (get_sreg(ea, rFe) << 8) | (get_sreg(ea, rFm) << 5) | (get_sreg(ea, rFx) << 4);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int m65816_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn.Op1, 1, insn);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn.Op2, 1, insn);
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn.Op1, 0, insn);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn.Op2, 0, insn);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
uint8 code = get_byte(insn.ea);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(code);
|
||||
|
||||
if ( opinfo.itype == M65816_jmp || opinfo.itype == M65816_jsr )
|
||||
{
|
||||
if ( opinfo.addr == ABS_INDIR
|
||||
|| opinfo.addr == ABS_INDIR_LONG
|
||||
|| opinfo.addr == ABS_IX_INDIR )
|
||||
{
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
switch ( opinfo.addr )
|
||||
{
|
||||
case ABS_LONG_IX:
|
||||
{
|
||||
ea_t orig_ea = insn.Op1.addr;
|
||||
ea_t ea = xlat(orig_ea);
|
||||
|
||||
bool read_access;
|
||||
if ( insn.itype == M65816_sta )
|
||||
read_access = false;
|
||||
else
|
||||
read_access = true;
|
||||
|
||||
insn.add_dref(ea, insn.Op1.offb, read_access ? dr_R : dr_W);
|
||||
break;
|
||||
}
|
||||
|
||||
case DP:
|
||||
{
|
||||
bool read_access;
|
||||
if ( insn.itype == M65816_tsb || insn.itype == M65816_asl || insn.itype == M65816_trb
|
||||
|| insn.itype == M65816_rol || insn.itype == M65816_lsr || insn.itype == M65816_ror
|
||||
|| insn.itype == M65816_dec || insn.itype == M65816_inc )
|
||||
read_access = false;
|
||||
else
|
||||
read_access = true;
|
||||
|
||||
int32 val = backtrack_value(insn.ea, 2, BT_DP);
|
||||
if ( val != -1 )
|
||||
{
|
||||
ea_t orig_ea = val + insn.Op1.addr;
|
||||
ea_t ea = xlat(orig_ea);
|
||||
|
||||
insn.create_op_data(ea, insn.Op1);
|
||||
insn.add_dref(ea, insn.Op1.offb, read_access ? dr_R : dr_W);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65816_sep:
|
||||
case M65816_rep:
|
||||
{
|
||||
// Switching 8 -> 16 bits modes.
|
||||
uint8 flag_data = get_byte(insn.ea + 1);
|
||||
uint8 m_flag = flag_data & 0x20;
|
||||
uint8 x_flag = flag_data & 0x10;
|
||||
uint8 val = (insn.itype == M65816_rep) ? 0 : 1;
|
||||
|
||||
if ( m_flag )
|
||||
split_sreg_range(insn.ea + 2, rFm, val, SR_auto);
|
||||
if ( x_flag )
|
||||
split_sreg_range(insn.ea + 2, rFx, val, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_xce:
|
||||
{
|
||||
// Switching to native mode?
|
||||
uint8 prev = get_byte(insn.ea - 1);
|
||||
const struct opcode_info_t &opinf = get_opcode_info(prev);
|
||||
if ( opinf.itype == M65816_clc )
|
||||
split_sreg_range(insn.ea + 1, rFe, 0, SR_auto);
|
||||
else if ( opinf.itype == M65816_sec )
|
||||
split_sreg_range(insn.ea + 1, rFe, 1, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_jmp:
|
||||
case M65816_jml:
|
||||
case M65816_jsl:
|
||||
case M65816_jsr:
|
||||
{
|
||||
if ( insn.Op1.full_target_ea )
|
||||
{
|
||||
ea_t ftea = insn.Op1.full_target_ea;
|
||||
if ( insn.itype != M65816_jsl && insn.itype != M65816_jml )
|
||||
ftea = map_code_ea(insn, ftea, 0);
|
||||
else
|
||||
ftea = xlat(ftea);
|
||||
|
||||
split_sreg_range(ftea, rFm, get_sreg(insn.ea, rFm), SR_auto);
|
||||
split_sreg_range(ftea, rFx, get_sreg(insn.ea, rFx), SR_auto);
|
||||
split_sreg_range(ftea, rFe, get_sreg(insn.ea, rFe), SR_auto);
|
||||
split_sreg_range(ftea, rPB, ftea >> 16, SR_auto);
|
||||
split_sreg_range(ftea, rB, get_sreg(insn.ea, rB), SR_auto);
|
||||
split_sreg_range(ftea, rDs, get_sreg(insn.ea, rDs), SR_auto);
|
||||
split_sreg_range(ftea, rD, get_sreg(insn.ea, rD), SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_plb:
|
||||
{
|
||||
int32 val = backtrack_value(insn.ea, 1, BT_STACK);
|
||||
if ( val != -1 )
|
||||
{
|
||||
split_sreg_range(insn.ea + insn.size, rB, val, SR_auto);
|
||||
split_sreg_range(insn.ea + insn.size, rDs, val << 12, SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_pld:
|
||||
{
|
||||
int32 val = backtrack_value(insn.ea, 2, BT_STACK);
|
||||
if ( val != -1 )
|
||||
split_sreg_range(insn.ea + insn.size, rD, val, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_plp:
|
||||
{
|
||||
// Ideally, should pass another parameter, specifying when to stop
|
||||
// backtracking.
|
||||
// For example, in order to avoid this:
|
||||
// PHP
|
||||
// PLP <-- this one is causing interference
|
||||
// (dunno if that even happens, though)
|
||||
// PLP
|
||||
ea_t ea = backtrack_prev_ins(insn.ea, M65816_php);
|
||||
if ( ea != BADADDR )
|
||||
{
|
||||
uint16 p = get_cpu_status(ea);
|
||||
split_sreg_range(insn.ea + insn.size, rFm, (p >> 5) & 0x1, SR_auto);
|
||||
split_sreg_range(insn.ea + insn.size, rFx, (p >> 4) & 0x1, SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
143
idasdk76/module/65816/ins.cpp
Normal file
143
idasdk76/module/65816/ins.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 },
|
||||
{ "ADC", CF_USE1 }, // A <- (A) + M + C
|
||||
{ "AND", CF_USE1 }, // A <- A /\ M, C <- ~A7
|
||||
{ "ASL", CF_CHG1|CF_SHFT }, // C <- A7, A <- (A) << 1
|
||||
{ "BCC", CF_USE1 }, // if C=0, PC = PC + offset
|
||||
{ "BCS", CF_USE1 }, // if C=1, PC = PC + offset
|
||||
{ "BEQ", CF_USE1 }, // if Z=1, PC = PC + offset
|
||||
{ "BIT", CF_USE1 }, // Z <- ~(A /\ M) N<-M7 V<-M6
|
||||
{ "BMI", CF_USE1 }, // if N=1, PC = PC + offset
|
||||
{ "BNE", CF_USE1 }, // if Z=0, PC = PC + offset
|
||||
{ "BPL", CF_USE1 }, // if N=0, PC = PC + offset
|
||||
{ "BRA", CF_USE1|CF_STOP }, // Branch always
|
||||
{ "BRK", 0 }, // Stack <- PC, PC <- ($fffe) NOTE: Usually it stops the processor. However, some games (e.g. Dragon Quest VI) use BRK as a customized opcode, by overriding the behavior through the interrupt vector.
|
||||
{ "BRL", CF_USE1|CF_STOP }, // Branch always long
|
||||
{ "BVC", CF_USE1 }, // if V=0, PC = PC + offset
|
||||
{ "BVS", CF_USE1 }, // if V=1, PC = PC + offset
|
||||
{ "CLC", 0 }, // C <- 0
|
||||
{ "CLD", 0 }, // D <- 0
|
||||
{ "CLI", 0 }, // I <- 0
|
||||
{ "CLV", 0 }, // V <- 0
|
||||
{ "CMP", CF_USE1 }, // (A - M) -> NZC
|
||||
{ "COP", 0 }, // Coprocessor enable
|
||||
{ "CPX", CF_USE1 }, // (X - M) -> NZC
|
||||
{ "CPY", CF_USE1 }, // (Y - M) -> NZC
|
||||
{ "DEC", CF_USE1|CF_CHG1 }, // M <- (M) - 1
|
||||
{ "DEX", 0 }, // X <- (X) - 1
|
||||
{ "DEY", 0 }, // Y <- (Y) - 1
|
||||
{ "EOR", CF_USE1 }, // A <- (A) \-/ M
|
||||
{ "INC", CF_USE1|CF_CHG1 }, // M <- (M) + 1
|
||||
{ "INX", 0 }, // X <- (X) +1
|
||||
{ "INY", 0 }, // Y <- (Y) + 1
|
||||
{ "JML", CF_USE1|CF_STOP }, // K,PC <- Long Address
|
||||
{ "JMP", CF_USE1|CF_STOP }, // PC <- Address
|
||||
{ "JSL", CF_USE1|CF_CALL }, // Stack <- PC, PC <- Long Address
|
||||
{ "JSR", CF_USE1|CF_CALL }, // Stack <- PC, PC <- Address
|
||||
{ "LDA", CF_USE1 }, // A <- M
|
||||
{ "LDX", CF_USE1 }, // X <- M
|
||||
{ "LDY", CF_USE1 }, // Y <- M
|
||||
{ "LSR", CF_CHG1|CF_SHFT }, // C <- A0, A <- (A) >> 1
|
||||
{ "MVN", CF_USE1|CF_USE2 }, // Block move next
|
||||
{ "MVP", CF_USE1|CF_USE2 }, // Block move previous
|
||||
{ "NOP", 0 }, // [no operation]
|
||||
{ "ORA", CF_USE1 }, // A <- (A) V M
|
||||
{ "PEA", CF_USE1 }, // Stack <- Address
|
||||
{ "PEI", CF_USE1 }, // Stack <- [DP + M]
|
||||
{ "PER", CF_USE1 }, // Stack <- PC + offset
|
||||
{ "PHA", 0 }, // Stack <- (A)
|
||||
{ "PHB", 0 }, // Stack <- (B)
|
||||
{ "PHD", 0 }, // Stack <- (D)
|
||||
{ "PHK", 0 }, // Stack <- (K)
|
||||
{ "PHP", 0 }, // Stack <- (P)
|
||||
{ "PHX", 0 }, // Push X register
|
||||
{ "PHY", 0 }, // Push Y register
|
||||
{ "PLA", 0 }, // A <- (Stack)
|
||||
{ "PLB", 0 }, // B <- (Stack)
|
||||
{ "PLD", 0 }, // D <- (Stack)
|
||||
{ "PLP", 0 }, // P <- (Stack)
|
||||
{ "PLX", 0 }, // Pull X register
|
||||
{ "PLY", 0 }, // Pull Y register
|
||||
{ "REP", CF_USE1 }, // Reset bits
|
||||
{ "ROL", CF_CHG1|CF_SHFT }, // C <- A7 & A <- A << 1 + C
|
||||
{ "ROR", CF_CHG1|CF_SHFT }, // C<-A0 & A<- (A7=C + A>>1)
|
||||
{ "RTI", CF_STOP }, // P <- (Stack), PC <-(Stack)
|
||||
{ "RTL", CF_STOP }, // K,PC <- (Stack)
|
||||
{ "RTS", CF_STOP }, // PC <- (Stack)
|
||||
{ "SBC", CF_USE1 }, // A <- (A) - M - ~C
|
||||
{ "SEC", 0 }, // C <- 1
|
||||
{ "SED", 0 }, // D <- 1
|
||||
{ "SEI", 0 }, // I <- 1
|
||||
{ "SEP", CF_USE1 }, // P <- Values
|
||||
{ "STA", CF_CHG1 }, // M <- (A)
|
||||
{ "STP", 0 }, // Stop processor
|
||||
{ "STX", CF_CHG1 }, // M <- (X)
|
||||
{ "STY", CF_CHG1 }, // M <- (Y)
|
||||
{ "STZ", CF_CHG1 }, // Store zero
|
||||
{ "TAX", 0 }, // X <- (A)
|
||||
{ "TAY", 0 }, // Y <- (A)
|
||||
{ "TCD", 0 }, // D <- (A)
|
||||
{ "TCS", 0 }, // S <- (A)
|
||||
{ "TDC", 0 }, // A <- (D)
|
||||
{ "TRB", CF_USE1|CF_CHG1 }, // Test and reset bits
|
||||
{ "TSB", CF_USE1|CF_CHG1 }, // Test and set bits
|
||||
{ "TSC", 0 }, // A <- (S)
|
||||
{ "TSX", 0 }, // X <- (S)
|
||||
{ "TXA", 0 }, // A <- (X)
|
||||
{ "TXS", 0 }, // S <- (X)
|
||||
{ "TXY", 0 }, // Y <- (X)
|
||||
{ "TYA", 0 }, // A <- (Y)
|
||||
{ "TYX", 0 }, // X <- (Y)
|
||||
{ "WAI", 0 }, // Wait for interrupt
|
||||
{ "WDM", 0 }, // Reserved
|
||||
{ "XBA", 0 }, // Exchange A's bytes
|
||||
{ "XCE", 0 } // Exchange carry & emu bits
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == M65816_last);
|
||||
|
||||
|
||||
const struct addrmode_info_t AddressingModes[] =
|
||||
{
|
||||
{ "Absolute" }, // ABS
|
||||
{ "Absolute Indexed X" }, // ABS_IX,
|
||||
{ "Absolute Indexed Y" }, // ABS_IY,
|
||||
{ "Absolute Indexed Indirect" }, // ABS_IX_INDIR,
|
||||
{ "Absolute Indirect" }, // ABS_INDIR,
|
||||
{ "Absolute Indirect Long" }, // ABS_INDIR_LONG,
|
||||
{ "Absolute Long" }, // ABS_LONG,
|
||||
{ "Absolute Long Indexed X" }, // ABS_LONG_IX,
|
||||
{ "Accumulator" }, // ACC,
|
||||
{ "Block Move" }, // BLK_MOV,
|
||||
{ "Direct Page" }, // DP,
|
||||
{ "Direct Page Indexed X" }, // DP_IX,
|
||||
{ "Direct Page Indexed Y" }, // DP_IY,
|
||||
{ "Direct Page Indexed X Indirect" }, // DP_IX_INDIR,
|
||||
{ "Direct Page Indirect" }, // DP_INDIR,
|
||||
{ "Direct Page Indirect Long" }, // DP_INDIR_LONG,
|
||||
{ "Direct Page Indirect Indexed Y" }, // DP_INDIR_IY,
|
||||
{ "Direct Page Indirect Long Indexed Y" }, // DP_INDIR_LONG_IY,
|
||||
{ "Immediate" }, // IMM,
|
||||
{ "Implied" }, // IMPLIED,
|
||||
{ "Program Counter Relative" }, // PC_REL,
|
||||
{ "Program Counter Relative Long" }, // PC_REL_LONG,
|
||||
{ "Stack Absolute" }, // STACK_ABS,
|
||||
{ "Stack Direct Page Indirect" }, // STACK_DP_INDIR,
|
||||
{ "Stack Interrupt" }, // STACK_INT,
|
||||
{ "Stack Program Counter Relative" }, // STACK_PC_REL,
|
||||
{ "Stack Pull" }, // STACK_PULL,
|
||||
{ "Stack Push" }, // STACK_PUSH,
|
||||
{ "Stack RTI" }, // STACK_RTI,
|
||||
{ "Stack RTL" }, // STACK_RTL,
|
||||
{ "Stack RTS" }, // STACK_RTS,
|
||||
{ "Stack REL" }, // STACK_REL,
|
||||
{ "Stack Relative Indirect Indexed Y" } // STACK_REL_INDIR_IY,
|
||||
};
|
||||
|
||||
CASSERT(qnumber(AddressingModes) == ADDRMODE_last);
|
||||
109
idasdk76/module/65816/ins.hpp
Normal file
109
idasdk76/module/65816/ins.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
#ifndef __INSTRS_HPP__
|
||||
#define __INSTRS_HPP__
|
||||
|
||||
extern const struct instruc_t Instructions[];
|
||||
|
||||
// The instruction types (``itype''s)
|
||||
// m65* CPUs implements.
|
||||
|
||||
enum m65_itype_t
|
||||
{
|
||||
// http://www.westerndesigncenter.com/wdc/datasheets/Programmanual.pdf
|
||||
M65816_null=0, // Unknown Operation
|
||||
M65816_adc, // Add with carry
|
||||
M65816_and, // AND A with memory
|
||||
M65816_asl, // Shift memory or A left
|
||||
M65816_bcc, // Branch if carry clear
|
||||
M65816_bcs, // Branch if carry set
|
||||
M65816_beq, // Branch if equal
|
||||
M65816_bit, // Test memory bits against A
|
||||
M65816_bmi, // Branch if minus
|
||||
M65816_bne, // Branch if not equal
|
||||
M65816_bpl, // Branch if plus
|
||||
M65816_bra, // Branch always
|
||||
M65816_brk, // Software break
|
||||
M65816_brl, // Branch always long
|
||||
M65816_bvc, // Branch if overflow clear
|
||||
M65816_bvs, // Branch if overflow set
|
||||
M65816_clc, // Clear carry flag
|
||||
M65816_cld, // Clear decimal mode flag
|
||||
M65816_cli, // Clear interrupt disable flag
|
||||
M65816_clv, // Clear overflow flag
|
||||
M65816_cmp, // Compare A with memory
|
||||
M65816_cop, // Co-processor enable
|
||||
M65816_cpx, // Compare X with memory
|
||||
M65816_cpy, // Compare Y with memory
|
||||
M65816_dec, // Decrement
|
||||
M65816_dex, // Decrement X
|
||||
M65816_dey, // Decrement Y
|
||||
M65816_eor, // XOR A with M
|
||||
M65816_inc, // Increment
|
||||
M65816_inx, // Increment X
|
||||
M65816_iny, // Increment Y
|
||||
M65816_jml, // Jump long (inter-bank)
|
||||
M65816_jmp, // Jump
|
||||
M65816_jsl, // Jump to subroutine long (inter-bank)
|
||||
M65816_jsr, // Jump to subroutine
|
||||
M65816_lda, // Load A from memory
|
||||
M65816_ldx, // Load X from memory
|
||||
M65816_ldy, // Load Y from memory
|
||||
M65816_lsr, // Logical shift memory or A right
|
||||
M65816_mvn, // Block move next
|
||||
M65816_mvp, // Block move prev
|
||||
M65816_nop, // Nop
|
||||
M65816_ora, // Or A with memory
|
||||
M65816_pea, // Push effective absolute address
|
||||
M65816_pei, // Push effective indirect address
|
||||
M65816_per, // Push effective PC-relative indirect address
|
||||
M65816_pha, // Push A
|
||||
M65816_phb, // Push B (data bank register)
|
||||
M65816_phd, // Push D (direct page register)
|
||||
M65816_phk, // Push K (program bank register)
|
||||
M65816_php, // Push processor status
|
||||
M65816_phx, // Push X
|
||||
M65816_phy, // Push Y
|
||||
M65816_pla, // Pull A
|
||||
M65816_plb, // Pull B
|
||||
M65816_pld, // Pull D
|
||||
M65816_plp, // Pull processor status
|
||||
M65816_plx, // Pull X
|
||||
M65816_ply, // Pull Y
|
||||
M65816_rep, // Reset status bits
|
||||
M65816_rol, // Rotate memory or A left
|
||||
M65816_ror, // Rotate memory or A right
|
||||
M65816_rti, // Return from interrupt
|
||||
M65816_rtl, // Return from subroutine long
|
||||
M65816_rts, // Return from subroutine
|
||||
M65816_sbc, // Subtract with borrow from A
|
||||
M65816_sec, // Set carry flag
|
||||
M65816_sed, // Set decimal mode flag
|
||||
M65816_sei, // Set interrupt disable flag
|
||||
M65816_sep, // Set status bits
|
||||
M65816_sta, // Store A to memory
|
||||
M65816_stp, // Stop processor
|
||||
M65816_stx, // Store X to memory
|
||||
M65816_sty, // Store Y to memory
|
||||
M65816_stz, // Store zero to memory
|
||||
M65816_tax, // Transfer A to X
|
||||
M65816_tay, // Transfer A to Y
|
||||
M65816_tcd, // Transfer 16-bit A to D (direct page register)
|
||||
M65816_tcs, // Transfer A to S
|
||||
M65816_tdc, // Transfer 16-bit D to A
|
||||
M65816_trb, // Test and reset memory bits against A
|
||||
M65816_tsb, // Test and set memory bits against A
|
||||
M65816_tsc, // Transfer S to A
|
||||
M65816_tsx, // Transfer S to X
|
||||
M65816_txa, // Transfer X to A
|
||||
M65816_txs, // Transfer X to S
|
||||
M65816_txy, // Transfer X to Y
|
||||
M65816_tya, // Transfer Y to A
|
||||
M65816_tyx, // Transfer Y to X
|
||||
M65816_wai, // Wait for interrupt
|
||||
M65816_wdm, // Reserved
|
||||
M65816_xba, // Exchange bytes in A
|
||||
M65816_xce, // Exchange carry and emulation bits
|
||||
M65816_last
|
||||
};
|
||||
|
||||
#endif
|
||||
422
idasdk76/module/65816/m65816.cfg
Normal file
422
idasdk76/module/65816/m65816.cfg
Normal file
@@ -0,0 +1,422 @@
|
||||
;; Copied from m7900.cfg
|
||||
; The format of the input file:
|
||||
; each device definition begins with a line like this:
|
||||
;
|
||||
; .devicename
|
||||
;
|
||||
; after it go the port definitions in this format:
|
||||
;
|
||||
; portname address
|
||||
;
|
||||
; the bit definitions (optional) are represented like this:
|
||||
;
|
||||
; portname.bitname bitnumber
|
||||
;
|
||||
; lines beginning with a space are ignored.
|
||||
; comment lines should be started with ';' character.
|
||||
;
|
||||
; the default device is specified at the start of the file
|
||||
;
|
||||
; .default device_name
|
||||
;
|
||||
; all lines non conforming to the format are passed to the callback function
|
||||
;
|
||||
; MITSUBISHI 7900 SPECIFIC LINES
|
||||
;------------------------
|
||||
;
|
||||
; the processor definition may include the memory configuration.
|
||||
; the line format is:
|
||||
|
||||
; area CLASS AREA-NAME START:END
|
||||
;
|
||||
; where CLASS is anything, but please use one of CODE, DATA, BSS
|
||||
; START and END are addresses, the end address is not included
|
||||
|
||||
; Interrupt vectors are declared in the following way:
|
||||
|
||||
; entry NAME ADDRESS COMMENT
|
||||
|
||||
.default snes
|
||||
|
||||
.snes
|
||||
|
||||
; --------------------- PPU Picture Processing Unit (Write-Only Ports)
|
||||
|
||||
INIDISP 0x2100 Display Control 1 (a000bbbb a: 0=screen on 1=screen off, b = brightness)
|
||||
OBSEL 0x2101 Object Size and Object Base (aaabbccc a = Size, b = Name Selection, c = Base Selection)
|
||||
OAMADDL 0x2102 OAM Address (lower 8bit)
|
||||
OAMADDH 0x2103 OAM Address (upper 1bit) and Priority Rotation
|
||||
OAMDATA 0x2104 OAM Data Write (write-twice)
|
||||
BGMODE 0x2105 BG Mode and BG Character Size (abcdefff abcd = BG tile size (4321): 0 = 8x8 1 = 16x16, e = BG 3 High Priority, f = BG Mode)
|
||||
MOSAIC 0x2106 Mosaic Size and Mosaic Enable (aaaabbbb a = Mosaic Size b = Mosaic BG Enable)
|
||||
BG1SC 0x2107 BG1 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG2SC 0x2108 BG2 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG3SC 0x2109 BG3 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG4SC 0x210a BG4 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG12NBA 0x210b BG Character Data Area Designation (aaaabbbb a = BG 2 Tile Base Address, b = BG 1 Tile Base Address)
|
||||
BG34NBA 0x210c BG Character Data Area Designation (aaaabbbb a = BG 4 Tile Base Address, b = BG 3 Tile Base Address)
|
||||
BG1HOFS 0x210d BG1 Horizontal Scroll (X) (write-twice) / M7HOFS
|
||||
BG1VOFS 0x210e BG1 Vertical Scroll (Y) (write-twice) / M7VOFS
|
||||
BG2HOFS 0x210f BG2 Horizontal Scroll (X) (write-twice)
|
||||
BG2VOFS 0x2110 BG2 Vertical Scroll (Y) (write-twice)
|
||||
BG3HOFS 0x2111 BG3 Horizontal Scroll (X) (write-twice)
|
||||
BG3VOFS 0x2112 BG3 Vertical Scroll (Y) (write-twice)
|
||||
BG4HOFS 0x2113 BG4 Horizontal Scroll (X) (write-twice)
|
||||
BG4VOFS 0x2114 BG4 Vertical Scroll (Y) (write-twice)
|
||||
VMAIN 0x2115 VRAM Address Increment Mode
|
||||
VMADDL 0x2116 VRAM Address (lower 8bit)
|
||||
VMADDH 0x2117 VRAM Address (upper 8bit)
|
||||
VMDATAL 0x2118 VRAM Data Write (lower 8bit)
|
||||
VMDATAH 0x2119 VRAM Data Write (upper 8bit)
|
||||
M7SEL 0x211a Rotation/Scaling Mode Settings (aa0000bc a = Screen Over b = Vertical Flip c = Horizontal Flip)
|
||||
M7A 0x211b Rotation/Scaling Parameter A & Maths 16bit operand
|
||||
M7B 0x211c Rotation/Scaling Parameter B & Maths 8bit operand
|
||||
M7C 0x211d Rotation/Scaling Parameter C (write-twice)
|
||||
M7D 0x211e Rotation/Scaling Parameter D (write-twice)
|
||||
M7X 0x211f Rotation/Scaling Center Coordinate X (write-twice)
|
||||
M7Y 0x2120 Rotation/Scaling Center Coordinate Y (write-twice)
|
||||
CGADD 0x2121 Palette CGRAM Address
|
||||
CGDATA 0x2122 Palette CGRAM Data Write (write-twice)
|
||||
W12SEL 0x2123 Window BG1/BG2 Mask Settings (aaaabbbb a = BG 2 Window Settings b = BG 1 Window Settings)
|
||||
W34SEL 0x2124 Window BG3/BG4 Mask Settings (aaaabbbb a = BG 4 Window Settings b = BG 3 Window Settings)
|
||||
WOBJSEL 0x2125 Window OBJ/MATH Mask Settings (aaaabbbb a = Color Window Settings b = OBJ Window Settings)
|
||||
WH0 0x2126 Window 1 Left Position (X1)
|
||||
WH1 0x2127 Window 1 Right Position (X2)
|
||||
WH2 0x2128 Window 2 Left Position (X1)
|
||||
WH3 0x2129 Window 2 Right Position (X2)
|
||||
WBGLOG 0x212a Window 1/2 Mask Logic (BG1-BG4) (aabbccdd a = Bg4, b = Bg3, c = Bg2, d = Bg1)
|
||||
WOBJLOG 0x212b Window 1/2 Mask Logic (OBJ/MATH) (0000aabb a = Color Window b = OBJ Window)
|
||||
TM 0x212c Main Screen Designation (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
TS 0x212d Sub Screen Designation (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
TMW 0x212e Window Area Main Screen Disable (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
TSW 0x212f Window Area Sub Screen Disable (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
CGWSEL 0x2130 Color Math Control Register A (aabb00cd a = Main Color Window On/Off, b = Sub Color Window On/Off, c = Fixed Color Add/Subtract Enable, d = Direct Select)
|
||||
CGADSUB 0x2131 Color Math Control Register B (abcdefgh a = 0 for Addition, 1 for Subtraction, b = 1/2 Enable c = Back Enable, d = Object Enable, efgh = Enable Bg 4, 3, 2, 1)
|
||||
COLDATA 0x2132 Color Math Sub Screen Backdrop Color (abcddddd a = Blue b = Green c = Red ddddd = Color Data)
|
||||
SETINI 0x2133 Display Control 2 (ab00cdef a = External Sync, b = ExtBG Mode, c = Pseudo 512 Mode, d = Vertical Size, e = Object-V Select, f = Interlace)
|
||||
|
||||
; --------------------- PPU Picture Processing Unit (Read-Only Ports)
|
||||
|
||||
MPYL 0x2134 PPU1 Signed Multiply Result (lower 8bit)
|
||||
MPYM 0x2135 PPU1 Signed Multiply Result (middle 8bit)
|
||||
MPYH 0x2136 PPU1 Signed Multiply Result (upper 8bit)
|
||||
SLHV 0x2137 PPU1 Latch H/V-Counter by Software (Read=Strobe)
|
||||
RDOAM 0x2138 PPU1 OAM Data Read (read-twice)
|
||||
RDVRAML 0x2139 PPU1 VRAM Data Read (lower 8bits)
|
||||
RDVRAMH 0x213a PPU1 VRAM Data Read (upper 8bits)
|
||||
RDCGRAM 0x213b PPU2 CGRAM Data Read (Palette) (read-twice)
|
||||
OPHCT 0x213c PPU2 Horizontal Counter Latch (read-twice)
|
||||
OPVCT 0x213d PPU2 Vertical Counter Latch (read-twice)
|
||||
STAT77 0x213e PPU1 Status and PPU1 Version Number
|
||||
STAT78 0x213f PPU2 Status and PPU2 Version Number
|
||||
|
||||
; --------------------- APU Audio Processing Unit (R/W)
|
||||
|
||||
APUI00 0x2140 Main CPU to Sound CPU Communication Port 0
|
||||
APUI01 0x2141 Main CPU to Sound CPU Communication Port 1
|
||||
APUI02 0x2142 Main CPU to Sound CPU Communication Port 2
|
||||
APUI03 0x2143 Main CPU to Sound CPU Communication Port 3
|
||||
|
||||
; --------------------- WRAM Access
|
||||
|
||||
WMDATA 0x2180 WRAM Data Read/Write (R/W)
|
||||
WMADDL 0x2181 WRAM Address (lower 8bit) (W)
|
||||
WMADDM 0x2182 WRAM Address (middle 8bit) (W)
|
||||
WMADDH 0x2183 WRAM Address (upper 1bit) (W)
|
||||
|
||||
; --------------------- CPU On-Chip I/O Ports
|
||||
|
||||
JOYA 0x4016 Joypad Input Register A (R) / Joypad Output (W)
|
||||
JOYB 0x4017 Joypad Input Register B (R)
|
||||
|
||||
; --------------------- CPU On-Chip I/O Ports (Write-only) (Read=open bus)
|
||||
|
||||
NMITIMEN 0x4200 Interrupt Enable and Joypad Request (a0bc000d a = NMI b = V-Count c = H-Count d = Joypad)
|
||||
WRIO 0x4201 Joypad Programmable I/O Port (Open-Collector Output)
|
||||
WRMPYA 0x4202 Set unsigned 8bit Multiplicand
|
||||
WRMPYB 0x4203 Set unsigned 8bit Multiplier and Start Multiplication
|
||||
WRDIVL 0x4204 Set unsigned 16bit Dividend (lower 8bit)
|
||||
WRDIVH 0x4205 Set unsigned 16bit Dividend (upper 8bit)
|
||||
WRDIVB 0x4206 Set unsigned 8bit Divisor and Start Division
|
||||
HTIMEL 0x4207 H-Count Timer Setting (lower 8bits)
|
||||
HTIMEH 0x4208 H-Count Timer Setting (upper 1bit)
|
||||
VTIMEL 0x4209 V-Count Timer Setting (lower 8bits)
|
||||
VTIMEH 0x420a V-Count Timer Setting (upper 1bit)
|
||||
MDMAEN 0x420b Select General Purpose DMA Channel(s) and Start Transfer (abcdefgh a = Channel 7...h = Channel 0: 1 = Enable 0 = Disable
|
||||
HDMAEN 0x420c Select H-Blank DMA (H-DMA) Channel(s) (abcdefgh a = Channel 7 .. h = Channel 0: 1 = Enable 0 = Disable
|
||||
MEMSEL 0x420d Memory-2 Waitstate Control (0000000a a: 0 = 2.68 MHz, 1 = 3.58 MHz
|
||||
|
||||
; --------------------- CPU On-Chip I/O Ports (Read-only)
|
||||
|
||||
RDNMI 0x4210 V-Blank NMI Flag and CPU Version Number (Read/Ack)
|
||||
TIMEUP 0x4211 H/V-Timer IRQ Flag (Read/Ack)
|
||||
HVBJOY 0x4212 H/V-Blank flag and Joypad Busy flag (R)
|
||||
RDIO 0x4213 Joypad Programmable I/O Port (Input)
|
||||
RDDIVL 0x4214 Unsigned Division Result (Quotient) (lower 8bit)
|
||||
RDDIVH 0x4215 Unsigned Division Result (Quotient) (upper 8bit)
|
||||
RDMPYL 0x4216 Unsigned Division Remainder / Multiply Product (lower 8bit)
|
||||
RDMPYH 0x4217 Unsigned Division Remainder / Multiply Product (upper 8bit)
|
||||
JOY1L 0x4218 Joypad 1 (gameport 1, pin 4) (lower 8bit) (abcd0000 a = Button A b = X c = L d = R)
|
||||
JOY1H 0x4219 Joypad 1 (gameport 1, pin 4) (upper 8bit) (abcdefgh a = B b = Y c = Select d = Start efgh = Up/Dn/Lt/Rt)
|
||||
JOY2L 0x421a Joypad 2 (gameport 2, pin 4) (lower 8bit)
|
||||
JOY2H 0x421b Joypad 2 (gameport 2, pin 4) (upper 8bit)
|
||||
JOY3L 0x421c Joypad 3 (gameport 1, pin 5) (lower 8bit)
|
||||
JOY3H 0x421d Joypad 3 (gameport 1, pin 5) (upper 8bit)
|
||||
JOY4L 0x421e Joypad 4 (gameport 2, pin 5) (lower 8bit)
|
||||
JOY4H 0x421f Joypad 4 (gameport 2, pin 5) (upper 8bit)
|
||||
|
||||
; --------------------- DMA
|
||||
|
||||
DMAP0 0x4300 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD0 0x4301 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T0L 0x4302 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T0H 0x4303 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B0 0x4304 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS0L 0x4305 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS0H 0x4306 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS00 0x4307 Indirect HDMA Address (bank)
|
||||
A2A0L 0x4308 HDMA Table Current Address (low)
|
||||
A2A0H 0x4309 HDMA Table Current Address (high)
|
||||
NTRL0 0x430a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED0 0x430b Unused byte (read/write-able)
|
||||
MIRR0 0x430f Mirror of 430Bh (R/W)
|
||||
DMAP1 0x4310 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD1 0x4311 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T1L 0x4312 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T1H 0x4313 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B1 0x4314 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS1L 0x4315 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS1H 0x4316 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS10 0x4317 Indirect HDMA Address (bank)
|
||||
A2A1L 0x4318 HDMA Table Current Address (low)
|
||||
A2A1H 0x4319 HDMA Table Current Address (high)
|
||||
NTRL1 0x431a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED1 0x431b Unused byte (read/write-able)
|
||||
MIRR1 0x431f Mirror of 431Bh (R/W)
|
||||
DMAP2 0x4320 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD2 0x4321 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T2L 0x4322 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T2H 0x4323 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B2 0x4324 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS2L 0x4325 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS2H 0x4326 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS20 0x4327 Indirect HDMA Address (bank)
|
||||
A2A2L 0x4328 HDMA Table Current Address (low)
|
||||
A2A2H 0x4329 HDMA Table Current Address (high)
|
||||
NTRL2 0x432a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED2 0x432b Unused byte (read/write-able)
|
||||
MIRR2 0x432f Mirror of 432Bh (R/W)
|
||||
DMAP3 0x4330 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD3 0x4331 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T3L 0x4332 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T3H 0x4333 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B3 0x4334 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS3L 0x4335 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS3H 0x4336 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS30 0x4337 Indirect HDMA Address (bank)
|
||||
A2A3L 0x4338 HDMA Table Current Address (low)
|
||||
A2A3H 0x4339 HDMA Table Current Address (high)
|
||||
NTRL3 0x433a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED3 0x433b Unused byte (read/write-able)
|
||||
MIRR3 0x433f Mirror of 433Bh (R/W)
|
||||
DMAP4 0x4340 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD4 0x4341 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T4L 0x4342 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T4H 0x4343 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B4 0x4344 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS4L 0x4345 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS4H 0x4346 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS40 0x4347 Indirect HDMA Address (bank)
|
||||
A2A4L 0x4348 HDMA Table Current Address (low)
|
||||
A2A4H 0x4349 HDMA Table Current Address (high)
|
||||
NTRL4 0x434a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED4 0x434b Unused byte (read/write-able)
|
||||
MIRR4 0x434f Mirror of 434Bh (R/W)
|
||||
DMAP5 0x4350 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD5 0x4351 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T5L 0x4352 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T5H 0x4353 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B5 0x4354 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS5L 0x4355 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS5H 0x4356 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS50 0x4357 Indirect HDMA Address (bank)
|
||||
A2A5L 0x4358 HDMA Table Current Address (low)
|
||||
A2A5H 0x4359 HDMA Table Current Address (high)
|
||||
NTRL5 0x435a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED5 0x435b Unused byte (read/write-able)
|
||||
MIRR5 0x435f Mirror of 435Bh (R/W)
|
||||
DMAP6 0x4360 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD6 0x4361 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T6L 0x4362 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T6H 0x4363 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B6 0x4364 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS6L 0x4365 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS6H 0x4366 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS60 0x4367 Indirect HDMA Address (bank)
|
||||
A2A6L 0x4368 HDMA Table Current Address (low)
|
||||
A2A6H 0x4369 HDMA Table Current Address (high)
|
||||
NTRL6 0x436a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED6 0x436b Unused byte (read/write-able)
|
||||
MIRR6 0x436f Mirror of 436Bh (R/W)
|
||||
DMAP7 0x4370 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD7 0x4371 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T7L 0x4372 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T7H 0x4373 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B7 0x4374 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS7L 0x4375 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS7H 0x4376 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS70 0x4377 Indirect HDMA Address (bank)
|
||||
A2A7L 0x4378 HDMA Table Current Address (low)
|
||||
A2A7H 0x4379 HDMA Table Current Address (high)
|
||||
NTRL7 0x437a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED7 0x437b Unused byte (read/write-able)
|
||||
MIRR7 0x437f Mirror of 437Bh (R/W)
|
||||
|
||||
.superfx
|
||||
|
||||
; --------------------- GSU I/O Map
|
||||
|
||||
R0 0x3000 Default source/destination register (Sreg/Dreg) (R/W)
|
||||
R1 0x3002 PLOT opcode: X coordinate (0000h on reset) (R/W)
|
||||
R2 0x3004 PLOT opcode: Y coordinate (0000h on reset) (R/W)
|
||||
R3 0x3006 General purpose (R/W)
|
||||
R4 0x3008 LMULT opcode: lower 16bits of result (R/W)
|
||||
R5 0x300a General purpose (R/W)
|
||||
R6 0x300c LMULT and FMULT opcodes: multiplier (R/W)
|
||||
R7 0x300e MERGE opcode (R/W)
|
||||
R8 0x3010 MERGE opcode (R/W)
|
||||
R9 0x3012 General purpose (R/W)
|
||||
R10 0x3014 General purpose (conventionally stack pointer) (R/W)
|
||||
R11 0x3016 LINK opcode: destination (R/W)
|
||||
R12 0x3018 LOOP opcode: counter (R/W)
|
||||
R13 0x301a LOOP opcode: address (R/W)
|
||||
R14 0x301c GETxx opcodes: Game Pak ROM Address Pointer (R/W)
|
||||
R15 0x301e Program Counter, writing MSB starts GSU operation (R/W)
|
||||
SFR 0x3030 Status/Flag Register (R) (Bit1-5: R/W)
|
||||
BRAMR 0x3033 Back-up RAM Register (W)
|
||||
PBR 0x3034 Program Bank Register (8bit, bank 00h..FFh) (R/W)
|
||||
ROMBR 0x3036 Game Pak ROM Bank Register (8bit, bank 00h..FFh) (R)
|
||||
CFGR 0x3037 Config Register (W)
|
||||
SCBR 0x3038 Screen Base Register (8bit, in 1Kbyte units) (W)
|
||||
CLSR 0x3039 Clock Select Register (W)
|
||||
SCMR 0x303a Screen Mode Register (W)
|
||||
VCR 0x303b Version Code Register (R)
|
||||
RAMBR 0x303c Game Pak RAM Bank Register (1bit, bank 70h/71h) (R)
|
||||
CBR 0x303e Cache Base Register (in upper 12bit; lower 4bit=unused) (R)
|
||||
|
||||
.sa1
|
||||
|
||||
; --------------------- SA-1 I/O Map (Write Only Registers)
|
||||
|
||||
CCNT 0x2200 SA-1 CPU Control (W)
|
||||
SIE 0x2201 SNES CPU Int Enable (W)
|
||||
SIC 0x2202 SNES CPU Int Clear (W)
|
||||
CRV 0x2203 SA-1 CPU Reset Vector Lsb (W)
|
||||
CNVL 0x2205 SA-1 CPU NMI Vector Lsb (W)
|
||||
CNVH 0x2206 SA-1 CPU NMI Vector Msb (W)
|
||||
CIVL 0x2207 SA-1 CPU IRQ Vector Lsb (W)
|
||||
CIVH 0x2208 SA-1 CPU IRQ Vector Msb (W)
|
||||
SCNT 0x2209 SNES CPU Control (W)
|
||||
CIE 0x220a SA-1 CPU Int Enable (W)
|
||||
CIC 0x220b SA-1 CPU Int Clear (W)
|
||||
SNVL 0x220c SNES CPU NMI Vector Lsb (W)
|
||||
SNVH 0x220d SNES CPU NMI Vector Msb (W)
|
||||
SIVL 0x220e SNES CPU IRQ Vector Lsb (W)
|
||||
SIVH 0x220f SNES CPU IRQ Vector Msb (W)
|
||||
TMC 0x2210 H/V Timer Control (W)
|
||||
CTR 0x2211 SA-1 CPU Timer Restart (W)
|
||||
HCNTL 0x2212 Set H-Count Lsb (W)
|
||||
HCNTH 0x2213 Set H-Count Msb (W)
|
||||
VCNTL 0x2214 Set V-Count Lsb (W)
|
||||
VCNTH 0x2215 Set V-Count Msb (W)
|
||||
CXB 0x2220 MMC Bank C - Hirom C0h-CFh / LoRom 00h-1Fh (W)
|
||||
DXB 0x2221 MMC Bank D - Hirom D0h-DFh / LoRom 20h-3Fh (W)
|
||||
EXB 0x2222 MMC Bank E - Hirom E0h-EFh / LoRom 80h-9Fh (W)
|
||||
FXB 0x2223 MMC Bank F - Hirom F0h-FFh / LoRom A0h-BFh (W)
|
||||
BMAPS 0x2224 SNES CPU BW-RAM Mapping to 6000h-7FFFh (W)
|
||||
BMAP 0x2225 SA-1 CPU BW-RAM Mapping to 6000h-7FFFh (W)
|
||||
SBWE 0x2226 SNES CPU BW-RAM Write Enable (W)
|
||||
CBWE 0x2227 SA-1 CPU BW-RAM Write Enable (W)
|
||||
BWPA 0x2228 BW-RAM Write-Protected Area (W)
|
||||
SIWP 0x2229 SNES I-RAM Write-Protection (W)
|
||||
CIWP 0x222a SA-1 I-RAM Write-Protection (W)
|
||||
DCNT 0x2230 DMA Control (W)
|
||||
CDMA 0x2231 Character Conversion DMA Parameters (W)
|
||||
SDAL 0x2232 DMA Source Device Start Address Lsb (W)
|
||||
SDAM 0x2233 DMA Source Device Start Address Mid (W)
|
||||
SDAH 0x2234 DMA Source Device Start Address Msb (W)
|
||||
DDAL 0x2235 DMA Dest Device Start Address Lsb (W)
|
||||
DDAM 0x2236 DMA Dest Device Start Address Mid (Start/I-RAM) (W)
|
||||
DDAH 0x2237 DMA Dest Device Start Address Msb (Start/BW-RAM)(W)
|
||||
DTCL 0x2238 DMA Terminal Counter Lsb (W)
|
||||
DTCH 0x2239 DMA Terminal Counter Msb (W)
|
||||
BBF 0x223f BW-RAM Bit Map Format for 600000h-6FFFFFh (W)
|
||||
BRF0 0x2240 Bit Map Register File (W)
|
||||
BRF1 0x2241 Bit Map Register File (W)
|
||||
BRF2 0x2242 Bit Map Register File (W)
|
||||
BRF3 0x2243 Bit Map Register File (W)
|
||||
BRF4 0x2244 Bit Map Register File (W)
|
||||
BRF5 0x2245 Bit Map Register File (W)
|
||||
BRF6 0x2246 Bit Map Register File (W)
|
||||
BRF7 0x2247 Bit Map Register File (W)
|
||||
BRF8 0x2248 Bit Map Register File (W)
|
||||
BRF9 0x2249 Bit Map Register File (W)
|
||||
BRFA 0x224a Bit Map Register File (W)
|
||||
BRFB 0x224b Bit Map Register File (W)
|
||||
BRFC 0x224c Bit Map Register File (W)
|
||||
BRFD 0x224d Bit Map Register File (W)
|
||||
BRFE 0x224e Bit Map Register File (W)
|
||||
BRFF 0x224f Bit Map Register File (W)
|
||||
MCNT 0x2250 Arithmetic Control (W)
|
||||
MAL 0x2251 Arithmetic Param A Lsb (Multiplicand/Dividend) (W)
|
||||
MAH 0x2252 Arithmetic Param A Msb (Multiplicand/Dividend) (W)
|
||||
MBL 0x2253 Arithmetic Param B Lsb (Multiplier/Divisor) (W)
|
||||
MBH 0x2254 Arithmetic Param B Msb (Multiplier/Divisor)/Start (W)
|
||||
VBD 0x2258 Variable-Length Bit Processing (W)
|
||||
VDAL 0x2259 Var-Length Bit Game Pak ROM Start Address Lsb (W)
|
||||
VDAM 0x225a Var-Length Bit Game Pak ROM Start Address Mid (W)
|
||||
VDAH 0x225b Var-Length Bit Game Pak ROM Start Address Msb & Kick
|
||||
|
||||
; --------------------- SA-1 I/O Map (Read Only Registers)
|
||||
|
||||
SFR 0x2300 SNES CPU Flag Read (R)
|
||||
CFR 0x2301 SA-1 CPU Flag Read (R)
|
||||
HCRL 0x2302 H-Count Read Lsb / Do Latching (R)
|
||||
HCRH 0x2303 H-Count Read Msb (R)
|
||||
VCRL 0x2304 V-Count Read Lsb (R)
|
||||
VCRH 0x2305 V-Count Read Msb (R)
|
||||
MRAL 0x2306 Arithmetic Result, bit0-7 (Sum/Product/Quotient) (R)
|
||||
MRAH 0x2307 Arithmetic Result, bit8-15 (Sum/Product/Quotient) (R)
|
||||
MRBL 0x2308 Arithmetic Result, bit16-23 (Sum/Product/Remainder) (R)
|
||||
MRBH 0x2309 Arithmetic Result, bit24-31 (Sum/Product/Remainder) (R)
|
||||
MRC 0x230a Arithmetic Result, bit32-39 (Sum) (R)
|
||||
OF 0x230b Arithmetic Overflow Flag (R)
|
||||
VDPL 0x230c Variable-Length Data Read Port Lsb (R)
|
||||
VDPH 0x230d Variable-Length Data Read Port Msb (R)
|
||||
VC 0x230e Version Code Register (R)
|
||||
|
||||
.cx4
|
||||
|
||||
.spc7110
|
||||
|
||||
.sdd1
|
||||
|
||||
.sharprtc
|
||||
|
||||
.epsonrtc
|
||||
|
||||
.obc1
|
||||
|
||||
.dsp1
|
||||
|
||||
.dsp2
|
||||
|
||||
.dsp3
|
||||
|
||||
.dsp4
|
||||
|
||||
.st010
|
||||
|
||||
.st011
|
||||
|
||||
.st018
|
||||
263
idasdk76/module/65816/m65816.hpp
Normal file
263
idasdk76/module/65816/m65816.hpp
Normal file
@@ -0,0 +1,263 @@
|
||||
|
||||
#ifndef __M65816_HPP__
|
||||
#define __M65816_HPP__
|
||||
|
||||
#include "../../module/idaidp.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
#define PROCMOD_NAME m65816
|
||||
#define PROCMOD_NODE_NAME "$ " QSTRINGIZE(PROCMOD_NAME)
|
||||
|
||||
// Direct Memory Reference with full-length address
|
||||
#define o_mem_far o_idpspec0
|
||||
|
||||
// If there is an address in 'Op[N].full_target_ea',
|
||||
// it means the target address of a branch/jump
|
||||
// is already known. That's there to help the 'emu'
|
||||
// module propagate M&X flags & status.
|
||||
#define full_target_ea specval
|
||||
|
||||
|
||||
// Is indirect memory reference?
|
||||
#define indirect segpref
|
||||
|
||||
// These defines are used by some 6502 asm_t descriptors.
|
||||
// Although this is primarily a 65816 module, they'll
|
||||
// remain here since at some point, this CPU module /might/
|
||||
// supersede the 6502 one.
|
||||
// Should that happen, we wouldn't want to waste the
|
||||
// set of asm_t's that are defined for 6502.
|
||||
#define UAS_SECT 0x0002 // Segments are named .SECTION
|
||||
#define UAS_NOSEG 0x0004 // No 'segment' directives
|
||||
#define UAS_SELSG 0x0010 // Segment should be selected by its name
|
||||
#define UAS_CDSEG 0x0080 // Only DSEG,CSEG,XSEG
|
||||
#define UAS_NOENS 0x0200 // don't specify start addr in the .end directive
|
||||
|
||||
|
||||
enum M65816_registers
|
||||
{
|
||||
rA, // Accumulator
|
||||
rX, // X index
|
||||
rY, // Y index
|
||||
rS, // Stack
|
||||
rCs, // code segment
|
||||
rDs, // data segment
|
||||
|
||||
// This will hold the value of B, the
|
||||
// data bank register. We won't make use of Ds
|
||||
// directly, as it is typically used, in computation,
|
||||
// as a 16-byte paragraph register, while B is a
|
||||
// 64KB pages register. Also, by having a dedicated
|
||||
// B, the user will be able to modify it more
|
||||
// easily (without having to manually shift the value by
|
||||
// 12 bits).
|
||||
// Note: Also, we won't have this register ``mapped'' to a sel_t.
|
||||
// We'll stuff the B value in there directly, which allows
|
||||
// it to be more versatile, and access banks where there's
|
||||
// no ROM loaded (such as [S|W]RAM bank(s)).
|
||||
rB,
|
||||
|
||||
// Direct page register. Same note as that of rB applies.
|
||||
rD,
|
||||
|
||||
// These will be considered segment
|
||||
// registers by IDA (just as rCs, rDs, rB and rD),
|
||||
// but we'll actually use them to keep information
|
||||
// about the 'm', 'x' and 'e' flags, determining
|
||||
// what's the accumulator & indices mode, and whether
|
||||
// we run in 6502 emulation or 65816 native mode.
|
||||
rFm,
|
||||
rFx,
|
||||
rFe,
|
||||
|
||||
// program bank register
|
||||
rPB
|
||||
};
|
||||
|
||||
|
||||
// Addressing modes
|
||||
enum m65_addrmode_t
|
||||
{
|
||||
ABS = 0,
|
||||
ABS_IX,
|
||||
ABS_IY,
|
||||
ABS_IX_INDIR,
|
||||
ABS_INDIR,
|
||||
ABS_INDIR_LONG,
|
||||
ABS_LONG,
|
||||
ABS_LONG_IX,
|
||||
ACC,
|
||||
BLK_MOV,
|
||||
DP,
|
||||
DP_IX,
|
||||
DP_IY,
|
||||
DP_IX_INDIR,
|
||||
DP_INDIR,
|
||||
DP_INDIR_LONG,
|
||||
DP_INDIR_IY,
|
||||
DP_INDIR_LONG_IY,
|
||||
IMM,
|
||||
IMPLIED,
|
||||
PC_REL,
|
||||
PC_REL_LONG,
|
||||
STACK_ABS,
|
||||
STACK_DP_INDIR,
|
||||
STACK_INT,
|
||||
STACK_PC_REL,
|
||||
STACK_PULL,
|
||||
STACK_PUSH,
|
||||
STACK_RTI,
|
||||
STACK_RTL,
|
||||
STACK_RTS,
|
||||
STACK_REL,
|
||||
STACK_REL_INDIR_IY,
|
||||
ADDRMODE_last
|
||||
};
|
||||
|
||||
// The various phrases that can be used in case
|
||||
// an operand is of type 'o_displ'.
|
||||
enum odispl_phrases_t
|
||||
{
|
||||
rDX = 100, // "dp, X" DP_IX
|
||||
rDY, // "dp, Y" DP_IY
|
||||
riDX, // "(dp, X)" DP_IX_INDIR
|
||||
rAbsi, // "(abs)" ABS_INDIR
|
||||
rAbsiL, // "long(abs)" ABS_INDIR_LONG
|
||||
rAbsX, // "abs, X" ABS_IX
|
||||
rAbsY, // "abs, Y" ABS_IY
|
||||
rAbsLX, // "long abs, X" ABS_LONG_IX
|
||||
rAbsXi, // "(abs,X)" ABS_IX_INDIR
|
||||
rDi, // "(dp,n)" DP_INDIR
|
||||
rDiL, // "long(dp,n)" DP_INDIR_LONG
|
||||
rDiY, // "(dp,n), Y" DP_INDIR_IY
|
||||
rDiLY, // "long(dp,n), Y" DP_INDIR_LONG_IY
|
||||
rSiY, // (s,n),Y STACK_REL_INDIR_IY
|
||||
rSDi // "(dp,n)" STACK_DP_INDIR
|
||||
};
|
||||
|
||||
|
||||
// Information about addressing modes.
|
||||
struct addrmode_info_t
|
||||
{
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern const struct addrmode_info_t AddressingModes[];
|
||||
|
||||
|
||||
// The type of m65* processors. Used
|
||||
// to declare availability of certain opcodes depending
|
||||
// on the processor.
|
||||
enum m65_variant_t
|
||||
{
|
||||
M6502 = 1,
|
||||
M65C02 = 2,
|
||||
M65802 = 4,
|
||||
M65816 = 8,
|
||||
M6X = 1 | 2 | 4 | 8
|
||||
};
|
||||
|
||||
|
||||
// Special flags, for certain opcodes
|
||||
enum opcode_flags_t
|
||||
{
|
||||
// Increment instruction's byte count
|
||||
// if accumulator is in 16-bits mode.
|
||||
ACC16_INCBC = 1,
|
||||
|
||||
// Increment instruction's byte count
|
||||
// if X/Y registers are in 16-bits mode.
|
||||
XY16_INCBC = 2
|
||||
};
|
||||
|
||||
// Information about an opcode
|
||||
struct opcode_info_t
|
||||
{
|
||||
m65_itype_t itype;
|
||||
m65_addrmode_t addr;
|
||||
uint8 cpu_variants; // OR'd m65_variant_t
|
||||
uint16 flags; // OR'd opcode_flags_t
|
||||
};
|
||||
|
||||
inline bool is_acc_16_bits(ea_t ea) { return (get_sreg(ea, rFm) == 0); }
|
||||
inline bool is_xy_16_bits(ea_t ea) { return (get_sreg(ea, rFx) == 0); }
|
||||
inline bool is_acc_16_bits(const insn_t &insn) { return is_acc_16_bits(insn.ea); }
|
||||
inline bool is_xy_16_bits(const insn_t &insn) { return is_xy_16_bits(insn.ea); }
|
||||
|
||||
const struct opcode_info_t &get_opcode_info(uint8 opcode);
|
||||
|
||||
// Determines whether an m65_itype_t is of type 'push'
|
||||
#define M65_ITYPE_PUSH(op) \
|
||||
(((op) == M65816_pea) \
|
||||
|| ((op) == M65816_pei) \
|
||||
|| ((op) == M65816_per) \
|
||||
|| ((op) == M65816_pha) \
|
||||
|| ((op) == M65816_phb) \
|
||||
|| ((op) == M65816_phd) \
|
||||
|| ((op) == M65816_phk) \
|
||||
|| ((op) == M65816_php) \
|
||||
|| ((op) == M65816_phx) \
|
||||
|| ((op) == M65816_phy))
|
||||
|
||||
// Determines whether an m65_itype_t is of type 'pull'
|
||||
#define M65_ITYPE_PULL(op) \
|
||||
(((op) == M65816_pla) \
|
||||
|| ((op) == M65816_plb) \
|
||||
|| ((op) == M65816_pld) \
|
||||
|| ((op) == M65816_plp) \
|
||||
|| ((op) == M65816_plx) \
|
||||
|| ((op) == M65816_ply))
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi ana(insn_t *_insn);
|
||||
int idaapi emu(const insn_t &insn);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class snes_addr_t;
|
||||
|
||||
struct m65816_iohandler_t : public iohandler_t
|
||||
{
|
||||
m65816_iohandler_t(netnode &nn) : iohandler_t(nn) {}
|
||||
|
||||
virtual bool check_ioresp() const override
|
||||
{
|
||||
if ( inf_like_binary() )
|
||||
return true;
|
||||
else
|
||||
return get_segm_by_name("ppu") != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(idb_listener_t, struct m65816_t);
|
||||
|
||||
struct m65816_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
m65816_iohandler_t ioh = m65816_iohandler_t(helper);
|
||||
idb_listener_t idb_listener = idb_listener_t(*this);
|
||||
struct SuperFamicomCartridge *cartridge = nullptr;
|
||||
snes_addr_t *sa = nullptr;
|
||||
bool flow = false;
|
||||
|
||||
m65816_t();
|
||||
~m65816_t();
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
ea_t xlat(ea_t address);
|
||||
|
||||
void handle_operand(const op_t &x, bool read_access, const insn_t &insn);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void m65816_assumes(outctx_t &ctx);
|
||||
ea_t calc_addr(const op_t &x, ea_t *orig_ea, const insn_t &insn);
|
||||
void m65816_header(outctx_t &ctx) const;
|
||||
void m65816_segstart(outctx_t &ctx, segment_t *Srange) const;
|
||||
void m65816_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
#endif
|
||||
75
idasdk76/module/65816/makefile
Normal file
75
idasdk76/module/65816/makefile
Normal file
@@ -0,0 +1,75 @@
|
||||
PROC=m65816
|
||||
CONFIGS=m65816.cfg
|
||||
O1=bt
|
||||
|
||||
|
||||
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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp ana.cpp ins.hpp \
|
||||
m65816.hpp
|
||||
$(F)bt$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp bt.cpp bt.hpp \
|
||||
ins.hpp m65816.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp bt.hpp emu.cpp \
|
||||
ins.hpp m65816.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp ins.cpp ins.hpp \
|
||||
m65816.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp bt.hpp ins.hpp \
|
||||
m65816.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../ldr/snes/addr.cpp ../../ldr/snes/super-famicom.hpp \
|
||||
../../module/idaidp.hpp ../iohandler.hpp ins.hpp \
|
||||
m65816.hpp reg.cpp
|
||||
473
idasdk76/module/65816/out.cpp
Normal file
473
idasdk76/module/65816/out.cpp
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "bt.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_m65816_t : public outctx_t
|
||||
{
|
||||
out_m65816_t(void) = delete; // not used
|
||||
m65816_t &pm() { return *static_cast<m65816_t *>(procmod); }
|
||||
public:
|
||||
void out_dp(const op_t &x);
|
||||
void out_addr_near_b(const op_t &x);
|
||||
void out_addr_near(const op_t &x);
|
||||
void out_addr_far(const op_t &x);
|
||||
void print_orig_ea(const op_t &x);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_m65816_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_m65816_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_dp(const op_t &x)
|
||||
{
|
||||
sel_t dp = get_sreg(insn.ea, rD);
|
||||
if ( dp != BADSEL )
|
||||
{
|
||||
ea_t orig_ea = dp + x.addr;
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_addr_near_b(const op_t &x)
|
||||
{
|
||||
sel_t db = get_sreg(insn.ea, rB);
|
||||
if ( db != BADSEL )
|
||||
{
|
||||
ea_t orig_ea = (db << 16) + x.addr;
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_16);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void out_m65816_t::out_addr_near(const op_t &x)
|
||||
{
|
||||
ea_t orig_ea = map_code_ea(insn, x);
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_addr_far(const op_t &x)
|
||||
{
|
||||
ea_t orig_ea = x.addr;
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_24);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::print_orig_ea(const op_t &x)
|
||||
{
|
||||
if ( !has_cmt(F) )
|
||||
{
|
||||
char buf[64];
|
||||
qsnprintf(buf, sizeof(buf),
|
||||
COLSTR(" %s orig=0x%0*a", SCOLOR_AUTOCMT),
|
||||
ash.cmnt,
|
||||
(x.type == o_far || x.type == o_mem_far) ? 6 : 4,
|
||||
x.addr);
|
||||
out_line(buf);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t m65816_t::calc_addr(const op_t &x, ea_t *orig_ea, const insn_t &insn)
|
||||
{
|
||||
ea_t ea;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_near:
|
||||
ea = map_code_ea(insn, x);
|
||||
goto XLAT_ADDR;
|
||||
case o_far:
|
||||
case o_mem_far:
|
||||
ea = x.addr;
|
||||
goto XLAT_ADDR;
|
||||
case o_mem:
|
||||
ea = map_data_ea(insn, x);
|
||||
XLAT_ADDR:
|
||||
if ( orig_ea != NULL )
|
||||
*orig_ea = ea;
|
||||
return xlat(ea);
|
||||
default:
|
||||
INTERR(559);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_m65816_t::out_operand(const op_t &x)
|
||||
{
|
||||
ea_t ea, orig_ea;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
break;
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, 0);
|
||||
break;
|
||||
case o_near:
|
||||
case o_far:
|
||||
if ( insn.indirect )
|
||||
out_symbol('(');
|
||||
ea = pm().calc_addr(x, &orig_ea, insn);
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
uint32 v = x.addr;
|
||||
if ( x.type == o_far )
|
||||
v &= 0xFFFFFF;
|
||||
else
|
||||
v &= 0xFFFF;
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(v, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
if ( insn.indirect )
|
||||
out_symbol(')');
|
||||
if ( orig_ea != ea )
|
||||
print_orig_ea(x);
|
||||
break;
|
||||
case o_mem:
|
||||
case o_mem_far:
|
||||
{
|
||||
if ( insn.indirect )
|
||||
out_symbol('(');
|
||||
|
||||
if ( x.type == o_mem_far )
|
||||
{
|
||||
ea = pm().calc_addr(x, &orig_ea, insn);
|
||||
out_addr_far(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
sel_t db = get_sreg(insn.ea, rB);
|
||||
if ( db == BADSEL )
|
||||
ea = orig_ea = x.addr;
|
||||
else
|
||||
ea = pm().calc_addr(x, &orig_ea, insn);
|
||||
out_addr_near_b(x);
|
||||
}
|
||||
|
||||
if ( insn.indirect )
|
||||
out_symbol(')');
|
||||
|
||||
if ( orig_ea != ea )
|
||||
print_orig_ea(x);
|
||||
}
|
||||
break;
|
||||
case o_displ:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case rS:
|
||||
out_register(ph.reg_names[x.phrase]);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
break;
|
||||
case rD:
|
||||
out_register(ph.reg_names[x.phrase]);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
break;
|
||||
case rSiY:
|
||||
out_symbol('(');
|
||||
out_register("S");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("Y");
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rDi:
|
||||
case rSDi:
|
||||
out_symbol('(');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rDiL:
|
||||
out_symbol('[');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(']');
|
||||
break;
|
||||
case rDX:
|
||||
case rDY:
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register((x.phrase == rDX) ? "X" : "Y");
|
||||
break;
|
||||
case riDX:
|
||||
out_symbol('(');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("X");
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rDiY:
|
||||
case rDiLY:
|
||||
out_symbol(x.phrase == rDiLY ? '[' : '(');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(x.phrase == rDiLY ? ']' : ')');
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("Y");
|
||||
break;
|
||||
case rAbsi:
|
||||
out_symbol('(');
|
||||
out_addr_near_b(x);
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rAbsiL:
|
||||
out_symbol('[');
|
||||
out_addr_near_b(x);
|
||||
out_symbol(']');
|
||||
break;
|
||||
case rAbsX:
|
||||
case rAbsY:
|
||||
out_addr_near_b(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register(x.phrase == rAbsY ? "Y" : "X");
|
||||
break;
|
||||
case rAbsLX:
|
||||
{
|
||||
ea_t lorig_ea = x.addr;
|
||||
ea_t lea = pm().xlat(lorig_ea);
|
||||
|
||||
out_addr_far(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("X");
|
||||
|
||||
if ( lorig_ea != lea )
|
||||
print_orig_ea(x);
|
||||
}
|
||||
break;
|
||||
case rAbsXi:
|
||||
out_symbol('(');
|
||||
out_addr_near(x); // jmp, jsr
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("X");
|
||||
out_symbol(')');
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case o_void:
|
||||
return 0;
|
||||
default:
|
||||
err:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool forced_print(flags_t F, int reg)
|
||||
{
|
||||
return (reg == rFm || reg == rFx) && is_func(F);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
void m65816_t::m65816_assumes(outctx_t &ctx)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
char buf[MAXSTR];
|
||||
char *ptr = buf;
|
||||
char *end = buf + sizeof(buf);
|
||||
segment_t *seg = getseg(ea);
|
||||
bool seg_started = (ea == seg->start_ea);
|
||||
for ( int reg=ph.reg_first_sreg; reg <= ph.reg_last_sreg; reg++ )
|
||||
{
|
||||
if ( reg == rCs )
|
||||
continue;
|
||||
sreg_range_t srrange;
|
||||
if ( !get_sreg_range(&srrange, ea, reg) )
|
||||
continue;
|
||||
sel_t curval = srrange.val;
|
||||
if ( seg_started || srrange.start_ea == ea )
|
||||
{
|
||||
sreg_range_t prev;
|
||||
bool prev_exists = get_sreg_range(&prev, ea - 1, reg);
|
||||
if ( seg_started
|
||||
|| (prev_exists && prev.val != curval)
|
||||
|| forced_print(ctx.F, reg) )
|
||||
{
|
||||
if ( reg == rFm || reg == rFx )
|
||||
{
|
||||
ctx.gen_printf(0, ".%c%d", reg == rFm ? 'A' : 'I', curval > 0 ? 8 : 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ptr != buf )
|
||||
APPCHAR(ptr, end, ' ');
|
||||
ptr += qsnprintf(ptr, end-ptr, "%s=%a", ph.reg_names[reg], curval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ptr != buf )
|
||||
ctx.gen_cmt_line("%s", buf);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m65816_t::m65816_header(outctx_t &ctx) const
|
||||
{
|
||||
ctx.gen_cmt_line("%s Processor: %s", ash.cmnt, inf_get_procname().c_str());
|
||||
ctx.gen_cmt_line("%s Target assembler: %s", ash.cmnt, ash.name);
|
||||
if ( ash.header != NULL )
|
||||
for ( const char *const *ptr=ash.header; *ptr != NULL; ptr++ )
|
||||
ctx.flush_buf(*ptr,0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Srange) could be made const
|
||||
void m65816_t::m65816_segstart(outctx_t &ctx, segment_t *Srange) const
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, Srange);
|
||||
if ( ash.uflag & UAS_SECT )
|
||||
{
|
||||
ctx.gen_printf(0, COLSTR("%s: .section",SCOLOR_ASMDIR), name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s.segment %s",SCOLOR_ASMDIR),
|
||||
(ash.uflag & UAS_NOSEG) ? ash.cmnt : "",
|
||||
name.c_str());
|
||||
if ( ash.uflag & UAS_SELSG )
|
||||
ctx.flush_buf(name.c_str(), DEFAULT_INDENT);
|
||||
if ( ash.uflag & UAS_CDSEG )
|
||||
ctx.flush_buf(COLSTR("CSEG",SCOLOR_ASMDIR), DEFAULT_INDENT); // XSEG - eXternal memory
|
||||
}
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Srange);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s",SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m65816_t::m65816_footer(outctx_t &ctx) const
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
char *ptr = buf;
|
||||
char *end = buf + sizeof(buf);
|
||||
APPEND(ptr, end, ash.end);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
if ( ash.uflag & UAS_NOENS )
|
||||
APPEND(ptr, end, ash.cmnt);
|
||||
APPCHAR(ptr, end, ' ');
|
||||
APPEND(ptr, end, name.begin());
|
||||
}
|
||||
ctx.flush_buf(buf, DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
705
idasdk76/module/65816/reg.cpp
Normal file
705
idasdk76/module/65816/reg.cpp
Normal file
@@ -0,0 +1,705 @@
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
|
||||
#include "m65816.hpp"
|
||||
int data_id;
|
||||
|
||||
#include "../../ldr/snes/addr.cpp"
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"A", // Accumulator
|
||||
"X", // Index
|
||||
"Y", // Index
|
||||
"S", // Stack register (used?)
|
||||
"cs",
|
||||
"ds",
|
||||
|
||||
"B", // Data bank
|
||||
"D", // Direct page register (used?)
|
||||
|
||||
"m", // Holds accumulator-is-8-bits flag
|
||||
"x", // Holds indices-are-8-bits flag
|
||||
"e", // Holds emulation mode flag
|
||||
|
||||
"PB" // Program bank
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
ea_t m65816_t::xlat(ea_t address)
|
||||
{
|
||||
return sa->xlat(address);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
m65816_t::m65816_t()
|
||||
{
|
||||
cartridge = new SuperFamicomCartridge;
|
||||
sa = new snes_addr_t;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
m65816_t::~m65816_t()
|
||||
{
|
||||
delete cartridge;
|
||||
cartridge = nullptr;
|
||||
delete sa;
|
||||
sa = nullptr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handler for: get_autocmt.
|
||||
// Will possibly store a comment in 'buf',
|
||||
// depending on whether an autocmt is deemed necessary
|
||||
// for the current line.
|
||||
//
|
||||
// For the moment this will just print, in a user-friendly
|
||||
// way, information about the addressing mode, if needed.
|
||||
static bool make_insn_cmt(qstring *buf, const insn_t &insn)
|
||||
{
|
||||
uint8 opcode = get_byte(insn.ea);
|
||||
const struct opcode_info_t &opcode_info = get_opcode_info(opcode);
|
||||
static const bool addressing_info_required[] =
|
||||
{
|
||||
false, // ABS
|
||||
false, // ABS_IX,
|
||||
false, // ABS_IY,
|
||||
false, // ABS_IX_INDIR,
|
||||
false, // ABS_INDIR,
|
||||
false, // ABS_INDIR_LONG,
|
||||
false, // ABS_LONG,
|
||||
false, // ABS_LONG_IX,
|
||||
false, // ACC,
|
||||
true, // BLK_MOV,
|
||||
false, // DP,
|
||||
false, // DP_IX,
|
||||
false, // DP_IY,
|
||||
false, // DP_IX_INDIR,
|
||||
false, // DP_INDIR,
|
||||
false, // DP_INDIR_LONG,
|
||||
false, // DP_INDIR_IY,
|
||||
false, // DP_INDIR_LONG_IY,
|
||||
false, // IMM,
|
||||
false, // IMPLIED,
|
||||
true, // PC_REL,
|
||||
true, // PC_REL_LONG,
|
||||
false, // STACK_ABS,
|
||||
false, // STACK_DP_INDIR,
|
||||
false, // STACK_INT,
|
||||
false, // STACK_PC_REL,
|
||||
false, // STACK_PULL,
|
||||
false, // STACK_PUSH,
|
||||
false, // STACK_RTI,
|
||||
false, // STACK_RTL,
|
||||
false, // STACK_RTS,
|
||||
false, // STACK_REL,
|
||||
false // STACK_REL_INDIR_IY,
|
||||
};
|
||||
|
||||
if ( !addressing_info_required[opcode_info.addr] )
|
||||
return false;
|
||||
|
||||
const struct addrmode_info_t &addrmode_info = AddressingModes[opcode_info.addr];
|
||||
*buf = addrmode_info.name;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case idb_event::sgr_changed:
|
||||
{
|
||||
ea_t start_ea = va_arg(va, ea_t);
|
||||
ea_t dummy = va_arg(va, ea_t); qnotused(dummy);
|
||||
int regnum = va_arg(va, int);
|
||||
sel_t value = va_arg(va, sel_t);
|
||||
if ( regnum == rB )
|
||||
{
|
||||
// sel_t d2 = va_arg(va, sel_t); qnotused(d2);
|
||||
if ( value == BADSEL )
|
||||
split_sreg_range(start_ea, rDs, BADSEL, SR_auto);
|
||||
else
|
||||
split_sreg_range(start_ea, rDs, value << 12, SR_auto);
|
||||
}
|
||||
else if ( regnum == rPB )
|
||||
{
|
||||
uint16 offset = start_ea & 0xffff;
|
||||
ea_t newEA = pm.xlat((value << 16) + offset);
|
||||
if ( start_ea != newEA )
|
||||
warning("Inconsistent program bank number ($%02X:%04X != $%02X:%04X)",
|
||||
uint32(start_ea >> 16),
|
||||
offset,
|
||||
uint8(value),
|
||||
offset);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void m65816_t::load_from_idb()
|
||||
{
|
||||
cartridge->read_hash(helper);
|
||||
//cartridge.print();
|
||||
if ( !sa->addr_init(*cartridge) )
|
||||
warning("Unsupported mapper: %s", cartridge->mapper_string());
|
||||
ioh.restore_device(IORESP_NONE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(m65816_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi m65816_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int retcode = 1;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
case processor_t::ev_term:
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
case processor_t::ev_newprc:
|
||||
break;
|
||||
case processor_t::ev_creating_segm:
|
||||
{
|
||||
segment_t *sptr = va_arg(va, segment_t *);
|
||||
|
||||
// default DS is equal to CS
|
||||
sptr->defsr[rDs - ph.reg_first_sreg] = sptr->sel;
|
||||
|
||||
// detect SNES bank 0
|
||||
if ( xlat(0) == (sptr->start_ea & 0xff0000) )
|
||||
{
|
||||
// initial bank must be $00 (especially important on HiROM)
|
||||
// Example: Donkey Kong Country 2 - Emulation_mode_RESET
|
||||
sptr->defsr[rB - ph.reg_first_sreg] = 0;
|
||||
sptr->defsr[rPB - ph.reg_first_sreg] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, set the default bank number from EA
|
||||
uint8 pb = sptr->start_ea >> 16;
|
||||
sptr->defsr[rB - ph.reg_first_sreg] = pb;
|
||||
sptr->defsr[rPB - ph.reg_first_sreg] = pb;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
cartridge->read_hash(helper);
|
||||
//cartridge.print();
|
||||
if ( !sa->addr_init(*cartridge) )
|
||||
warning("Unsupported mapper: %s", cartridge->mapper_string());
|
||||
|
||||
const char *device_ptr = nullptr;
|
||||
if ( cartridge->has_superfx )
|
||||
device_ptr = "superfx";
|
||||
else if ( cartridge->has_sa1 )
|
||||
device_ptr = "sa1";
|
||||
else if ( cartridge->has_cx4 )
|
||||
device_ptr = "cx4";
|
||||
else if ( cartridge->has_spc7110 )
|
||||
device_ptr = "spc7110";
|
||||
else if ( cartridge->has_sdd1 )
|
||||
device_ptr = "sdd1";
|
||||
else if ( cartridge->has_sharprtc )
|
||||
device_ptr = "sharprtc";
|
||||
else if ( cartridge->has_epsonrtc )
|
||||
device_ptr = "epsonrtc";
|
||||
else if ( cartridge->has_obc1 )
|
||||
device_ptr = "obc1";
|
||||
else if ( cartridge->has_dsp1 )
|
||||
device_ptr = "dsp1";
|
||||
else if ( cartridge->has_dsp2 )
|
||||
device_ptr = "dsp2";
|
||||
else if ( cartridge->has_dsp3 )
|
||||
device_ptr = "dsp3";
|
||||
else if ( cartridge->has_dsp4 )
|
||||
device_ptr = "dsp4";
|
||||
else if ( cartridge->has_st010 )
|
||||
device_ptr = "st010";
|
||||
else if ( cartridge->has_st011 )
|
||||
device_ptr = "st011";
|
||||
else if ( cartridge->has_st018 )
|
||||
device_ptr = "st018";
|
||||
qstring loader_device;
|
||||
if ( device_ptr == nullptr )
|
||||
{
|
||||
ssize_t len = helper.hashstr(&loader_device, "device");
|
||||
if ( len <= 0 )
|
||||
device_ptr = "65816";
|
||||
else
|
||||
device_ptr = loader_device.c_str();
|
||||
}
|
||||
ioh.set_device_name(device_ptr, IORESP_ALL);
|
||||
|
||||
set_default_sreg_value(NULL, rFm, 1);
|
||||
set_default_sreg_value(NULL, rFx, 1);
|
||||
set_default_sreg_value(NULL, rFe, 1);
|
||||
set_default_sreg_value(NULL, rD, 0);
|
||||
|
||||
// see processor_t::ev_creating_segm for the following registers
|
||||
//set_default_sreg_value(NULL, rPB, 0);
|
||||
//set_default_sreg_value(NULL, rB, 0);
|
||||
//set_default_sreg_value(NULL, rDs, 0);
|
||||
|
||||
if ( inf_get_start_ip() != BADADDR )
|
||||
{
|
||||
ea_t reset_ea = xlat(inf_get_start_ip());
|
||||
ea_t sea = getseg(reset_ea)->start_ea;
|
||||
split_sreg_range(reset_ea, rFm, get_sreg(sea, rFm), SR_auto);
|
||||
split_sreg_range(reset_ea, rFx, get_sreg(sea, rFx), SR_auto);
|
||||
split_sreg_range(reset_ea, rFe, get_sreg(sea, rFe), SR_auto);
|
||||
split_sreg_range(reset_ea, rPB, 0, SR_auto);
|
||||
split_sreg_range(reset_ea, rB, 0, SR_auto);
|
||||
split_sreg_range(reset_ea, rD, get_sreg(sea, rD), SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
{
|
||||
load_from_idb();
|
||||
if ( msgid == processor_t::ev_oldfile )
|
||||
{ // read rommode_t for backward compatibility
|
||||
nodeidx_t mode = helper.hashval_long("rommode_t");
|
||||
if ( mode != 0 )
|
||||
{
|
||||
switch ( mode )
|
||||
{
|
||||
case 0x20:
|
||||
cartridge->mapper = SuperFamicomCartridge::LoROM;
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
cartridge->mapper = SuperFamicomCartridge::HiROM;
|
||||
break;
|
||||
}
|
||||
helper.hashdel("rommode_t");
|
||||
cartridge->write_hash(helper);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_get_autocmt:
|
||||
{
|
||||
qstring *buf = va_arg(va, qstring *);
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
if ( make_insn_cmt(buf, *insn) )
|
||||
retcode = 1;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_may_be_func:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
retcode = 0;
|
||||
ea_t cref_addr;
|
||||
for ( cref_addr = get_first_cref_to(insn->ea);
|
||||
cref_addr != BADADDR;
|
||||
cref_addr = get_next_cref_to(insn->ea, cref_addr) )
|
||||
{
|
||||
uint8 opcode = get_byte(cref_addr);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(opcode);
|
||||
if ( opinfo.itype == M65816_jsl
|
||||
|| opinfo.itype == M65816_jsr
|
||||
|| opinfo.itype == M65816_jml )
|
||||
{
|
||||
retcode = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_is_call_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(get_byte(insn->ea));
|
||||
if ( opinfo.itype == M65816_jsr
|
||||
|| opinfo.itype == M65816_jsl )
|
||||
retcode = 1;
|
||||
else
|
||||
retcode = -1;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_is_ret_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(get_byte(insn->ea));
|
||||
if ( opinfo.itype == M65816_rti
|
||||
|| opinfo.itype == M65816_rtl
|
||||
|| opinfo.itype == M65816_rts )
|
||||
retcode = 1;
|
||||
else
|
||||
retcode = -1;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_is_indirect_jump:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(get_byte(insn->ea));
|
||||
if ( opinfo.itype == M65816_jmp
|
||||
|| opinfo.itype == M65816_jml )
|
||||
{
|
||||
if ( opinfo.addr == ABS_INDIR
|
||||
|| opinfo.addr == ABS_IX_INDIR
|
||||
|| opinfo.addr == ABS_INDIR_LONG )
|
||||
retcode = 2;
|
||||
else
|
||||
retcode = 1;
|
||||
}
|
||||
else
|
||||
retcode = 0;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m65816_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m65816_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 *);
|
||||
m65816_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_assumes:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m65816_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;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
retcode = 0;
|
||||
break;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// CA65 ASSEMBLER
|
||||
//
|
||||
// http://www.cc65.org/doc/ca65-4.html#ss4.1
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t ca65asm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF4, // Assembler features
|
||||
0, // User-defined flags
|
||||
"CA65 ASSEMBLER", // Name
|
||||
0,
|
||||
NULL, // 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
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// PseudoSam
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const ps_headers[] =
|
||||
{
|
||||
".code",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t pseudosam =
|
||||
{
|
||||
AS_COLON | ASH_HEXF1 | AS_N2CHR | AS_NOXRF,
|
||||
UAS_SELSG,
|
||||
"PseudoSam by PseudoCode",
|
||||
0,
|
||||
ps_headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".db", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
NULL, // 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(...)
|
||||
".rs %s", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // seg prefix
|
||||
NULL, // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// SVENSON ELECTRONICS 6502/65C02 ASSEMBLER - V.1.0 - MAY, 1988
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t svasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF4,
|
||||
UAS_NOSEG,
|
||||
"SVENSON ELECTRONICS 6502/65C02 ASSEMBLER - V.1.0 - MAY, 1988",
|
||||
0,
|
||||
NULL, // headers
|
||||
"* = ",
|
||||
".END",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\'", // special symbols in char and string constants
|
||||
|
||||
".BYTE", // ascii string directive
|
||||
".BYTE", // byte directive
|
||||
".WORD", // word directive
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// TASM assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t tasm =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_NOENS | UAS_NOSEG,
|
||||
"Table Driven Assembler (TASM) by Speech Technology Inc.",
|
||||
0,
|
||||
NULL, // headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".text", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
NULL, // 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(...)
|
||||
".block %s", // uninited arrays
|
||||
".equ",
|
||||
NULL, // seg prefix
|
||||
NULL, // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
"and", // and
|
||||
"or", // or
|
||||
NULL, // xor
|
||||
"not", // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Avocet assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t avocet =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_NOENS | UAS_NOSEG,
|
||||
"Avocet Systems 2500AD 6502 Assembler",
|
||||
0,
|
||||
NULL, // headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".fcc", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
NULL, // 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(...)
|
||||
".ds %s", // uninited arrays
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] =
|
||||
{
|
||||
&ca65asm,
|
||||
|
||||
// 6502 asm_t; imported from the 6502 CPU module.
|
||||
&svasm,
|
||||
&tasm,
|
||||
&pseudosam,
|
||||
&avocet,
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "MOS Technology 658xx series:"
|
||||
static const char *const shnames[] = { "m65816", "m65c816", NULL };
|
||||
static const char *const lnames[] = { FAMILY"MOS Technology 65816", "MOS Technology 65C816", NULL };
|
||||
|
||||
static const uchar retcode_1[] = { 0x60 }; // RTS
|
||||
static const uchar retcode_2[] = { 0x40 }; // RTI
|
||||
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 }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_65C816, // id
|
||||
// flag
|
||||
PR_SEGS
|
||||
| PR_SEGTRANS,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
RegNames, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rCs, // first segreg
|
||||
rPB, // last segreg
|
||||
0, // size of a segment register
|
||||
rCs, // number of CS register
|
||||
rDs, // number of DS register
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0,
|
||||
M65816_last,
|
||||
Instructions, // instruc
|
||||
3, // int tbyte_size; -- doesn't exist
|
||||
|
||||
{ 0, 0, 0, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
M65816_rts, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user