update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

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

View 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

View 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

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

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

View 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

View 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

View 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

View 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

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

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