update to ida 7.6, add builds
This commit is contained in:
650
idasdk76/module/h8500/ana.cpp
Normal file
650
idasdk76/module/h8500/ana.cpp
Normal file
@@ -0,0 +1,650 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Hitchi H8
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h8500.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#define MAP3 ushort(-3)
|
||||
#define MAP4 ushort(-4)
|
||||
#define MAP5 ushort(-5)
|
||||
#define MAP6 ushort(-6)
|
||||
|
||||
static const ushort A2[] =
|
||||
{
|
||||
/* 00 */ H8500_nop, MAP6, H8500_ldm, H8500_pjsr, MAP5, MAP4, MAP6, MAP6,
|
||||
/* 08 */ H8500_trapa, H8500_trap_vs, H8500_rte, H8500_bpt, MAP5, MAP4, H8500_bsr, H8500_unlk,
|
||||
/* 10 */ H8500_jmp, MAP6, H8500_stm, H8500_pjmp, H8500_rtd, MAP4, H8500_null, H8500_link,
|
||||
/* 18 */ H8500_jsr, H8500_rts, H8500_sleep, H8500_null, H8500_rtd, MAP4, H8500_bsr, H8500_link,
|
||||
/* 20 */ H8500_bra, H8500_brn, H8500_bhi, H8500_bls, H8500_bcc, H8500_bcs, H8500_bne, H8500_beq,
|
||||
/* 28 */ H8500_bvc, H8500_bvs, H8500_bpl, H8500_bmi, H8500_bge, H8500_blt, H8500_bgt, H8500_ble,
|
||||
/* 30 */ H8500_bra, H8500_brn, H8500_bhi, H8500_bls, H8500_bcc, H8500_bcs, H8500_bne, H8500_beq,
|
||||
/* 38 */ H8500_bvc, H8500_bvs, H8500_bpl, H8500_bmi, H8500_bge, H8500_blt, H8500_bgt, H8500_ble,
|
||||
/* 40 */ H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e,
|
||||
/* 48 */ H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i,
|
||||
/* 50 */ H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e,
|
||||
/* 58 */ H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i,
|
||||
};
|
||||
|
||||
static const ushort A2tail[] =
|
||||
{
|
||||
/* 60 */ H8500_mov_l,
|
||||
/* 70 */ H8500_mov_s,
|
||||
/* 80 */ H8500_mov_f,
|
||||
/* 90 */ H8500_mov_f,
|
||||
/* A0 */ MAP3,
|
||||
/* B0 */ MAP4,
|
||||
/* C0 */ MAP4,
|
||||
/* D0 */ MAP4,
|
||||
/* E0 */ MAP4,
|
||||
/* F0 */ MAP4,
|
||||
};
|
||||
|
||||
static const ushort A3[] =
|
||||
{
|
||||
/* 00 */ MAP6, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
/* 08 */ H8500_add_q, H8500_add_q, H8500_null, H8500_null, H8500_add_q, H8500_add_q, H8500_null, H8500_null,
|
||||
/* 10 */ H8500_swap, H8500_exts, H8500_extu, H8500_clr, H8500_neg, H8500_not, H8500_tst, H8500_tas,
|
||||
/* 18 */ H8500_shal, H8500_shar, H8500_shll, H8500_shlr, H8500_rotl, H8500_rotr, H8500_rotxl, H8500_rotxr,
|
||||
};
|
||||
|
||||
static const ushort A3tail[] =
|
||||
{
|
||||
/* 20 */ H8500_add_g, H8500_adds,
|
||||
/* 30 */ H8500_sub, H8500_subs,
|
||||
/* 40 */ H8500_or, H8500_bset,
|
||||
/* 50 */ H8500_and, H8500_bclr,
|
||||
/* 60 */ H8500_xor, H8500_bnot,
|
||||
/* 70 */ H8500_cmp_g, H8500_btst,
|
||||
/* 80 */ H8500_mov_g, H8500_ldc,
|
||||
/* 90 */ H8500_xch, H8500_stc,
|
||||
/* A0 */ H8500_addx, H8500_mulxu,
|
||||
/* B0 */ H8500_subx, H8500_divxu,
|
||||
/* C0 */ H8500_bset, H8500_bset,
|
||||
/* D0 */ H8500_bclr, H8500_bclr,
|
||||
/* E0 */ H8500_bnot, H8500_bnot,
|
||||
/* F0 */ H8500_btst, H8500_btst,
|
||||
};
|
||||
|
||||
static const ushort A4[] =
|
||||
{
|
||||
/* 00 */ MAP6, H8500_null, H8500_null, H8500_null, H8500_cmp_g, H8500_cmp_g, H8500_mov_g, H8500_mov_g,
|
||||
/* 08 */ H8500_add_q, H8500_add_q, H8500_null, H8500_null, H8500_add_q, H8500_add_q, H8500_null, H8500_null,
|
||||
/* 10 */ H8500_null, H8500_null, H8500_null, H8500_clr, H8500_neg, H8500_not, H8500_tst, H8500_tas,
|
||||
/* 18 */ H8500_shal, H8500_shar, H8500_shll, H8500_shlr, H8500_rotl, H8500_rotr, H8500_rotxl, H8500_rotxr,
|
||||
};
|
||||
|
||||
static const ushort A4tail[] =
|
||||
{
|
||||
/* 20 */ H8500_add_g, H8500_adds,
|
||||
/* 30 */ H8500_sub, H8500_subs,
|
||||
/* 40 */ H8500_or, H8500_bset,
|
||||
/* 50 */ H8500_and, H8500_bclr,
|
||||
/* 60 */ H8500_xor, H8500_bnot,
|
||||
/* 70 */ H8500_cmp_g, H8500_btst,
|
||||
/* 80 */ H8500_mov_g, H8500_ldc,
|
||||
/* 90 */ H8500_mov_g, H8500_stc,
|
||||
/* A0 */ H8500_addx, H8500_mulxu,
|
||||
/* B0 */ H8500_subx, H8500_divxu,
|
||||
/* C0 */ H8500_bset, H8500_bset,
|
||||
/* D0 */ H8500_bclr, H8500_bclr,
|
||||
/* E0 */ H8500_bnot, H8500_bnot,
|
||||
/* F0 */ H8500_btst, H8500_btst,
|
||||
};
|
||||
|
||||
static const ushort A5[] =
|
||||
{
|
||||
/* 00 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
/* 08 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
/* 10 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
/* 18 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
};
|
||||
|
||||
static const ushort A5tail[] =
|
||||
{
|
||||
/* 20 */ H8500_add_g, H8500_adds,
|
||||
/* 30 */ H8500_sub, H8500_subs,
|
||||
/* 40 */ H8500_or, H8500_orc,
|
||||
/* 50 */ H8500_and, H8500_andc,
|
||||
/* 60 */ H8500_xor, H8500_xorc,
|
||||
/* 70 */ H8500_cmp_g, H8500_null,
|
||||
/* 80 */ H8500_mov_g, H8500_ldc,
|
||||
/* 90 */ H8500_null, H8500_null,
|
||||
/* A0 */ H8500_addx, H8500_mulxu,
|
||||
/* B0 */ H8500_subx, H8500_divxu,
|
||||
/* C0 */ H8500_null, H8500_null,
|
||||
/* D0 */ H8500_null, H8500_null,
|
||||
/* E0 */ H8500_null, H8500_null,
|
||||
/* F0 */ H8500_null, H8500_null,
|
||||
};
|
||||
|
||||
static const ushort A6[] =
|
||||
{
|
||||
/* 00 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
/* 08 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
|
||||
/* 10 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_prtd, H8500_null, H8500_null, H8500_null,
|
||||
/* 18 */ H8500_null, H8500_prts, H8500_null, H8500_null, H8500_prtd, H8500_null, H8500_null, H8500_null,
|
||||
};
|
||||
|
||||
static const ushort A6tail[] =
|
||||
{
|
||||
/* 20 */ H8500_null, H8500_null,
|
||||
/* 30 */ H8500_null, H8500_null,
|
||||
/* 40 */ H8500_null, H8500_null,
|
||||
/* 50 */ H8500_null, H8500_null,
|
||||
/* 60 */ H8500_null, H8500_null,
|
||||
/* 70 */ H8500_null, H8500_null,
|
||||
/* 80 */ H8500_movfpe, H8500_null,
|
||||
/* 90 */ H8500_movtpe, H8500_null,
|
||||
/* A0 */ H8500_dadd, H8500_null,
|
||||
/* B0 */ H8500_dsub, H8500_scb,
|
||||
/* C0 */ H8500_pjmp, H8500_pjsr,
|
||||
/* D0 */ H8500_jmp, H8500_jsr,
|
||||
/* E0 */ H8500_jmp, H8500_jsr,
|
||||
/* F0 */ H8500_jmp, H8500_jsr,
|
||||
};
|
||||
|
||||
struct tables_t
|
||||
{
|
||||
const ushort *head;
|
||||
const ushort *tail;
|
||||
};
|
||||
|
||||
static const tables_t tables[] =
|
||||
{
|
||||
{ A3, A3tail },
|
||||
{ A4, A4tail },
|
||||
{ A5, A5tail },
|
||||
{ A6, A6tail },
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void immv(op_t &x, int v)
|
||||
{
|
||||
x.type = o_imm;
|
||||
x.dtype = dt_dword;
|
||||
x.value = v;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void imm8(insn_t &insn, op_t &x)
|
||||
{
|
||||
insn.auxpref |= aux_disp8;
|
||||
x.type = o_imm;
|
||||
x.dtype = dt_byte;
|
||||
x.value = insn.get_next_byte();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void imm16(insn_t &insn, op_t &x)
|
||||
{
|
||||
insn.auxpref |= aux_disp16;
|
||||
x.type = o_imm;
|
||||
x.dtype = dt_word;
|
||||
x.value = insn.get_next_word();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opreg(op_t &x, int code, char dtype)
|
||||
{
|
||||
x.type = o_reg;
|
||||
x.dtype = dtype;
|
||||
x.reg = code & 7;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void aa8(insn_t &insn, op_t &x, char dtype)
|
||||
{
|
||||
insn.auxpref |= aux_page|aux_disp8;
|
||||
x.type = o_mem;
|
||||
x.dtype = dtype;
|
||||
x.addr = insn.get_next_byte();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void aa16(insn_t &insn, op_t &x, char dtype)
|
||||
{
|
||||
insn.auxpref |= aux_disp16;
|
||||
x.type = o_mem;
|
||||
x.dtype = dtype;
|
||||
x.addr = insn.get_next_word();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void ds8(insn_t &insn, op_t &x, int reg, char dtype)
|
||||
{
|
||||
insn.auxpref |= aux_disp8;
|
||||
x.type = o_displ;
|
||||
x.dtype = dtype;
|
||||
x.reg = reg & 7;
|
||||
x.addr = insn.get_next_byte();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void ds16(insn_t &insn, op_t &x, int reg, char dtype)
|
||||
{
|
||||
insn.auxpref |= aux_disp16;
|
||||
x.type = o_displ;
|
||||
x.dtype = dtype;
|
||||
x.reg = reg & 7;
|
||||
x.addr = insn.get_next_word();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void phrase(op_t &x, int code, uchar pht, char dtype)
|
||||
{
|
||||
x.type = o_phrase;
|
||||
x.dtype = dtype;
|
||||
x.phrase = code & 7;
|
||||
x.phtype = pht;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void d8(insn_t &insn, op_t &x)
|
||||
{
|
||||
insn.auxpref |= aux_disp8;
|
||||
int32 disp = char(insn.get_next_byte());
|
||||
x.type = o_near;
|
||||
x.dtype = dt_code;
|
||||
x.addr = insn.ip + insn.size + disp;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int h8500_t::h8500_ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
uint8 code = insn.get_next_byte();
|
||||
uint8 saved_code = code;
|
||||
char dtype = dt_byte;
|
||||
if ( code < 0x60 )
|
||||
{
|
||||
insn.itype = A2[code];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( code & 8 )
|
||||
{
|
||||
insn.auxpref |= aux_word;
|
||||
dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.auxpref |= aux_byte;
|
||||
dtype = dt_byte;
|
||||
}
|
||||
insn.itype = A2tail[(code>>4)-6];
|
||||
}
|
||||
if ( insn.itype == H8500_null )
|
||||
return 0;
|
||||
switch ( code )
|
||||
{
|
||||
case 0x02: // ldm.w @sp+, <reglist>
|
||||
// insn.auxpref |= aux_word;
|
||||
phrase(insn.Op1, SP, ph_post, dt_word);
|
||||
insn.Op2.type = o_reglist;
|
||||
insn.Op2.reg = insn.get_next_byte();
|
||||
if ( !insn.Op2.reg )
|
||||
return 0;
|
||||
break;
|
||||
case 0x12: // stm.w <reglist>, @-sp
|
||||
// insn.auxpref |= aux_word;
|
||||
insn.Op1.type = o_reglist;
|
||||
insn.Op1.reg = insn.get_next_byte();
|
||||
if ( !insn.Op1.reg )
|
||||
return 0;
|
||||
phrase(insn.Op2, SP, ph_pre, dt_word);
|
||||
break;
|
||||
case 0x01: // scb/f
|
||||
insn.auxpref |= aux_f;
|
||||
break;
|
||||
case 0x06: // scb/ne
|
||||
insn.auxpref |= aux_ne;
|
||||
break;
|
||||
case 0x07: // scb/eq
|
||||
insn.auxpref |= aux_eq;
|
||||
break;
|
||||
case 0x08: // trapa #xx
|
||||
code = insn.get_next_byte();
|
||||
if ( (code & 0xF0) != 0x10 )
|
||||
return 0;
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op1.value = code & 15;
|
||||
break;
|
||||
case 0x0F: // unlk
|
||||
opreg(insn.Op1, FP, dt_word);
|
||||
break;
|
||||
case 0x10: // jmp @aa:16
|
||||
case 0x18: // jsr @aa:16
|
||||
aa16(insn, insn.Op1, dt_code);
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.addr += insn.ea & ~0xFFFF;
|
||||
break;
|
||||
case 0x17: // link #xx:8
|
||||
opreg(insn.Op1, FP, dt_word);
|
||||
imm8(insn, insn.Op2);
|
||||
break;
|
||||
case 0x1F: // link #xx:16
|
||||
opreg(insn.Op1, FP, dt_word);
|
||||
imm16(insn, insn.Op2);
|
||||
break;
|
||||
case 0x03: // pjsr @aa:24
|
||||
case 0x13: // pjmp @aa:24
|
||||
{
|
||||
insn.auxpref |= aux_disp24;
|
||||
uint32 page = insn.get_next_byte();
|
||||
insn.Op1.type = o_far;
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.addr = (page<<16) | insn.get_next_word();
|
||||
}
|
||||
break;
|
||||
case 0x04: // #xx:8
|
||||
insn.auxpref |= aux_byte;
|
||||
// fallthrough
|
||||
case 0x14: // #xx:8
|
||||
imm8(insn, insn.Op1);
|
||||
break;
|
||||
case 0x05: // #aa:8.B
|
||||
insn.auxpref |= aux_byte;
|
||||
aa8(insn, insn.Op1, dt_byte);
|
||||
break;
|
||||
case 0x15: // #aa:16.B
|
||||
insn.auxpref |= aux_byte;
|
||||
aa16(insn, insn.Op1, dt_byte);
|
||||
break;
|
||||
case 0x0C: // #xx:16
|
||||
insn.auxpref |= aux_word;
|
||||
// fallthrough
|
||||
case 0x1C: // #xx:16
|
||||
imm16(insn, insn.Op1);
|
||||
break;
|
||||
case 0x0D: // #aa:8.W
|
||||
insn.auxpref |= aux_word;
|
||||
aa8(insn, insn.Op1, dt_word);
|
||||
dtype = dt_word;
|
||||
break;
|
||||
case 0x1D: // #aa:16.W
|
||||
insn.auxpref |= aux_word;
|
||||
aa16(insn, insn.Op1, dt_word);
|
||||
dtype = dt_word;
|
||||
break;
|
||||
case 0x0E: // bsr d:8
|
||||
case 0x20: case 0x21: case 0x22: case 0x23: // d:8
|
||||
case 0x24: case 0x25: case 0x26: case 0x27:
|
||||
case 0x28: case 0x29: case 0x2A: case 0x2B:
|
||||
case 0x2C: case 0x2D: case 0x2E: case 0x2F:
|
||||
d8(insn, insn.Op1);
|
||||
break;
|
||||
case 0x1E: // bsr d:16
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: // d:16
|
||||
case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
case 0x38: case 0x39: case 0x3A: case 0x3B:
|
||||
case 0x3C: case 0x3D: case 0x3E: case 0x3F:
|
||||
{
|
||||
insn.auxpref |= aux_disp16;
|
||||
int32 disp = short(insn.get_next_word());
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.addr = insn.ip + insn.size + disp;
|
||||
}
|
||||
break;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: // cmp:e #xx:8, Rn
|
||||
case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: // mov:e #xx:8, Rn
|
||||
case 0x54: case 0x55: case 0x56: case 0x57:
|
||||
insn.auxpref |= aux_byte;
|
||||
imm8(insn, insn.Op1);
|
||||
opreg(insn.Op2, code, dtype);
|
||||
break;
|
||||
case 0x48: case 0x49: case 0x4A: case 0x4B: // cmp:i #xx:16, Rn
|
||||
case 0x4C: case 0x4D: case 0x4E: case 0x4F:
|
||||
case 0x58: case 0x59: case 0x5A: case 0x5B: // mov:i #xx:16, Rn
|
||||
case 0x5C: case 0x5D: case 0x5E: case 0x5F:
|
||||
insn.auxpref |= aux_word;
|
||||
imm16(insn, insn.Op1);
|
||||
opreg(insn.Op2, code, dtype);
|
||||
break;
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: // @aa:8, Rn
|
||||
case 0x64: case 0x65: case 0x66: case 0x67:
|
||||
case 0x68: case 0x69: case 0x6A: case 0x6B:
|
||||
case 0x6C: case 0x6D: case 0x6E: case 0x6F:
|
||||
aa8(insn, insn.Op1, dtype);
|
||||
opreg(insn.Op2, code, dtype);
|
||||
break;
|
||||
case 0x70: case 0x71: case 0x72: case 0x73: // Rn, @aa:8
|
||||
case 0x74: case 0x75: case 0x76: case 0x77:
|
||||
case 0x78: case 0x79: case 0x7A: case 0x7B:
|
||||
case 0x7C: case 0x7D: case 0x7E: case 0x7F:
|
||||
opreg(insn.Op1, code, dtype);
|
||||
aa8(insn, insn.Op2, dtype);
|
||||
break;
|
||||
case 0x80: case 0x81: case 0x82: case 0x83: // mov:f @(d:8, R6), Rn
|
||||
case 0x84: case 0x85: case 0x86: case 0x87:
|
||||
case 0x88: case 0x89: case 0x8A: case 0x8B:
|
||||
case 0x8C: case 0x8D: case 0x8E: case 0x8F:
|
||||
ds8(insn, insn.Op1, R6, dtype);
|
||||
opreg(insn.Op2, code, dtype);
|
||||
break;
|
||||
case 0x90: case 0x91: case 0x92: case 0x93: // mov:f Rn, @(d:8, R6)
|
||||
case 0x94: case 0x95: case 0x96: case 0x97:
|
||||
case 0x98: case 0x99: case 0x9A: case 0x9B:
|
||||
case 0x9C: case 0x9D: case 0x9E: case 0x9F:
|
||||
opreg(insn.Op1, code, dtype);
|
||||
ds8(insn, insn.Op2, R6, dtype);
|
||||
break;
|
||||
case 0xA0: case 0xA1: case 0xA2: case 0xA3: // Rn, Rn
|
||||
case 0xA4: case 0xA5: case 0xA6: case 0xA7:
|
||||
case 0xA8: case 0xA9: case 0xAA: case 0xAB:
|
||||
case 0xAC: case 0xAD: case 0xAE: case 0xAF:
|
||||
opreg(insn.Op1, code, dtype);
|
||||
break;
|
||||
case 0xB0: case 0xB1: case 0xB2: case 0xB3: // @-Rn, Rn
|
||||
case 0xB4: case 0xB5: case 0xB6: case 0xB7:
|
||||
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
|
||||
case 0xBC: case 0xBD: case 0xBE: case 0xBF:
|
||||
phrase(insn.Op1, code, ph_pre, dtype);
|
||||
break;
|
||||
case 0xC0: case 0xC1: case 0xC2: case 0xC3: // @Rn+, Rn
|
||||
case 0xC4: case 0xC5: case 0xC6: case 0xC7:
|
||||
case 0xC8: case 0xC9: case 0xCA: case 0xCB:
|
||||
case 0xCC: case 0xCD: case 0xCE: case 0xCF:
|
||||
phrase(insn.Op1, code, ph_post, dtype);
|
||||
break;
|
||||
case 0xD0: case 0xD1: case 0xD2: case 0xD3: // @Rn, Rn
|
||||
case 0xD4: case 0xD5: case 0xD6: case 0xD7:
|
||||
case 0xD8: case 0xD9: case 0xDA: case 0xDB:
|
||||
case 0xDC: case 0xDD: case 0xDE: case 0xDF:
|
||||
phrase(insn.Op1, code, ph_normal, dtype);
|
||||
break;
|
||||
case 0xE0: case 0xE1: case 0xE2: case 0xE3: // @(d:8,Rn), Rn
|
||||
case 0xE4: case 0xE5: case 0xE6: case 0xE7:
|
||||
case 0xE8: case 0xE9: case 0xEA: case 0xEB:
|
||||
case 0xEC: case 0xED: case 0xEE: case 0xEF:
|
||||
ds8(insn, insn.Op1, code, dtype);
|
||||
break;
|
||||
case 0xF0: case 0xF1: case 0xF2: case 0xF3: // @(d:16,Rn), Rn
|
||||
case 0xF4: case 0xF5: case 0xF6: case 0xF7:
|
||||
case 0xF8: case 0xF9: case 0xFA: case 0xFB:
|
||||
case 0xFC: case 0xFD: case 0xFE: case 0xFF:
|
||||
ds16(insn, insn.Op1, code, dtype);
|
||||
break;
|
||||
}
|
||||
while ( insn.itype > H8500_last ) // while MAPs are not resolved
|
||||
{
|
||||
int index = -(3+short(insn.itype));
|
||||
if ( index < 0 || index >= qnumber(tables) )
|
||||
INTERR(10089);
|
||||
code = insn.get_next_byte();
|
||||
if ( code < 0x20 )
|
||||
{
|
||||
insn.itype = tables[index].head[code];
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = tables[index].tail[(code>>3)-4];
|
||||
opreg(insn.Op2, code, dtype);
|
||||
}
|
||||
if ( index == 3 ) switch ( saved_code ) // MAP6
|
||||
{
|
||||
case 0x01:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
if ( insn.itype != H8500_scb )
|
||||
return 0;
|
||||
break;
|
||||
case 0x11:
|
||||
if ( insn.itype != H8500_prts
|
||||
&& insn.itype != H8500_prtd
|
||||
&& insn.itype != H8500_jmp
|
||||
&& insn.itype != H8500_pjmp
|
||||
&& insn.itype != H8500_jsr
|
||||
&& insn.itype != H8500_pjsr )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ( insn.itype != H8500_movfpe
|
||||
&& insn.itype != H8500_movtpe
|
||||
&& insn.itype != H8500_dadd
|
||||
&& insn.itype != H8500_dsub )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case H8500_null:
|
||||
return 0;
|
||||
case H8500_add_q:
|
||||
insn.Op2 = insn.Op1;
|
||||
switch ( code )
|
||||
{
|
||||
case 0x08: immv(insn.Op1, 1); break;
|
||||
case 0x09: immv(insn.Op1, 2); break;
|
||||
case 0x0C: immv(insn.Op1, -1); break;
|
||||
case 0x0D: immv(insn.Op1, -2); break;
|
||||
}
|
||||
break;
|
||||
case H8500_bset:
|
||||
case H8500_bclr:
|
||||
case H8500_bnot:
|
||||
case H8500_btst:
|
||||
insn.Op2 = insn.Op1;
|
||||
if ( code < 0xC0 )
|
||||
opreg(insn.Op1, code, dtype);
|
||||
else
|
||||
immv(insn.Op1, code & 15);
|
||||
break;
|
||||
case H8500_mov_g:
|
||||
if ( (code & 0xF8) == 0x80 )
|
||||
break;
|
||||
insn.Op2 = insn.Op1;
|
||||
if ( code == 0x06 )
|
||||
{
|
||||
if ( (insn.auxpref & aux_word) == 0 )
|
||||
insn.auxpref |= aux_byte;
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
}
|
||||
else if ( code == 0x07 )
|
||||
{
|
||||
if ( (insn.auxpref & aux_byte) == 0 )
|
||||
insn.auxpref |= aux_word;
|
||||
insn.auxpref |= aux_mov16;
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.dtype = dt_word;
|
||||
insn.Op1.value = insn.get_next_word();
|
||||
}
|
||||
else
|
||||
opreg(insn.Op1, code, dtype);
|
||||
break;
|
||||
case H8500_cmp_g:
|
||||
if ( code > 5 )
|
||||
break;
|
||||
insn.Op2 = insn.Op1;
|
||||
if ( code == 0x04 )
|
||||
{
|
||||
insn.auxpref |= aux_byte;
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.auxpref |= aux_word;
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.dtype = dt_word;
|
||||
insn.Op1.value = insn.get_next_word();
|
||||
}
|
||||
break;
|
||||
case H8500_andc:
|
||||
case H8500_orc:
|
||||
case H8500_xorc:
|
||||
case H8500_ldc:
|
||||
case H8500_stc:
|
||||
insn.Op2.reg += SR;
|
||||
if ( insn.Op2.reg == RES1 || insn.Op2.reg == CP )
|
||||
return 0;
|
||||
if ( ((insn.auxpref & aux_word) != 0) != (insn.Op2.reg == SR) )
|
||||
return 0;
|
||||
if ( insn.itype != H8500_stc )
|
||||
break;
|
||||
// no break
|
||||
case H8500_movtpe:
|
||||
{
|
||||
op_t x = insn.Op1;
|
||||
insn.Op1 = insn.Op2;
|
||||
insn.Op2 = x;
|
||||
}
|
||||
break;
|
||||
case H8500_pjmp:
|
||||
case H8500_pjsr:
|
||||
case H8500_jmp:
|
||||
case H8500_jsr:
|
||||
insn.Op2.type = o_void;
|
||||
switch ( code & 0xF0 )
|
||||
{
|
||||
case 0xC0:
|
||||
case 0xD0: phrase(insn.Op1, code, ph_normal, dt_code); break;
|
||||
case 0xE0: ds8(insn, insn.Op1, code, dt_code); break;
|
||||
case 0xF0: ds16(insn, insn.Op1, code, dt_code); break;
|
||||
}
|
||||
break;
|
||||
case H8500_rtd:
|
||||
case H8500_prtd:
|
||||
if ( code == 0x14 )
|
||||
imm8(insn, insn.Op1);
|
||||
else
|
||||
imm16(insn, insn.Op1);
|
||||
break;
|
||||
case H8500_scb:
|
||||
insn.Op1 = insn.Op2;
|
||||
d8(insn, insn.Op2);
|
||||
break;
|
||||
case H8500_dadd:
|
||||
case H8500_dsub:
|
||||
if ( (insn.auxpref & aux_byte) == 0 )
|
||||
return 0;
|
||||
insn.auxpref &= ~aux_byte;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !is_mixed_size_insns() )
|
||||
{
|
||||
if ( (insn.auxpref & aux_word) && insn.Op1.dtype == dt_byte
|
||||
|| (insn.auxpref & aux_byte) && insn.Op1.dtype == dt_word )
|
||||
{
|
||||
if ( insn.itype != H8500_mov_g )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
514
idasdk76/module/h8500/emu.cpp
Normal file
514
idasdk76/module/h8500/emu.cpp
Normal file
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h8500.hpp"
|
||||
#include <frame.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void process_immediate_number(const insn_t &insn, int n)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(get_flags(insn.ea), n) )
|
||||
return;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case H8500_add_q:
|
||||
case H8500_bclr:
|
||||
case H8500_bnot:
|
||||
case H8500_bset:
|
||||
case H8500_btst:
|
||||
op_dec(insn.ea, n);
|
||||
break;
|
||||
case H8500_and:
|
||||
case H8500_or:
|
||||
case H8500_xor:
|
||||
case H8500_andc:
|
||||
case H8500_orc:
|
||||
case H8500_xorc:
|
||||
op_num(insn.ea, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline bool issp(int x)
|
||||
{
|
||||
return x == SP;
|
||||
}
|
||||
|
||||
inline bool isbp(int x)
|
||||
{
|
||||
return x == FP;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &x)
|
||||
{
|
||||
return OP_SP_ADD
|
||||
| ((x.type == o_displ || x.type == o_phrase) && issp(x.phrase)
|
||||
? OP_SP_BASED
|
||||
: OP_FP_BASED);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void add_stkpnt(const insn_t &insn, sval_t value)
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn == NULL )
|
||||
return;
|
||||
|
||||
if ( value & 1 )
|
||||
value++;
|
||||
|
||||
add_auto_stkpnt(pfn, insn.ea+insn.size, value);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline bool is_mov(int itype)
|
||||
{
|
||||
return itype >= H8500_mov_g && itype <= H8500_mov_s;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool get_op_value(const insn_t &insn, const op_t &x, int *value)
|
||||
{
|
||||
if ( x.type == o_imm )
|
||||
{
|
||||
*value = (int)x.value;
|
||||
return true;
|
||||
}
|
||||
bool ok = false;
|
||||
if ( x.type == o_reg )
|
||||
{
|
||||
int reg = x.reg;
|
||||
insn_t movi;
|
||||
if ( decode_prev_insn(&movi, insn.ea) != BADADDR
|
||||
&& is_mov(movi.itype)
|
||||
&& movi.Op1.type == o_imm
|
||||
&& movi.Op2.type == o_reg
|
||||
&& movi.Op2.reg == reg )
|
||||
{
|
||||
*value = (int)movi.Op1.value;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static int calc_reglist_count(int regs)
|
||||
{
|
||||
int count = 0;
|
||||
for ( int i=0; i < 8; i++,regs>>=1 )
|
||||
if ( regs & 1 )
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// @--sp
|
||||
inline bool is_sp_dec(const op_t &x)
|
||||
{
|
||||
return x.type == o_phrase
|
||||
&& issp(x.reg)
|
||||
&& x.phtype == ph_pre;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// @sp++
|
||||
inline bool is_sp_inc(const op_t &x)
|
||||
{
|
||||
return x.type == o_phrase
|
||||
&& issp(x.reg)
|
||||
&& x.phtype == ph_post;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void trace_sp(const insn_t &insn)
|
||||
{
|
||||
// @sp++
|
||||
if ( is_sp_inc(insn.Op1) )
|
||||
{
|
||||
int size = 2;
|
||||
if ( insn.Op2.type == o_reglist )
|
||||
size *= calc_reglist_count(insn.Op2.reg);
|
||||
add_stkpnt(insn, size);
|
||||
return;
|
||||
}
|
||||
|
||||
// @--sp
|
||||
if ( is_sp_dec(insn.Op2) )
|
||||
{
|
||||
int size = 2;
|
||||
if ( insn.Op1.type == o_reglist )
|
||||
size *= calc_reglist_count(insn.Op1.reg);
|
||||
add_stkpnt(insn, -size);
|
||||
return;
|
||||
}
|
||||
// xxx @--sp
|
||||
if ( is_sp_dec(insn.Op1) )
|
||||
{
|
||||
add_stkpnt(insn, -2);
|
||||
return;
|
||||
}
|
||||
|
||||
int v;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case H8500_add_g:
|
||||
case H8500_add_q:
|
||||
case H8500_adds:
|
||||
if ( issp(insn.Op2.reg) && get_op_value(insn, insn.Op1, &v) )
|
||||
add_stkpnt(insn, v);
|
||||
break;
|
||||
case H8500_sub:
|
||||
case H8500_subs:
|
||||
if ( issp(insn.Op2.reg) && get_op_value(insn, insn.Op1, &v) )
|
||||
add_stkpnt(insn, -v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static sval_t calc_func_call_delta(const insn_t &insn, ea_t callee)
|
||||
{
|
||||
sval_t delta;
|
||||
func_t *pfn = get_func(callee);
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
delta = pfn->argsize;
|
||||
if ( (pfn->flags & FUNC_FAR) != 0 && insn.Op1.type == o_near )
|
||||
delta += 2; // function will pop the code segment
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = get_ind_purged(callee);
|
||||
if ( delta == -1 )
|
||||
delta = 0;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// trace a function call.
|
||||
// adjuct the stack, determine the execution flow
|
||||
// returns:
|
||||
// true - the called function returns to the caller
|
||||
// false - the called function doesn't return to the caller
|
||||
static bool handle_function_call(const insn_t &insn, ea_t callee)
|
||||
{
|
||||
bool funcflow = true;
|
||||
if ( !func_does_return(callee) )
|
||||
funcflow = false;
|
||||
if ( inf_should_trace_sp() )
|
||||
{
|
||||
func_t *caller = get_func(insn.ea);
|
||||
if ( func_contains(caller, insn.ea+insn.size) )
|
||||
{
|
||||
sval_t delta = calc_func_call_delta(insn, callee);
|
||||
if ( delta != 0 )
|
||||
add_stkpnt(insn, delta);
|
||||
}
|
||||
}
|
||||
return funcflow;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline ea_t find_callee(const insn_t &insn)
|
||||
{
|
||||
return get_first_fcref_from(insn.ea);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void h8500_t::handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
case o_reglist:
|
||||
return;
|
||||
case o_imm:
|
||||
QASSERT(10090, isload);
|
||||
process_immediate_number(insn, x.n);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, calc_opimm_flags(insn));
|
||||
break;
|
||||
case o_phrase:
|
||||
case o_displ:
|
||||
{
|
||||
process_immediate_number(insn, x.n);
|
||||
if ( is_forced )
|
||||
break;
|
||||
flags_t F = get_flags(insn.ea);
|
||||
if ( op_adds_xrefs(F, x.n) )
|
||||
{
|
||||
ea_t ea = insn.add_off_drefs(x, isload ? dr_R : dr_W, calc_opdispl_flags(insn));
|
||||
if ( ea != BADADDR )
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
// create stack variables if required
|
||||
if ( x.type == o_displ
|
||||
&& may_create_stkvars()
|
||||
&& !is_defarg(F, x.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL
|
||||
&& (issp(x.phrase)
|
||||
|| isbp(x.phrase) && (pfn->flags & FUNC_FRAME) != 0) )
|
||||
{
|
||||
if ( insn.create_stkvar(x, x.addr, STKVAR_VALID_SIZE) )
|
||||
op_stkvar(insn.ea, x.n);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case o_near:
|
||||
case o_far:
|
||||
{
|
||||
cref_t ftype = x.type == o_near ? fl_JN : fl_JF;
|
||||
ea_t ea = calc_mem(insn, x);
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = x.type == o_near ? fl_CN : fl_CF;
|
||||
}
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
}
|
||||
break;
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = calc_mem(insn, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
INTERR(10091);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline bool is_far_ending(const insn_t &insn)
|
||||
{
|
||||
return insn.itype == H8500_prts
|
||||
|| insn.itype == H8500_prtd;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int h8500_t::h8500_emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, flag1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, flag2, true);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, flag3, true);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, flag1, false);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, flag2, false);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, flag3, false);
|
||||
|
||||
//
|
||||
// Determine if the next instruction should be executed
|
||||
//
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
flow = false;
|
||||
|
||||
//
|
||||
// Handle loads to segment registers
|
||||
//
|
||||
sel_t v = BADSEL;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case H8500_andc:
|
||||
if ( insn.Op1.value == 0 )
|
||||
v = 0;
|
||||
goto SPLIT;
|
||||
case H8500_orc:
|
||||
if ( insn.Op1.value == 0xFF )
|
||||
v = 0xFF;
|
||||
goto SPLIT;
|
||||
case H8500_ldc:
|
||||
if ( insn.Op1.type == o_imm )
|
||||
v = insn.Op1.value;
|
||||
// fallthrough
|
||||
case H8500_xorc:
|
||||
SPLIT:
|
||||
if ( insn.Op2.reg >= BR && insn.Op2.reg <= TP )
|
||||
split_sreg_range(insn.ea+insn.size, insn.Op2.reg, v, SR_auto);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (Feature & CF_CALL) != 0 )
|
||||
{
|
||||
ea_t callee = find_callee(insn);
|
||||
if ( !handle_function_call(insn, callee) )
|
||||
flow = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle SP modifications
|
||||
//
|
||||
if ( may_trace_sp() )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
if ( (pfn->flags & FUNC_USERFAR) == 0
|
||||
&& (pfn->flags & FUNC_FAR) == 0
|
||||
&& is_far_ending(insn) )
|
||||
{
|
||||
pfn->flags |= FUNC_FAR;
|
||||
update_func(pfn);
|
||||
reanalyze_callers(pfn->start_ea, 0);
|
||||
}
|
||||
if ( !flow )
|
||||
recalc_spd(insn.ea); // recalculate SP register for the next insn
|
||||
else
|
||||
trace_sp(insn);
|
||||
}
|
||||
}
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int is_jump_func(const func_t * /*pfn*/, ea_t *jump_target)
|
||||
{
|
||||
*jump_target = BADADDR;
|
||||
return 0; // means "don't know"
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int may_be_func(const insn_t &)
|
||||
{
|
||||
// if ( insn.itype == H8_push && isbp(insn.Op1.reg) ) return 100; // push.l er6
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int is_sane_insn(const insn_t &insn, int /*nocrefs*/)
|
||||
{
|
||||
if ( insn.itype == H8500_nop )
|
||||
{
|
||||
for ( int i=0; i < 8; i++ )
|
||||
if ( get_word(insn.ea-i*2) != 0 )
|
||||
return 1;
|
||||
return 0; // too many nops in a row
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
return 0;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case H8500_nop:
|
||||
break;
|
||||
case H8500_mov_g: // B/W Move data
|
||||
case H8500_mov_e: // B Move data
|
||||
case H8500_mov_i: // W Move data
|
||||
case H8500_mov_f: // B/W Move data
|
||||
case H8500_mov_l: // B/W Move data
|
||||
case H8500_mov_s: // B/W Move data
|
||||
case H8500_or:
|
||||
case H8500_and:
|
||||
if ( insn.Op1.type == insn.Op2.type && insn.Op1.reg == insn.Op2.reg )
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi h8500_get_frame_retsize(const func_t *pfn)
|
||||
{
|
||||
return pfn->flags & FUNC_FAR ? 4 : 2;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static uval_t find_ret_purged(const func_t *pfn)
|
||||
{
|
||||
uval_t argsize = 0;
|
||||
ea_t ea = pfn->start_ea;
|
||||
insn_t insn;
|
||||
while ( ea < pfn->end_ea )
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
if ( insn.itype == H8500_rtd || insn.itype == H8500_prtd )
|
||||
{
|
||||
argsize = insn.Op1.value;
|
||||
break;
|
||||
}
|
||||
ea = next_that(ea, pfn->end_ea, f_is_code);
|
||||
}
|
||||
|
||||
// could not find any ret instructions
|
||||
// but the function ends with a jump
|
||||
if ( ea >= pfn->end_ea
|
||||
&& (insn.itype == H8500_jmp || insn.itype == H8500_pjmp) )
|
||||
{
|
||||
ea_t target = calc_mem(insn, insn.Op1);
|
||||
pfn = get_func(target);
|
||||
if ( pfn != NULL )
|
||||
argsize = pfn->argsize;
|
||||
}
|
||||
|
||||
return argsize;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void setup_far_func(func_t *pfn)
|
||||
{
|
||||
if ( (pfn->flags & FUNC_FAR) == 0 )
|
||||
{
|
||||
ea_t ea1 = pfn->start_ea;
|
||||
ea_t ea2 = pfn->end_ea;
|
||||
while ( ea1 < ea2 )
|
||||
{
|
||||
if ( is_code(get_flags(ea1)) )
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, ea1);
|
||||
if ( is_far_ending(insn) )
|
||||
{
|
||||
pfn->flags |= FUNC_FAR;
|
||||
update_func(pfn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ea1 = next_head(ea1, ea2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
setup_far_func(pfn);
|
||||
uval_t argsize = find_ret_purged(pfn);
|
||||
add_frame(pfn, 0, 0, argsize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
122
idasdk76/module/h8500/h8500.hpp
Normal file
122
idasdk76/module/h8500/h8500.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H8500_HPP
|
||||
#define _H8500_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
|
||||
#define PROCMOD_NAME h8500
|
||||
#define PROCMOD_NODE_NAME "$ h8/500"
|
||||
|
||||
//---------------------------------
|
||||
// Operand types:
|
||||
|
||||
/*
|
||||
o_reg 1 Register direct Rn
|
||||
x.reg
|
||||
o_phrase 2 Register indirect @Rn
|
||||
x.phrase contains register number
|
||||
x.phtype contains phrase type (normal, post, pre)
|
||||
o_displ 3 Register indirect with displacement @(d:8,Rn)/@(d:16,Rn)
|
||||
x.reg, x.addr, aux_disp16, aux_disp32
|
||||
o_mem 5 Absolute address @aa:8/@aa:16/@aa:24
|
||||
x.page, x.addr
|
||||
o_imm 6 Immediate #xx:8/#xx:16/#xx:32
|
||||
x.value
|
||||
o_displ 7 Program-counter relative @(d:8,PC)/@(d:16,PC)
|
||||
o_reglist Register list
|
||||
x.reg
|
||||
*/
|
||||
|
||||
#define o_reglist o_idpspec0
|
||||
|
||||
#define phtype specflag1 // phrase type:
|
||||
const int ph_normal = 0; // just simple indirection
|
||||
const int ph_pre = 1; // predecrement
|
||||
const int ph_post = 2; // postincrement
|
||||
|
||||
#define page specflag1 // o_mem, page number if aux_page
|
||||
//------------------------------------------------------------------
|
||||
#define aux_byte 0x0001 // .b postfix
|
||||
#define aux_word 0x0002 // .w postfix
|
||||
#define aux_disp8 0x0004 // 8bit displacement
|
||||
#define aux_disp16 0x0008 // 16bit displacement
|
||||
#define aux_disp24 0x0010 // 24bit displacement
|
||||
#define aux_page 0x0020 // implicit page using BR
|
||||
#define aux_f 0x0040 // /f postfix
|
||||
#define aux_ne 0x0080 // /ne postfix
|
||||
#define aux_eq 0x0100 // /eq postfix
|
||||
#define aux_mov16 0x0200 // mov #xx:16, ...
|
||||
|
||||
//------------------------------------------------------------------
|
||||
enum regnum_t
|
||||
{
|
||||
R0, R1, R2, R3, R4, R5, R6, FP=R6, R7, SP=R7,
|
||||
SR, CCR, RES1, BR, EP, DP, CP, TP, // RES1 is forbidden
|
||||
};
|
||||
|
||||
|
||||
ea_t calc_mem(const insn_t &insn, const op_t &x); // map virtual to physical ea
|
||||
//------------------------------------------------------------------
|
||||
int calc_opimm_flags(const insn_t &insn);
|
||||
int calc_opdispl_flags(const insn_t &insn);
|
||||
|
||||
void idaapi h8500_header(outctx_t &ctx);
|
||||
|
||||
void idaapi h8500_segend(outctx_t &ctx, segment_t *seg);
|
||||
|
||||
int idaapi is_align_insn(ea_t ea);
|
||||
bool idaapi create_func_frame(func_t *pfn);
|
||||
int idaapi is_sp_based(const insn_t &insn, const op_t &x);
|
||||
|
||||
int idaapi h8500_get_frame_retsize(const func_t *);
|
||||
int is_jump_func(const func_t *pfn, ea_t *jump_target);
|
||||
int is_sane_insn(const insn_t &insn, int nocrefs);
|
||||
int may_be_func(const insn_t &insn); // can a function start here?
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct h8500_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
ioports_t ports;
|
||||
#define IDP_SAMESIZE 0x0001 // do not disassemble mixed size insns
|
||||
ushort idpflags = 0;
|
||||
bool is_mixed_size_insns() const { return (idpflags & IDP_SAMESIZE) == 0; }
|
||||
bool flow = false;
|
||||
char show_sizer = -1;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void load_symbols(const char *file);
|
||||
const char *find_sym(int address);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void * value,
|
||||
bool idb_loaded);
|
||||
|
||||
int h8500_ana(insn_t *_insn);
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload);
|
||||
int h8500_emu(const insn_t &insn);
|
||||
|
||||
void h8500_assume(outctx_t &ctx);
|
||||
void h8500_segstart(outctx_t &ctx, segment_t *Srange) const;
|
||||
void h8500_footer(outctx_t &ctx) const;
|
||||
|
||||
void save_idpflags() { helper.altset(-1, idpflags); }
|
||||
void load_from_idb();
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
#endif // _H8500_HPP
|
||||
127
idasdk76/module/h8500/ins.cpp
Normal file
127
idasdk76/module/h8500/ins.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2000 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h8500.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
// Data transfer
|
||||
|
||||
{ "mov:g", CF_USE1|CF_CHG2 }, // B/W Move data
|
||||
{ "mov:e", CF_USE1|CF_CHG2 }, // B Move data
|
||||
{ "mov:i", CF_USE1|CF_CHG2 }, // W Move data
|
||||
{ "mov:f", CF_USE1|CF_CHG2 }, // B/W Move data
|
||||
{ "mov:l", CF_USE1|CF_CHG2 }, // B/W Move data
|
||||
{ "mov:s", CF_USE1|CF_CHG2 }, // B/W Move data
|
||||
{ "ldm", CF_USE1|CF_CHG2 }, // W Pop data from the stack to one or more registers
|
||||
{ "stm", CF_USE1|CF_CHG2 }, // W Push data from one or more registers onto the stack
|
||||
{ "xch", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // W Exchange data between two general registers
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // B Exchange the upper and lower bytes in a general register
|
||||
{ "movtpe", CF_USE1|CF_CHG2 }, // B Transfer data from a general register to memory
|
||||
{ "movfpe", CF_USE1|CF_CHG2 }, // B Transfer data from memory to a general register
|
||||
|
||||
// Arithmetic operations
|
||||
|
||||
{ "add:g", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition
|
||||
{ "add:q", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Subtraction
|
||||
{ "adds", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition
|
||||
{ "subs", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Subtraction
|
||||
{ "addx", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition with carry
|
||||
{ "subx", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Subtraction with borrow
|
||||
{ "dadd", CF_USE1|CF_USE2|CF_CHG2 }, // B Decimal addition
|
||||
{ "dsub", CF_USE1|CF_USE2|CF_CHG2 }, // B Decimal subtraction
|
||||
{ "mulxu", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Unsigned multiplication
|
||||
{ "divxu", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Unsigned division
|
||||
{ "cmp:g", CF_USE1|CF_USE2 }, // B/W Compare data
|
||||
{ "cmp:e", CF_USE1|CF_USE2 }, // B Compare data
|
||||
{ "cmp:i", CF_USE1|CF_USE2 }, // W Compare data
|
||||
{ "exts", CF_USE1|CF_CHG1 }, // B Convert byte to word by extending the sign bit
|
||||
{ "extu", CF_USE1|CF_CHG1 }, // B Convert byte to word data by padding with zero bits
|
||||
{ "tst", CF_USE1 }, // B/W Compare with 0
|
||||
{ "neg", CF_USE1|CF_CHG1 }, // B/W Negate
|
||||
{ "clr", CF_CHG1 }, // B/W Make zero
|
||||
{ "tas", CF_USE1|CF_CHG1 }, // B Test and set
|
||||
|
||||
// Logic Operations
|
||||
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logical AND
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logical OR
|
||||
{ "xor", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Exclusive OR
|
||||
{ "not", CF_USE1|CF_CHG1 }, // B/W Bitwise NOT
|
||||
|
||||
// Shift Operations
|
||||
|
||||
{ "shal", CF_USE1|CF_CHG1 }, // B/W Arithmetic shift left
|
||||
{ "shar", CF_USE1|CF_CHG1 }, // B/W Arithmetic shift right
|
||||
{ "shll", CF_USE1|CF_CHG1 }, // B/W Logical shift left
|
||||
{ "shlr", CF_USE1|CF_CHG1 }, // B/W Logical shift right
|
||||
{ "rotl", CF_USE1|CF_CHG1 }, // B/W Rotate left
|
||||
{ "rotr", CF_USE1|CF_CHG1 }, // B/W Rotate right
|
||||
{ "rotxl", CF_USE1|CF_CHG1 }, // B/W Rotate through carry left
|
||||
{ "rotxr", CF_USE1|CF_CHG1 }, // B/W Rotate through carry right
|
||||
|
||||
// Bit Manipulations
|
||||
|
||||
{ "bset", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Test bit and set
|
||||
{ "bclr", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Test bit and clear
|
||||
{ "bnot", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Test bit and invert
|
||||
{ "btst", CF_USE1|CF_USE2 }, // B/W Test bit
|
||||
|
||||
// Branching Instructions
|
||||
|
||||
{ "bra", CF_USE1|CF_STOP }, // Branch Always
|
||||
{ "brn", CF_USE1 }, // Branch Never
|
||||
{ "bhi", CF_USE1 }, // Branch if High (C|Z = 0)
|
||||
{ "bls", CF_USE1 }, // Branch if Low or Same (C|Z = 1)
|
||||
{ "bcc", CF_USE1 }, // Branch if Carry Clear (C = 0)
|
||||
{ "bcs", CF_USE1 }, // Branch if Carry Set (C = 1)
|
||||
{ "bne", CF_USE1 }, // Branch if Not Equal (Z = 0)
|
||||
{ "beq", CF_USE1 }, // Branch if Equal (Z = 1)
|
||||
{ "bvc", CF_USE1 }, // Branch if Overflow Clear (V = 0)
|
||||
{ "bvs", CF_USE1 }, // Branch if Overflow Set (V = 1)
|
||||
{ "bpl", CF_USE1 }, // Branch if Plus (N = 0)
|
||||
{ "bmi", CF_USE1 }, // Branch if Minus (N = 1)
|
||||
{ "bge", CF_USE1 }, // Branch if Greater or Equal (N^V = 0)
|
||||
{ "blt", CF_USE1 }, // Branch if Less Than (N^V = 1)
|
||||
{ "bgt", CF_USE1 }, // Branch if Greater Than (Z|(N^V) = 0)
|
||||
{ "ble", CF_USE1 }, // Branch if Less or Equal (Z|(N^V) = 1)
|
||||
{ "jmp", CF_USE1|CF_STOP }, // Branch unconditionally (same page)
|
||||
{ "pjmp", CF_USE1|CF_STOP }, // Branch unconditionally (specified page)
|
||||
{ "bsr", CF_USE1|CF_CALL }, // Branch to subroutine (same page)
|
||||
{ "jsr", CF_USE1|CF_CALL }, // Branch to subroutine (same page)
|
||||
{ "pjsr", CF_USE1|CF_CALL }, // Branch to subroutine (specified page)
|
||||
{ "rts", CF_STOP }, // Return from subroutine (same page)
|
||||
{ "prts", CF_STOP }, // Return from subroutine (different page)
|
||||
{ "rtd", CF_USE1|CF_STOP }, // Return from subroutine (same page) and adjust SP
|
||||
{ "prtd", CF_USE1|CF_STOP }, // Return from subroutine (different page) and adjust SP
|
||||
{ "scb", CF_USE1|CF_USE2 }, // Control loop
|
||||
|
||||
// System Control Instructions
|
||||
|
||||
{ "trapa", CF_USE1 }, // Generate trap exception
|
||||
{ "trap/vs", 0 }, // Generate trap exception if the V bit is set
|
||||
{ "rte", CF_STOP }, // Return from exception-handling routine
|
||||
{ "link", CF_USE1|CF_USE2 }, // Create stack frame
|
||||
{ "unlk", 0 }, // Deallocate stack frame
|
||||
{ "sleep", 0 }, // Go to power-down state
|
||||
{ "ldc", CF_USE1|CF_CHG2 }, // B/W Move to control register
|
||||
{ "stc", CF_USE1|CF_CHG2 }, // B/W Move from control register
|
||||
{ "andc", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logically AND control register
|
||||
{ "orc", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logically OR control register
|
||||
{ "xorc", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logically exclusive-OR control register
|
||||
{ "nop", 0 }, // No operation
|
||||
{ "bpt", 0 }, //
|
||||
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == H8500_last);
|
||||
130
idasdk76/module/h8500/ins.hpp
Normal file
130
idasdk76/module/h8500/ins.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum
|
||||
{
|
||||
|
||||
H8500_null = 0, // Unknown Operation
|
||||
|
||||
// Data transfer
|
||||
|
||||
H8500_mov_g, // B/W Move data
|
||||
H8500_mov_e, // B Move data
|
||||
H8500_mov_i, // W Move data
|
||||
H8500_mov_f, // B/W Move data
|
||||
H8500_mov_l, // B/W Move data
|
||||
H8500_mov_s, // B/W Move data
|
||||
H8500_ldm, // W Pop data from the stack to one or more registers
|
||||
H8500_stm, // W Push data from one or more registers onto the stack
|
||||
H8500_xch, // W Exchange data between two general registers
|
||||
H8500_swap, // B Exchange the upper and lower bytes in a general register
|
||||
H8500_movtpe, // B Transfer data from a general register to memory
|
||||
H8500_movfpe, // B Transfer data from memory to a general register
|
||||
|
||||
// Arithmetic operations
|
||||
|
||||
H8500_add_g, // B/W Addition
|
||||
H8500_add_q, // B/W Addition
|
||||
H8500_sub, // B/W Subtraction
|
||||
H8500_adds, // B/W Addition
|
||||
H8500_subs, // B/W Subtraction
|
||||
H8500_addx, // B/W Addition with carry
|
||||
H8500_subx, // B/W Subtraction with borrow
|
||||
H8500_dadd, // B Decimal addition
|
||||
H8500_dsub, // B Decimal subtraction
|
||||
H8500_mulxu, // B/W Unsigned multiplication
|
||||
H8500_divxu, // B/W Unsigned division
|
||||
H8500_cmp_g, // B/W Compare data
|
||||
H8500_cmp_e, // B Compare data
|
||||
H8500_cmp_i, // W Compare data
|
||||
H8500_exts, // B Convert byte to word by extending the sign bit
|
||||
H8500_extu, // B Convert byte to word data by padding with zero bits
|
||||
H8500_tst, // B/W Compare with 0
|
||||
H8500_neg, // B/W Negate
|
||||
H8500_clr, // B/W Make zero
|
||||
H8500_tas, // B Test and set
|
||||
|
||||
// Logic Operations
|
||||
|
||||
H8500_and, // B/W Logical AND
|
||||
H8500_or, // B/W Logical OR
|
||||
H8500_xor, // B/W Exclusive OR
|
||||
H8500_not, // B/W Bitwise NOT
|
||||
|
||||
// Shift Operations
|
||||
|
||||
H8500_shal, // B/W Arithmetic shift left
|
||||
H8500_shar, // B/W Arithmetic shift right
|
||||
H8500_shll, // B/W Logical shift left
|
||||
H8500_shlr, // B/W Logical shift right
|
||||
H8500_rotl, // B/W Rotate left
|
||||
H8500_rotr, // B/W Rotate right
|
||||
H8500_rotxl, // B/W Rotate through carry left
|
||||
H8500_rotxr, // B/W Rotate through carry right
|
||||
|
||||
// Bit Manipulations
|
||||
|
||||
H8500_bset, // B/W Test bit and set
|
||||
H8500_bclr, // B/W Test bit and clear
|
||||
H8500_bnot, // B/W Test bit and invert
|
||||
H8500_btst, // B/W Test bit
|
||||
|
||||
// Branching Instructions
|
||||
|
||||
H8500_bra, // Branch Always
|
||||
H8500_brn, // Branch Never
|
||||
H8500_bhi, // Branch if High (C|Z = 0)
|
||||
H8500_bls, // Branch if Low or Same (C|Z = 1)
|
||||
H8500_bcc, // Branch if Carry Clear (C = 0)
|
||||
H8500_bcs, // Branch if Carry Set (C = 1)
|
||||
H8500_bne, // Branch if Not Equal (Z = 0)
|
||||
H8500_beq, // Branch if Equal (Z = 1)
|
||||
H8500_bvc, // Branch if Overflow Clear (V = 0)
|
||||
H8500_bvs, // Branch if Overflow Set (V = 1)
|
||||
H8500_bpl, // Branch if Plus (N = 0)
|
||||
H8500_bmi, // Branch if Minus (N = 1)
|
||||
H8500_bge, // Branch if Greater or Equal (N^V = 0)
|
||||
H8500_blt, // Branch if Less Than (N^V = 1)
|
||||
H8500_bgt, // Branch if Greater Than (Z|(N^V) = 0)
|
||||
H8500_ble, // Branch if Less or Equal (Z|(N^V) = 1)
|
||||
H8500_jmp, // Branch unconditionally (same page)
|
||||
H8500_pjmp, // Branch unconditionally (specified page)
|
||||
H8500_bsr, // Branch to subroutine (same page)
|
||||
H8500_jsr, // Branch to subroutine (same page)
|
||||
H8500_pjsr, // Branch to subroutine (specified page)
|
||||
H8500_rts, // Return from subroutine (same page)
|
||||
H8500_prts, // Return from subroutine (different page)
|
||||
H8500_rtd, // Return from subroutine (same page) and adjust SP
|
||||
H8500_prtd, // Return from subroutine (different page) and adjust SP
|
||||
H8500_scb, // Control loop
|
||||
|
||||
// System Control Instructions
|
||||
|
||||
H8500_trapa, // Generate trap exception
|
||||
H8500_trap_vs, // Generate trap exception if the V bit is set
|
||||
H8500_rte, // Return from exception-handling routine
|
||||
H8500_link, // Create stack frame
|
||||
H8500_unlk, // Deallocate stack frame
|
||||
H8500_sleep, // Go to power-down state
|
||||
H8500_ldc, // B/W Move to control register
|
||||
H8500_stc, // B/W Move from control register
|
||||
H8500_andc, // B/W Logically AND control register
|
||||
H8500_orc, // B/W Logically OR control register
|
||||
H8500_xorc, // B/W Logically exclusive-OR control register
|
||||
H8500_nop, // No operation
|
||||
H8500_bpt, //
|
||||
|
||||
H8500_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
51
idasdk76/module/h8500/makefile
Normal file
51
idasdk76/module/h8500/makefile
Normal file
@@ -0,0 +1,51 @@
|
||||
PROC=h8500
|
||||
|
||||
|
||||
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)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 ../idaidp.hpp \
|
||||
ana.cpp h8500.hpp ins.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(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 ../idaidp.hpp \
|
||||
emu.cpp h8500.hpp ins.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.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 ../idaidp.hpp \
|
||||
h8500.hpp ins.cpp ins.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.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 ../idaidp.hpp \
|
||||
h8500.hpp ins.hpp out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.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 ../idaidp.hpp \
|
||||
h8500.hpp ins.hpp reg.cpp
|
||||
409
idasdk76/module/h8500/out.cpp
Normal file
409
idasdk76/module/h8500/out.cpp
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h8500.hpp"
|
||||
#include <segregs.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_h8500_t : public outctx_t
|
||||
{
|
||||
out_h8500_t(void) = delete; // not used
|
||||
public:
|
||||
void outreg(int r) { out_register(ph.reg_names[r]); }
|
||||
void out_bad_address(ea_t addr);
|
||||
void out_sizer(const op_t &x);
|
||||
void out_reglist(int reg, int cnt);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
};
|
||||
CASSERT(sizeof(out_h8500_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_h8500_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_h8500_t::out_bad_address(ea_t addr)
|
||||
{
|
||||
h8500_t &pm = *static_cast<h8500_t *>(procmod);
|
||||
const char *name = pm.find_sym((int)addr);
|
||||
if ( name != NULL && name[0] != '\0' )
|
||||
{
|
||||
out_line(name, COLOR_IMPNAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(addr, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
static int calc_sizer(const insn_t &insn, const op_t &x)
|
||||
{
|
||||
if ( insn.itype == H8500_mov_g && x.type == o_imm )
|
||||
return insn.auxpref & aux_mov16 ? 16 : 8;
|
||||
// special case: cmp:g.b #x:8, @(d:16,r)
|
||||
// special case: cmp:g.w #x:16, @(d:8,r)
|
||||
else if ( insn.itype == H8500_cmp_g && x.type == o_imm )
|
||||
return insn.auxpref & aux_word ? 16 : 8;
|
||||
else
|
||||
return (insn.auxpref & aux_disp24) ? 24 : (insn.auxpref & aux_disp16) ? 16 : 8;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t calc_mem(const insn_t &insn, const op_t &x)
|
||||
{
|
||||
if ( x.type == o_near )
|
||||
return to_ea(insn.cs, x.addr);
|
||||
|
||||
// Before this was simply to_ea, now we do it like this:
|
||||
// (if someone complains, both methods should be retained)
|
||||
ea_t ea = x.addr;
|
||||
switch ( calc_sizer(insn, x) )
|
||||
{
|
||||
case 8:
|
||||
if ( insn.auxpref & aux_page )
|
||||
{
|
||||
ea &= 0xFF;
|
||||
sel_t br = get_sreg(insn.ea, BR);
|
||||
if ( br != BADSEL )
|
||||
ea |= br << 8;
|
||||
else
|
||||
ea = BADADDR;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
ea &= 0xFFFF;
|
||||
if ( x.type == o_mem )
|
||||
{
|
||||
sel_t dp = get_sreg(insn.ea, DP);
|
||||
if ( dp != BADSEL )
|
||||
ea |= dp << 16;
|
||||
else
|
||||
ea = BADADDR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ea |= insn.ea & ~0xFFFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ea;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_h8500_t::out_sizer(const op_t &x)
|
||||
{
|
||||
h8500_t &pm = *static_cast<h8500_t *>(procmod);
|
||||
if ( pm.show_sizer == -1 )
|
||||
pm.show_sizer = !qgetenv("H8_NOSIZER");
|
||||
if ( !pm.show_sizer )
|
||||
return;
|
||||
if ( (insn.auxpref & (aux_disp8|aux_disp16|aux_disp24)) == 0 )
|
||||
return;
|
||||
out_symbol(':');
|
||||
// 1D 00 11 07 00 01 mov:g.w #1:16, @0x11:16
|
||||
// 1D 00 11 06 01 mov:g.w #1:16, @0x11:16
|
||||
// 0D 11 07 00 01 mov:g.w #1:8, @0x11:8
|
||||
// 0D 11 06 01 mov:g.w #1:8, @0x11:8
|
||||
// 0D 11 07 00 01 mov:g.w #1:8, @0x11:8
|
||||
// 1D 00 11 07 00 01 mov:g.w #1:16, @0x11:16
|
||||
// 15 00 11 06 01 mov:g.b #1:16, @0x11:16
|
||||
// 05 11 06 01 mov:g.b #1:8, @0x11:8
|
||||
int s = calc_sizer(insn, x);
|
||||
out_long(s, 10);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_h8500_t::out_reglist(int reg, int cnt)
|
||||
{
|
||||
int bit = 1;
|
||||
int delayed = -1;
|
||||
int first = 1;
|
||||
for ( int i=0; i <= cnt; i++,bit<<=1 )
|
||||
{
|
||||
if ( (reg & bit) == 0 )
|
||||
{
|
||||
if ( delayed >= 0 )
|
||||
{
|
||||
if ( !first )
|
||||
out_symbol(',');
|
||||
if ( delayed == (i-1) )
|
||||
{
|
||||
outreg(delayed);
|
||||
}
|
||||
else if ( delayed == (i-2) )
|
||||
{
|
||||
outreg(delayed);
|
||||
out_symbol(',');
|
||||
outreg(delayed+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
outreg(delayed);
|
||||
out_symbol('-');
|
||||
outreg(i-1);
|
||||
}
|
||||
delayed = -1;
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( delayed < 0 )
|
||||
delayed = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int calc_opimm_flags(const insn_t &insn)
|
||||
{
|
||||
bool sign = insn.itype == H8500_add_q
|
||||
|| insn.itype == H8500_adds
|
||||
|| insn.itype == H8500_subs;
|
||||
return OOFS_IFSIGN|OOFW_IMM|(sign ? OOF_SIGNED : 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int calc_opdispl_flags(const insn_t &insn)
|
||||
{
|
||||
bool sign = (insn.auxpref & aux_disp8) != 0;
|
||||
return OOF_ADDR | OOFS_IFSIGN | (sign ? OOF_SIGNED : 0)
|
||||
| (insn.auxpref & aux_disp24 ? OOFW_32
|
||||
: insn.auxpref & aux_disp16 ? OOFW_16
|
||||
: OOFW_8);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_h8500_t::out_operand(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_reg:
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
case o_reglist:
|
||||
out_symbol('(');
|
||||
out_reglist(x.reg, 8);
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, calc_opimm_flags(insn));
|
||||
out_sizer(x);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
out_symbol('@');
|
||||
// fallthrough
|
||||
case o_near:
|
||||
case o_far:
|
||||
{
|
||||
ea_t ea = calc_mem(insn, x);
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
out_bad_address(x.addr);
|
||||
out_sizer(x);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
if ( x.phtype == ph_normal )
|
||||
{
|
||||
bool outdisp = is_off(F, x.n)
|
||||
|| is_stkvar(F, x.n)
|
||||
|| is_enum(F, x.n)
|
||||
|| is_stroff(F, x.n);
|
||||
if ( outdisp )
|
||||
goto OUTDISP;
|
||||
}
|
||||
out_symbol('@');
|
||||
if ( x.phtype == ph_pre )
|
||||
out_symbol('-');
|
||||
outreg(x.phrase);
|
||||
if ( x.phtype == ph_post )
|
||||
out_symbol('+');
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
OUTDISP:
|
||||
out_symbol('@');
|
||||
out_symbol('(');
|
||||
out_value(x, calc_opdispl_flags(insn));
|
||||
out_sizer(x);
|
||||
out_symbol(',');
|
||||
outreg(x.reg);
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10099);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_h8500_t::out_proc_mnem(void)
|
||||
{
|
||||
const char *postfix = NULL;
|
||||
if ( insn.auxpref & aux_byte )
|
||||
postfix = ".b";
|
||||
else if ( insn.auxpref & aux_word )
|
||||
postfix = ".w";
|
||||
else if ( insn.auxpref & aux_f )
|
||||
postfix = "/f";
|
||||
else if ( insn.auxpref & aux_ne )
|
||||
postfix = "/ne";
|
||||
else if ( insn.auxpref & aux_eq )
|
||||
postfix = "/eq";
|
||||
out_mnem(8, postfix);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_h8500_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();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Srange) could be made const
|
||||
void h8500_t::h8500_segstart(outctx_t &ctx, segment_t *Srange) const
|
||||
{
|
||||
const char *predefined[] =
|
||||
{
|
||||
".text", // Text section
|
||||
".rdata", // Read-only data section
|
||||
".data", // Data sections
|
||||
".lit8", // Data sections
|
||||
".lit4", // Data sections
|
||||
".sdata", // Small data section, addressed through register $gp
|
||||
".sbss", // Small bss section, addressed through register $gp
|
||||
".bss", // bss (block started by storage) section, which loads zero-initialized data
|
||||
};
|
||||
|
||||
if ( is_spec_segm(Srange->type) )
|
||||
return;
|
||||
|
||||
qstring sname;
|
||||
qstring sclas;
|
||||
get_segm_name(&sname, Srange);
|
||||
get_segm_class(&sclas, Srange);
|
||||
|
||||
if ( !print_predefined_segname(ctx, &sname, predefined, qnumber(predefined)) )
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s", SCOLOR_ASMDIR) "" COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sclas == "CODE" ? ".text" :
|
||||
sclas == "BSS" ? ".bss" :
|
||||
".data",
|
||||
ash.cmnt,
|
||||
sname.c_str());
|
||||
if ( Srange->orgbase != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), Srange->orgbase);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi h8500_segend(outctx_t &, segment_t *)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
void h8500_t::h8500_assume(outctx_t &ctx)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
segment_t *seg = getseg(ea);
|
||||
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || seg == NULL )
|
||||
return;
|
||||
bool seg_started = (ea == seg->start_ea);
|
||||
|
||||
for ( int i=ph.reg_first_sreg; i <= ph.reg_last_sreg; i++ )
|
||||
{
|
||||
if ( i == ph.reg_code_sreg )
|
||||
continue;
|
||||
sreg_range_t sra;
|
||||
if ( !get_sreg_range(&sra, ea, i) )
|
||||
continue;
|
||||
bool show = sra.start_ea == ea;
|
||||
if ( show )
|
||||
{
|
||||
sreg_range_t prev_sra;
|
||||
if ( get_prev_sreg_range(&prev_sra, ea, i) )
|
||||
show = sra.val != prev_sra.val;
|
||||
}
|
||||
if ( seg_started || show )
|
||||
{
|
||||
if ( ctx.outbuf.empty() )
|
||||
{
|
||||
ctx.out_tagon(COLOR_AUTOCMT);
|
||||
ctx.out_line(ash.cmnt);
|
||||
ctx.out_line(" assume ");
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.out_line(", ");
|
||||
}
|
||||
ctx.out_line(ph.reg_names[i]);
|
||||
ctx.out_char(':');
|
||||
if ( sra.val == BADSEL )
|
||||
ctx.out_line("nothing");
|
||||
else
|
||||
ctx.out_btoa(sra.val, 16);
|
||||
}
|
||||
}
|
||||
if ( !ctx.outbuf.empty() )
|
||||
{
|
||||
ctx.out_tagoff(COLOR_AUTOCMT);
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi h8500_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL);
|
||||
ctx.gen_empty_line();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void h8500_t::h8500_footer(outctx_t &ctx) const
|
||||
{
|
||||
qstring nbuf = get_colored_name(inf_get_start_ea());
|
||||
const char *name = nbuf.c_str();
|
||||
const char *end = ash.end;
|
||||
if ( end == NULL )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s end %s",SCOLOR_AUTOCMT), ash.cmnt, name);
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
|
||||
ash.end, ash.cmnt, name);
|
||||
}
|
||||
506
idasdk76/module/h8500/reg.cpp
Normal file
506
idasdk76/module/h8500/reg.cpp
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h8500.hpp"
|
||||
#include <fpro.h>
|
||||
#include <diskio.hpp>
|
||||
|
||||
#include <ieee.h>
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const register_names[] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "fp", "sp",
|
||||
"sr", "ccr", "?", "br", "ep", "dp", "cp", "tp",
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcode_0[] = { 0x56, 0x70 }; // rte
|
||||
static const uchar retcode_1[] = { 0x54, 0x70 }; // rts
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_0), retcode_0 },
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
static void idaapi func_header(outctx_t &ctx, func_t *pfn)
|
||||
{
|
||||
ctx.gen_func_header(pfn);
|
||||
|
||||
if ( ctx.curlabel.empty() )
|
||||
return;
|
||||
|
||||
ctx.gen_printf(0, "%s" COLSTR(":", SCOLOR_SYMBOL) " "
|
||||
SCOLOR_ON SCOLOR_AUTOCMT
|
||||
"%s %s"
|
||||
SCOLOR_OFF SCOLOR_AUTOCMT,
|
||||
ctx.curlabel.begin(),
|
||||
ASH.cmnt,
|
||||
(pfn->flags & FUNC_FAR) != 0 ? "far" : "near");
|
||||
ctx.ctxflags |= CTXF_LABEL_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// GNU ASM
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t gas =
|
||||
{
|
||||
AS_ASCIIC|ASH_HEXF3|ASD_DECF0|ASB_BINF3|ASO_OCTF1|AS_COLON|AS_N2CHR|AS_NCMAS|AS_ONEDUP,
|
||||
0,
|
||||
"GNU assembler",
|
||||
0,
|
||||
NULL, // header lines
|
||||
".org", // org
|
||||
NULL, // end
|
||||
|
||||
"!", // comment string
|
||||
'"', // string delimiter
|
||||
'"', // char delimiter
|
||||
"\"", // special symbols in char and string constants
|
||||
|
||||
".ascii", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".word", // word directive
|
||||
".long", // double words
|
||||
NULL, // qwords
|
||||
NULL, // oword (16 bytes)
|
||||
".float", // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
".space %s", // uninited arrays
|
||||
"=", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
NULL, // current IP (instruction pointer)
|
||||
func_header, // func_header
|
||||
NULL, // func_footer
|
||||
".globl", // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
".extern", // "extrn" name keyword
|
||||
// .extern directive requires an explicit object size
|
||||
".comm", // "comm" (communal variable)
|
||||
NULL, // get_type_name
|
||||
".align", // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"~", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
AS2_COLONSUF, // flag2
|
||||
NULL, // cmnt2
|
||||
NULL, // low8
|
||||
NULL, // high8
|
||||
NULL, // low16
|
||||
NULL, // high16
|
||||
"#include \"%s\"", // a_include_fmt
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &gas, NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void h8500_t::load_symbols(const char *file)
|
||||
{
|
||||
ports.clear();
|
||||
|
||||
// KLUDGE: read_ioports() will complain if the file is
|
||||
// not present, but we don't want that.
|
||||
char cfgpath[QMAXPATH];
|
||||
const char *rfile = getsysfile(cfgpath, sizeof(cfgpath), file, CFG_SUBDIR);
|
||||
if ( rfile != NULL )
|
||||
read_ioports(&ports, NULL, file);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *h8500_t::find_sym(int address)
|
||||
{
|
||||
const ioport_t *port = find_ioport(ports, address);
|
||||
return port != NULL ? port->name.c_str() : NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void h8500_t::load_from_idb()
|
||||
{
|
||||
// in old databases we store 0 for the "mixed size" flag and -1 for the
|
||||
// "same size" flag. Now we store 1 for the latter.
|
||||
uval_t flags = helper.altval(-1);
|
||||
idpflags = flags == 0 ? 0 : IDP_SAMESIZE;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
const char *h8500_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void * value,
|
||||
bool idb_loaded)
|
||||
{
|
||||
static const char form[] =
|
||||
"HELP\n"
|
||||
"H8/500 specific analyzer options\n"
|
||||
"\n"
|
||||
"Disassemble mixed size instructions\n"
|
||||
"\n"
|
||||
" According to the documentation, instructions like\n"
|
||||
"\n"
|
||||
" cmp:g.b #1:16, @0x222:16\n"
|
||||
"\n"
|
||||
" are not allowed. The correct instruction is:\n"
|
||||
"\n"
|
||||
" cmp:g.b #1:8, @0x222:16\n"
|
||||
"\n"
|
||||
" The size of the first operand should agree with the size\n"
|
||||
" of the instruction. (exception mov:g)\n"
|
||||
"\n"
|
||||
"ENDHELP\n"
|
||||
"H8/500 specific analyzer options\n"
|
||||
"\n"
|
||||
// m
|
||||
" <Disassemble ~m~ixed size instructions:C>>\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
if ( keyword != nullptr )
|
||||
{
|
||||
if ( streq(keyword, "H8500_MIXED_SIZE") )
|
||||
{
|
||||
if ( value_type != IDPOPT_BIT )
|
||||
return IDPOPT_BADTYPE;
|
||||
// we store in IDPFLAGS the negation of the mixed size flag
|
||||
setflag(idpflags, IDP_SAMESIZE, *(int*)value == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IDPOPT_BADKEY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we store in IDPFLAGS the negation of the mixed size flag
|
||||
ushort flags = 0;
|
||||
if ( is_mixed_size_insns() )
|
||||
flags |= 1;
|
||||
ask_form(form, &flags);
|
||||
idpflags = 0;
|
||||
if ( (flags & 1) == 0 )
|
||||
idpflags |= IDP_SAMESIZE;
|
||||
}
|
||||
if ( idb_loaded )
|
||||
save_idpflags();
|
||||
return IDPOPT_OK;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "Hitachi H8/500:"
|
||||
static const char *const shnames[] = { "h8500", NULL };
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Hitachi H8/500",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// temporary solution for v4.7
|
||||
static ea_t idaapi h8_extract_address(ea_t screen_ea, const char *string, size_t x)
|
||||
{
|
||||
size_t len = strlen(string);
|
||||
if ( len == 0 || x > len )
|
||||
return BADADDR;
|
||||
if ( x == len )
|
||||
x--;
|
||||
const char *ptr = string + x;
|
||||
while ( ptr > string && qisxdigit(ptr[-1]) )
|
||||
ptr--;
|
||||
const char *start = ptr;
|
||||
while ( qisxdigit(ptr[0]) )
|
||||
ptr++;
|
||||
len = ptr - start;
|
||||
char buf[MAXSTR];
|
||||
memcpy(buf, start, len);
|
||||
buf[len] = '\0';
|
||||
ea_t ea = BADADDR;
|
||||
str2ea(&ea, buf, screen_ea);
|
||||
return ea;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static bool idaapi can_have_type(const op_t &x) // returns 1 - operand can have
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
case o_reg:
|
||||
case o_reglist:
|
||||
return false;
|
||||
case o_phrase:
|
||||
return x.phtype == ph_normal;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(h8500_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi h8500_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
inf_set_be(true);
|
||||
load_symbols("h8500.cfg");
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile: // new file loaded
|
||||
save_idpflags();
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile: // old file loaded
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm: // new segment
|
||||
{
|
||||
segment_t *sptr = va_arg(va, segment_t *);
|
||||
sptr->defsr[BR-ph.reg_first_sreg] = 0;
|
||||
sptr->defsr[DP-ph.reg_first_sreg] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_is_jump_func:
|
||||
{
|
||||
const func_t *pfn = va_arg(va, const func_t *);
|
||||
ea_t *jump_target = va_arg(va, ea_t *);
|
||||
return is_jump_func(pfn, jump_target);
|
||||
}
|
||||
|
||||
case processor_t::ev_is_sane_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
int no_crefs = va_arg(va, int);
|
||||
return is_sane_insn(*insn, no_crefs) == 1 ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_may_be_func:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
return may_be_func(*insn);
|
||||
}
|
||||
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_mnem(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
h8500_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
h8500_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 *);
|
||||
h8500_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
h8500_segend(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_assumes:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
h8500_assume(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return h8500_ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return h8500_emu(*insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_insn:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_insn(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_operand:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return out_opnd(*ctx, *op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_can_have_type:
|
||||
{
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return can_have_type(*op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_extract_address:
|
||||
{
|
||||
ea_t *out_ea = va_arg(va, ea_t *);
|
||||
ea_t screen_ea = va_arg(va, ea_t);
|
||||
const char *str = va_arg(va, const char *);
|
||||
size_t pos = va_arg(va, size_t);
|
||||
ea_t ea = h8_extract_address(screen_ea, str, pos);
|
||||
if ( ea == BADADDR )
|
||||
return -1;
|
||||
if ( ea == (BADADDR-1) )
|
||||
return 0;
|
||||
*out_ea = ea;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_sp_based:
|
||||
{
|
||||
int *mode = va_arg(va, int *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
*mode = is_sp_based(*insn, *op);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
create_func_frame(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_get_frame_retsize:
|
||||
{
|
||||
int *frsize = va_arg(va, int *);
|
||||
const func_t *pfn = va_arg(va, const func_t *);
|
||||
*frsize = h8500_get_frame_retsize(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_align_insn:
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
return is_align_insn(ea);
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_H8500, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_SEGS
|
||||
| PR_SGROTHER,
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
register_names, // Register names
|
||||
qnumber(register_names), // Number of registers
|
||||
|
||||
BR, // first
|
||||
TP, // last
|
||||
1, // size of a segment register
|
||||
CP, DP,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
H8500_null,
|
||||
H8500_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, 7, 15, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
H8500_rts, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
Reference in New Issue
Block a user