update to ida 7.6, add builds
This commit is contained in:
435
idasdk76/module/tms320c54/emu.cpp
Normal file
435
idasdk76/module/tms320c54/emu.cpp
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tms320c54.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <frame.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
ea_t calc_code_mem(const insn_t &insn, ea_t ea, bool is_near)
|
||||
{
|
||||
ea_t rv;
|
||||
if ( is_near )
|
||||
{
|
||||
sel_t xpc = get_sreg(insn.ea, XPC);
|
||||
if ( xpc == BADSEL )
|
||||
xpc = 0;
|
||||
rv = ((xpc & 0x7F) << 16) | (ea & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = to_ea(insn.cs, ea);
|
||||
}
|
||||
return use_mapping(rv);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
ea_t tms320c54_t::calc_data_mem(const insn_t &insn, ea_t ea, bool is_mem) const
|
||||
{
|
||||
ea_t rv;
|
||||
if ( is_mem )
|
||||
{
|
||||
sel_t dp = get_sreg(insn.ea, DP);
|
||||
if ( dp == BADSEL )
|
||||
return BADSEL;
|
||||
rv = ((dp & 0x1FF) << 7) | (ea & 0x7F);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = ea;
|
||||
}
|
||||
rv += dataseg;
|
||||
return use_mapping(rv);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
regnum_t tms320c54_t::get_mapped_register(ea_t ea) const
|
||||
{
|
||||
if ( idpflags & TMS320C54_MMR )
|
||||
{
|
||||
switch ( ea-dataseg )
|
||||
{
|
||||
case 0x00: return IMR;
|
||||
case 0x01: return IFR;
|
||||
case 0x06: return ST0;
|
||||
case 0x07: return ST1;
|
||||
case 0x08: return AL;
|
||||
case 0x09: return AH;
|
||||
case 0x0A: return AG;
|
||||
case 0x0B: return BL;
|
||||
case 0x0C: return BH;
|
||||
case 0x0D: return BG;
|
||||
case 0x0E: return T;
|
||||
case 0x0F: return TRN;
|
||||
case 0x10: return AR0;
|
||||
case 0x11: return AR1;
|
||||
case 0x12: return AR2;
|
||||
case 0x13: return AR3;
|
||||
case 0x14: return AR4;
|
||||
case 0x15: return AR5;
|
||||
case 0x16: return AR6;
|
||||
case 0x17: return AR7;
|
||||
case 0x18: return SP;
|
||||
case 0x19: return BK;
|
||||
case 0x1A: return BRC;
|
||||
case 0x1B: return RSA;
|
||||
case 0x1C: return REA;
|
||||
case 0x1D: return PMST;
|
||||
case 0x1E: return XPC;
|
||||
default: return rnone;
|
||||
}
|
||||
}
|
||||
else
|
||||
return rnone;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void process_imm(const insn_t &insn, const op_t &x, flags_t F)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(F, x.n) )
|
||||
return; // if already defined by user
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case TMS320C54_cmpm:
|
||||
case TMS320C54_bitf:
|
||||
case TMS320C54_andm:
|
||||
case TMS320C54_orm:
|
||||
case TMS320C54_xorm:
|
||||
case TMS320C54_addm:
|
||||
case TMS320C54_st:
|
||||
case TMS320C54_stm:
|
||||
case TMS320C54_rpt:
|
||||
case TMS320C54_ld3:
|
||||
case TMS320C54_mpy2:
|
||||
case TMS320C54_rptz:
|
||||
case TMS320C54_add3:
|
||||
case TMS320C54_sub3:
|
||||
case TMS320C54_and3:
|
||||
case TMS320C54_or3:
|
||||
case TMS320C54_xor3:
|
||||
case TMS320C54_mac2:
|
||||
op_num(insn.ea, x.n);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void tms320c54_t::handle_operand(const insn_t &insn, const op_t &x, flags_t F, bool use)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_bit:
|
||||
case o_reg:
|
||||
case o_cond8:
|
||||
case o_cond2:
|
||||
return;
|
||||
|
||||
case o_near:
|
||||
case o_far:
|
||||
{
|
||||
if ( insn.itype != TMS320C54_rptb && insn.itype != TMS320C54_rptbd )
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
ea_t ea = calc_code_mem(insn, x.addr, x.type == o_near);
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
#ifndef TMS320C54_NO_NAME_NO_REF
|
||||
if ( x.dtype == dt_byte )
|
||||
insn.add_dref(ea, x.offb, dr_R);
|
||||
else
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
#endif
|
||||
}
|
||||
#ifndef TMS320C54_NO_NAME_NO_REF
|
||||
else // evaluate RPTB[D] loops as dref
|
||||
insn.add_dref(calc_code_mem(insn, x.addr), x.offb, dr_I);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
QASSERT(10113, use);
|
||||
process_imm(insn, x, F);
|
||||
#ifndef TMS320C54_NO_NAME_NO_REF
|
||||
if ( op_adds_xrefs(F, x.n) )
|
||||
insn.add_off_drefs(x, dr_O, x.Signed ? OOF_SIGNED : 0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
case o_farmem:
|
||||
case o_mmr:
|
||||
{
|
||||
ea_t ea = calc_data_mem(insn, x.addr, x.type == o_mem);
|
||||
if ( ea != BADADDR )
|
||||
{
|
||||
#ifndef TMS320C54_NO_NAME_NO_REF
|
||||
insn.add_dref(ea, x.offb, use ? dr_R : dr_W);
|
||||
#endif
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_local: // local variables
|
||||
if ( may_create_stkvars()
|
||||
&& (get_func(insn.ea) != NULL)
|
||||
&& insn.create_stkvar(x, x.addr, STKVAR_VALID_SIZE) )
|
||||
{
|
||||
op_stkvar(insn.ea, x.n);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
set_immd(insn.ea);
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("interr: emu2 address:%a operand:%d type:%d", insn.ea, x.n, x.type);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// is the previous instruction a delayed jump ?
|
||||
//
|
||||
// The following array shows all delayed instructions (xxx[D])
|
||||
// who are required to always stop.
|
||||
//
|
||||
// Z = 1 : delay instruction bit
|
||||
//
|
||||
// BRANCH INSTRUCTIONS
|
||||
//
|
||||
// TMS320C54_bd, // Branch Unconditionally 1111 00Z0 0111 0011 16-bit constant B[D] pmad
|
||||
// TMS320C54_baccd, // Branch to Location Specified by Accumulator 1111 01ZS 1110 0010 BACC[D] src
|
||||
// TMS320C54_fbd, // Far Branch Unconditionally 1111 10Z0 1 7bit constant=pmad(22-16) 16-bit constant=pmad(15-0) FB[D] extpmad
|
||||
// TMS320C54_fbaccd, // Far Branch to Location Specified by Accumulator 1111 01ZS 1110 0110 FBACC[D] src
|
||||
//
|
||||
// RETURN INSTRUCTIONS
|
||||
//
|
||||
// TMS320C54_fretd, // Far Return 1111 01Z0 1110 0100 FRET[D]
|
||||
// TMS320C54_freted, // Enable Interrupts and Far Return From Interrupt 1111 01Z0 1110 0101 FRETE[D]
|
||||
// TMS320C54_retd, // Return 1111 11Z0 0000 0000 RET[D]
|
||||
// TMS320C54_reted, // Enable Interrupts and Return From Interrupt 1111 01Z0 1110 1011 RETE[D]
|
||||
// TMS320C54_retfd, // Enable Interrupts and Fast Return From Interrupt 1111 01Z0 1001 1011 RETF[D]
|
||||
|
||||
static bool delayed_stop(const insn_t &insn, flags_t F)
|
||||
{
|
||||
if ( !is_flow(F) )
|
||||
return false;
|
||||
|
||||
if ( insn.size == 0 || insn.size > 2 )
|
||||
return false;
|
||||
|
||||
int sub = 2 - insn.size; // backward offset to skip the previous 1-word instruction in the case of 2 consecutive 1-word instructions
|
||||
|
||||
// first, we analyze 1-word instructions
|
||||
ea_t ea = insn.ea - sub - 1;
|
||||
if ( is_code(get_flags(ea)) )
|
||||
{
|
||||
int code = get_wide_byte(ea); // get the instruction word
|
||||
switch ( code )
|
||||
{
|
||||
case 0xF6E2: // TMS320C54_baccd, // Branch to Location Specified by Accumulator 1111 01ZS 1110 0010 BACC[D] src
|
||||
case 0xF7E2:
|
||||
case 0xF6E6: // TMS320C54_fbaccd, // Far Branch to Location Specified by Accumulator 1111 01ZS 1110 0110 FBACC[D] src
|
||||
case 0xF7E6:
|
||||
case 0xF6E4: // TMS320C54_fretd, // Far Return 1111 01Z0 1110 0100 FRET[D]
|
||||
case 0xF6E5: // TMS320C54_freted, // Enable Interrupts and Far Return From Interrupt 1111 01Z0 1110 0101 FRETE[D]
|
||||
case 0xFE00: // TMS320C54_retd, // Return 1111 11Z0 0000 0000 RET[D]
|
||||
case 0xF6EB: // TMS320C54_reted, // Enable Interrupts and Return From Interrupt 1111 01Z0 1110 1011 RETE[D]
|
||||
case 0xF69B: // TMS320C54_retfd, // Enable Interrupts and Fast Return From Interrupt 1111 01Z0 1001 1011 RETF[D]
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// else, we analyze 2-word instructions
|
||||
ea = insn.ea - sub - 2;
|
||||
if ( is_code(get_flags(ea)) )
|
||||
{
|
||||
int code = get_wide_byte(ea); // get the first instruction word
|
||||
if ( code == 0xF273 // TMS320C54_bd, // Branch Unconditionally 1111 00Z0 0111 0011 16-bit constant B[D] pmad
|
||||
|| (code & 0xFF80) == 0xFA80 ) // TMS320C54_fbd, // Far Branch Unconditionally 1111 10Z0 1 7bit constant=pmad(22-16) 16-bit constant=pmad(15-0) FB[D] extpmad
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool is_basic_block_end(const insn_t &insn)
|
||||
{
|
||||
flags_t F = get_flags(insn.ea);
|
||||
if ( delayed_stop(insn, F) )
|
||||
return true;
|
||||
return !is_flow(get_flags(insn.ea+insn.size));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
// trace SP changes
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case TMS320C54_fret:
|
||||
case TMS320C54_fretd:
|
||||
case TMS320C54_frete:
|
||||
case TMS320C54_freted:
|
||||
add_stkpnt(insn, 2);
|
||||
break;
|
||||
case TMS320C54_ret:
|
||||
case TMS320C54_retd:
|
||||
case TMS320C54_rete:
|
||||
case TMS320C54_reted:
|
||||
case TMS320C54_retf:
|
||||
case TMS320C54_retfd:
|
||||
add_stkpnt(insn, 1);
|
||||
break;
|
||||
case TMS320C54_frame:
|
||||
add_stkpnt(insn, insn.Op1.value);
|
||||
break;
|
||||
case TMS320C54_popd:
|
||||
case TMS320C54_popm:
|
||||
add_stkpnt(insn, 1);
|
||||
break;
|
||||
case TMS320C54_pshd:
|
||||
case TMS320C54_pshm:
|
||||
add_stkpnt(insn, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int tms320c54_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_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);
|
||||
|
||||
// check for CPL changes
|
||||
if ( (insn.itype == TMS320C54_rsbx1 || insn.itype == TMS320C54_ssbx1)
|
||||
&& insn.Op1.type == o_reg && insn.Op1.reg == CPL )
|
||||
{
|
||||
int value = insn.itype == TMS320C54_rsbx1 ? 0 : 1;
|
||||
split_sreg_range(get_item_end(insn.ea), CPL, value, SR_auto);
|
||||
}
|
||||
|
||||
// check for DP changes
|
||||
if ( insn.itype == TMS320C54_ld2
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op1.dtype == dt_byte
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == DP )
|
||||
{
|
||||
split_sreg_range(get_item_end(insn.ea), DP, insn.Op1.value & 0x1FF, SR_auto);
|
||||
}
|
||||
|
||||
// determine if the next instruction should be executed
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
flow = false;
|
||||
if ( flow && delayed_stop(insn, F) )
|
||||
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 tms320c54_t::create_func_frame(func_t *pfn) const
|
||||
{
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
if ( pfn->frame == BADNODE )
|
||||
{
|
||||
insn_t insn;
|
||||
int regsize = 0;
|
||||
ea_t ea = pfn->start_ea;
|
||||
while ( ea < pfn->end_ea ) // check for register pushs
|
||||
{
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
break;
|
||||
if ( insn.itype != TMS320C54_pshm )
|
||||
break;
|
||||
if ( insn.Op1.type != o_mem && insn.Op1.type != o_mmr )
|
||||
break;
|
||||
if ( get_mapped_register(insn.Op1.addr) == rnone )
|
||||
break;
|
||||
regsize++;
|
||||
ea += insn.size;
|
||||
}
|
||||
int localsize = 0;
|
||||
while ( ea < pfn->end_ea ) // check for frame creation
|
||||
{
|
||||
if ( insn.itype == TMS320C54_frame && insn.Op1.type == o_imm )
|
||||
{
|
||||
localsize = -(int)insn.Op1.value;
|
||||
break;
|
||||
}
|
||||
ea += insn.size;
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
break;
|
||||
}
|
||||
add_frame(pfn, localsize+regsize, 0, 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi tms_get_frame_retsize(const func_t * /*pfn*/)
|
||||
{
|
||||
return 1; // 1 'byte' for the return address
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
return 0;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case TMS320C54_nop:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user