update to ida 7.6, add builds
This commit is contained in:
397
idasdk76/module/tms320c55/emu.cpp
Normal file
397
idasdk76/module/tms320c55/emu.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tms320c55.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <frame.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
ea_t calc_data_mem(const insn_t &insn, const op_t &op)
|
||||
{
|
||||
ea_t addr = op.addr;
|
||||
sel_t dph = 0;
|
||||
if ( op.tms_regH == DPH )
|
||||
{
|
||||
dph = get_sreg(to_ea(insn.cs, insn.ip), DPH);
|
||||
if ( dph == BADSEL )
|
||||
return BADSEL;
|
||||
addr &= 0xFFFF;
|
||||
}
|
||||
sel_t dp = 0;
|
||||
if ( op.tms_regP == DP )
|
||||
{
|
||||
dp = get_sreg(to_ea(insn.cs, insn.ip), DP);
|
||||
if ( dp == BADSEL )
|
||||
return BADSEL;
|
||||
addr &= 0xFFFF;
|
||||
}
|
||||
return (((dph & 0x7F) << 16) | (dp + addr)) << 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t calc_io_mem(const insn_t &insn, const op_t &op)
|
||||
{
|
||||
ea_t addr = op.addr;
|
||||
sel_t pdp = 0;
|
||||
if ( op.tms_regP == PDP )
|
||||
{
|
||||
pdp = get_sreg(to_ea(insn.cs, insn.ip), PDP);
|
||||
if ( pdp == BADSEL )
|
||||
return BADSEL;
|
||||
addr &= 0x7F;
|
||||
}
|
||||
ea_t ea = ((pdp & 0x1FF) << 7) | addr;
|
||||
return to_ea(insn.cs, ea);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int tms320c55_t::get_mapped_register(ea_t ea) const
|
||||
{
|
||||
ea = ea >> 1;
|
||||
if ( idpflags & TMS320C55_MMR )
|
||||
{
|
||||
static const int registers[] =
|
||||
{
|
||||
IER0, IFR0, ST0_55, ST1_55, ST3_55, -1, ST0, ST1,
|
||||
AC0L, AC0H, AC0G, AC1L, AC1H, AC1G, T3, TRN0,
|
||||
AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7,
|
||||
SP, BK03, BRC0, RSA0L, REA0L, PMST, XPC, -1,
|
||||
T0, T1, T2, T3, AC2L, AC2H, AC2G, CDP,
|
||||
AC3L, AC3H, AC3H, DPH, -1, -1, DP, PDP,
|
||||
BK47, BKC, BSA01, BSA23, BSA45, BSA67, BSAC, -1,
|
||||
TRN1, BRC1, BRS1, CSR, RSA0H, RSA0L, REA0H, REA0L,
|
||||
RSA1H, RSA1L, REA1H, REA1L, RPTC, IER1, IFR1, DBIER0,
|
||||
DBIER1, IVPD, IVPH, ST2_55, SSP, SP, SPH, CDPH
|
||||
};
|
||||
if ( ea <= 0x4F )
|
||||
return registers[int(ea)];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void process_imm(const insn_t &insn, const op_t &x, flags_t F)
|
||||
{
|
||||
set_immd(insn.ea); // assign contextual menu for conversions
|
||||
if ( is_defarg(F, x.n) )
|
||||
return; // if already defined by user
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case TMS320C55_rptcc:
|
||||
case TMS320C55_rpt:
|
||||
case TMS320C55_aadd:
|
||||
case TMS320C55_amov:
|
||||
case TMS320C55_asub:
|
||||
case TMS320C55_mov2:
|
||||
case TMS320C55_and3:
|
||||
case TMS320C55_or3:
|
||||
case TMS320C55_xor2:
|
||||
case TMS320C55_xor3:
|
||||
case TMS320C55_mpyk2:
|
||||
case TMS320C55_mpyk3:
|
||||
case TMS320C55_mpykr2:
|
||||
case TMS320C55_mpykr3:
|
||||
case TMS320C55_mack3:
|
||||
case TMS320C55_mack4:
|
||||
case TMS320C55_mackr3:
|
||||
case TMS320C55_mackr4:
|
||||
case TMS320C55_bclr2:
|
||||
case TMS320C55_bset2:
|
||||
case TMS320C55_rptadd:
|
||||
case TMS320C55_rptsub:
|
||||
case TMS320C55_add2:
|
||||
case TMS320C55_add3:
|
||||
case TMS320C55_sub2:
|
||||
case TMS320C55_sub3:
|
||||
case TMS320C55_and2:
|
||||
case TMS320C55_or2:
|
||||
case TMS320C55_intr:
|
||||
case TMS320C55_trap:
|
||||
case TMS320C55_btst:
|
||||
op_num(insn.ea, x.n);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void tms320c55_t::handle_operand(const insn_t &insn, const op_t &op, flags_t F, bool use)
|
||||
{
|
||||
switch ( op.type )
|
||||
{
|
||||
case o_cond:
|
||||
case o_shift:
|
||||
case o_io:
|
||||
return;
|
||||
|
||||
case o_reg:
|
||||
// analyze immediate values
|
||||
if ( op.tms_modifier == TMS_MODIFIER_REG_OFFSET
|
||||
|| op.tms_modifier == TMS_MODIFIER_P_REG_OFFSET
|
||||
|| op.tms_modifier == TMS_MODIFIER_REG_SHORT_OFFSET )
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
}
|
||||
// analyze local vars
|
||||
if ( op.reg == SP && op.tms_modifier == TMS_MODIFIER_REG_OFFSET )
|
||||
{
|
||||
if ( may_create_stkvars()
|
||||
&& get_func(insn.ea) != NULL
|
||||
&& insn.create_stkvar(op, 2 * op.value, STKVAR_VALID_SIZE) )
|
||||
{
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
// DP, DPH and PDP unknown changes
|
||||
if ( !use )
|
||||
{
|
||||
if ( op.reg == DP || op.reg == DPH || op.reg == PDP )
|
||||
split_sreg_range(get_item_end(insn.ea), op.reg, BADSEL, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_relop: // analyze immediate value
|
||||
if ( op.tms_relop_type == TMS_RELOP_IMM )
|
||||
set_immd(insn.ea);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
if ( insn.itype != TMS320C55_rptb && insn.itype != TMS320C55_rptblocal )
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
ea_t ea = calc_code_mem(insn, op.addr);
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
#ifndef TMS320C55_NO_NAME_NO_REF
|
||||
insn.add_cref(ea, op.offb, ftype);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TMS320C55_NO_NAME_NO_REF
|
||||
else // evaluate RPTB loops as dref
|
||||
insn.add_dref(calc_code_mem(insn, op.addr), op.offb, dr_I);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case o_imm:
|
||||
QASSERT(10114, use);
|
||||
process_imm(insn, op, F);
|
||||
#ifndef TMS320C55_NO_NAME_NO_REF
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, dr_O, op.tms_signed ? OOF_SIGNED : 0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = calc_data_mem(insn, op);
|
||||
if ( ea != BADADDR )
|
||||
{
|
||||
#ifndef TMS320C55_NO_NAME_NO_REF
|
||||
insn.add_dref(ea, op.offb, use ? dr_R : dr_W);
|
||||
#endif
|
||||
insn.create_op_data(ea, op);
|
||||
if ( !use )
|
||||
{
|
||||
int reg = get_mapped_register(ea);
|
||||
if ( reg == DP || reg == DPH || reg == PDP )
|
||||
split_sreg_range(get_item_end(insn.ea), reg, BADSEL, SR_auto);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("interr: emu2 address:%a operand:%d type:%d", insn.ea, op.n, op.type);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool add_stkpnt(const insn_t &insn, sval_t delta)
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn == NULL )
|
||||
return false;
|
||||
|
||||
return add_auto_stkpnt(pfn, insn.ea+insn.size, delta);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void trace_sp(const insn_t &insn)
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case TMS320C55_pop1: // pop dst; pop dbl(ACx); pop Smem; pop dbl(Lmem)
|
||||
add_stkpnt(insn, (insn.Op1.tms_operator1 & TMS_OPERATOR_DBL) ? 4:2);
|
||||
break;
|
||||
case TMS320C55_pop2: // pop dst1, dst2; pop dst, Smem
|
||||
add_stkpnt(insn, 4);
|
||||
break;
|
||||
case TMS320C55_psh1: // psh dst; psh dbl(ACx); psh Smem; psh dbl(Lmem)
|
||||
add_stkpnt(insn, (insn.Op1.tms_operator1 & TMS_OPERATOR_DBL) ? -4:-2);
|
||||
break;
|
||||
case TMS320C55_psh2: // psh src1, src2; psh src, Smem
|
||||
add_stkpnt(insn, -4);
|
||||
break;
|
||||
case TMS320C55_popboth:
|
||||
case TMS320C55_ret:
|
||||
add_stkpnt(insn, 2);
|
||||
break;
|
||||
case TMS320C55_pshboth:
|
||||
add_stkpnt(insn, -2);
|
||||
break;
|
||||
case TMS320C55_reti:
|
||||
add_stkpnt(insn, 6);
|
||||
break;
|
||||
case TMS320C55_aadd:
|
||||
if ( insn.Op2.type == o_reg && insn.Op2.reg == SP && insn.Op1.type == o_imm )
|
||||
add_stkpnt(insn, 2 * insn.Op1.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int tms320c55_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
flow = (feature & CF_STOP) == 0;
|
||||
|
||||
flags_t F = get_flags(insn.ea);
|
||||
if ( feature & CF_USE1 ) handle_operand(insn, insn.Op1, F, true);
|
||||
if ( feature & CF_USE2 ) handle_operand(insn, insn.Op2, F, true);
|
||||
if ( feature & CF_USE3 ) handle_operand(insn, insn.Op3, F, true);
|
||||
if ( feature & CF_USE4 ) handle_operand(insn, insn.Op4, F, true);
|
||||
if ( feature & CF_USE5 ) handle_operand(insn, insn.Op5, F, true);
|
||||
if ( feature & CF_USE6 ) handle_operand(insn, insn.Op6, F, true);
|
||||
|
||||
if ( feature & CF_CHG1 ) handle_operand(insn, insn.Op1, F, false);
|
||||
if ( feature & CF_CHG2 ) handle_operand(insn, insn.Op2, F, false);
|
||||
if ( feature & CF_CHG3 ) handle_operand(insn, insn.Op3, F, false);
|
||||
if ( feature & CF_CHG4 ) handle_operand(insn, insn.Op4, F, false);
|
||||
if ( feature & CF_CHG5 ) handle_operand(insn, insn.Op5, F, false);
|
||||
if ( feature & CF_CHG6 ) handle_operand(insn, insn.Op6, F, false);
|
||||
|
||||
// CPL and ARMS status flags changes
|
||||
if ( (insn.itype == TMS320C55_bclr1 || insn.itype == TMS320C55_bset1)
|
||||
&& insn.Op1.type == o_reg
|
||||
&& (insn.Op1.reg == CPL || insn.Op1.reg == ARMS) )
|
||||
{
|
||||
int value = insn.itype == TMS320C55_bclr1 ? 0 : 1;
|
||||
split_sreg_range(get_item_end(insn.ea), insn.Op1.reg, value, SR_auto);
|
||||
}
|
||||
|
||||
// DP, DPH and PDP changes
|
||||
if ( insn.itype == TMS320C55_mov2
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op1.type == o_imm )
|
||||
{
|
||||
ea_t end = insn.ea + insn.size;
|
||||
if ( insn.Op2.reg == DP )
|
||||
split_sreg_range(end, DP, insn.Op1.value & 0xFFFF, SR_auto);
|
||||
else if ( insn.Op2.reg == DPH )
|
||||
split_sreg_range(end, DPH, insn.Op1.value & 0x7F, SR_auto);
|
||||
else if ( insn.Op2.reg == PDP )
|
||||
split_sreg_range(end, PDP, insn.Op1.value & 0x1FF, SR_auto);
|
||||
}
|
||||
|
||||
// determine if the next instruction should be executed
|
||||
if ( flow && segtype(insn.ea) == SEG_XTRN )
|
||||
flow = false;
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
if ( may_trace_sp() )
|
||||
{
|
||||
if ( !flow )
|
||||
recalc_spd(insn.ea); // recalculate SP register for the next insn
|
||||
else
|
||||
trace_sp(insn);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
if ( pfn->frame == BADNODE )
|
||||
{
|
||||
insn_t insn;
|
||||
ushort regsize = 0;
|
||||
ea_t ea = pfn->start_ea;
|
||||
while ( ea < pfn->end_ea ) // check for register pushs
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
ea += insn.size;
|
||||
if ( insn.itype == TMS320C55_psh1 )
|
||||
regsize += (insn.Op1.tms_operator1 & TMS_OPERATOR_DBL) ? 4 : 2;
|
||||
else if ( insn.itype == TMS320C55_psh2 )
|
||||
regsize += 4;
|
||||
else if ( insn.itype == TMS320C55_pshboth )
|
||||
regsize += 2;
|
||||
else
|
||||
break;
|
||||
}
|
||||
int localsize = 0;
|
||||
while ( ea < pfn->end_ea ) // check for frame creation
|
||||
{
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
break;
|
||||
ea += insn.size;
|
||||
if ( insn.itype == TMS320C55_aadd
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == SP
|
||||
&& insn.Op1.type == o_imm )
|
||||
{
|
||||
localsize = int(2 * insn.Op1.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
add_frame(pfn, localsize, regsize, 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
return 0;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case TMS320C55_nop:
|
||||
case TMS320C55_nop_16:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool idaapi can_have_type(const op_t &op)
|
||||
{
|
||||
switch ( op.type )
|
||||
{
|
||||
case o_io:
|
||||
case o_reg:
|
||||
case o_relop:
|
||||
case o_imm:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user