249 lines
6.6 KiB
C++
249 lines
6.6 KiB
C++
/*
|
|
* Interactive disassembler (IDA).
|
|
* Version 3.05
|
|
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
|
* ALL RIGHTS RESERVED.
|
|
* FIDO: 2:5020/209
|
|
* E-mail: ig@estar.msk.su
|
|
*/
|
|
|
|
#include "tms.hpp"
|
|
|
|
//------------------------------------------------------------------------
|
|
static void set_immd_bit(const insn_t &insn)
|
|
{
|
|
set_immd(insn.ea);
|
|
if ( is_defarg0(get_flags(insn.ea)) )
|
|
return;
|
|
switch ( insn.itype )
|
|
{
|
|
case TMS_and:
|
|
case TMS_bit:
|
|
case TMS_bitt:
|
|
case TMS_bsar:
|
|
case TMS_cmpr:
|
|
case TMS_in:
|
|
case TMS_intr:
|
|
case TMS_apl2:
|
|
case TMS_opl2:
|
|
case TMS_xpl2:
|
|
case TMS_or:
|
|
case TMS_rpt:
|
|
case TMS_xc:
|
|
case TMS_xor:
|
|
case TMS_rptz:
|
|
|
|
case TMS2_bit:
|
|
case TMS2_in:
|
|
case TMS2_out:
|
|
case TMS2_andk:
|
|
case TMS2_ork:
|
|
case TMS2_xork:
|
|
case TMS2_rptk:
|
|
op_num(insn.ea, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
int tms320c5_t::find_ar(const insn_t &insn, ea_t *res) const
|
|
{
|
|
ea_t ea = insn.ea;
|
|
for ( int i=0; i < get_lookback(); i++ )
|
|
{
|
|
ea = prevInstruction(ea);
|
|
if ( !is_code(get_flags(ea)) )
|
|
break;
|
|
ushort _code = (ushort)get_wide_byte(ea);
|
|
if ( isC2() )
|
|
{
|
|
switch ( _code >> 11 )
|
|
{
|
|
case 6: // LAR
|
|
return 0;
|
|
case 0x18: // LARK
|
|
*res = map_data_ea(insn, _code & 0xFF);
|
|
return 1;
|
|
case 0x1A: // LRLK
|
|
if ( (_code & 0xF8FF) == 0xD000 )
|
|
{
|
|
ushort b = (ushort)get_wide_byte(ea+1);
|
|
*res = map_data_ea(insn, b);
|
|
return 1;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
switch ( _code >> 11 )
|
|
{
|
|
case 0: // Load AR from addressed data
|
|
return 0; // LAR found, unknown address
|
|
case 0x16: // Load AR short immediate
|
|
*res = map_data_ea(insn, _code & 0xFF);
|
|
return 1;
|
|
case 0x17: // Load AR long immediate
|
|
if ( (_code & ~7) == 0xBF08 )
|
|
{
|
|
ushort b = (ushort)get_wide_byte(ea+1);
|
|
*res = map_data_ea(insn, b);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void tms320c5_t::handle_operand(const insn_t &insn, const op_t &x, bool isload)
|
|
{
|
|
ea_t ea;
|
|
switch ( x.type )
|
|
{
|
|
case o_phrase: // 2 registers or indirect addressing
|
|
if ( insn.itype != TMS_mar
|
|
&& insn.itype != TMS2_mar
|
|
&& find_ar(insn, &ea) )
|
|
{
|
|
goto SET_DREF;
|
|
}
|
|
case o_reg:
|
|
case o_bit:
|
|
case o_cond:
|
|
break;
|
|
case o_imm:
|
|
{
|
|
if ( !isload )
|
|
goto badTouch;
|
|
set_immd_bit(insn);
|
|
flags_t F = get_flags(insn.ea);
|
|
if ( op_adds_xrefs(F, x.n) )
|
|
insn.add_off_drefs(x, dr_O, is_mpy(insn) ? OOF_SIGNED : 0);
|
|
}
|
|
break;
|
|
case o_mem:
|
|
ea = map_data_ea(insn, x);
|
|
SET_DREF:
|
|
insn.create_op_data(ea, x);
|
|
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
|
if ( x.type == o_mem )
|
|
{
|
|
if ( insn.itype == TMS_dmov
|
|
|| insn.itype == TMS_ltd
|
|
|| insn.itype == TMS_macd
|
|
|| insn.itype == TMS_madd
|
|
|| insn.itype == TMS2_dmov
|
|
|| insn.itype == TMS2_macd )
|
|
{
|
|
insn.add_dref(ea+1, x.offb, dr_W);
|
|
}
|
|
}
|
|
break;
|
|
case o_near:
|
|
{
|
|
ea = map_code_ea(insn, x);
|
|
if ( insn.itype == TMS_blpd
|
|
|| insn.itype == TMS_mac
|
|
|| insn.itype == TMS_macd
|
|
|| insn.itype == TMS2_blkp
|
|
|| insn.itype == TMS2_mac
|
|
|| insn.itype == TMS2_macd )
|
|
{
|
|
goto SET_DREF;
|
|
}
|
|
ea_t segbase = (ea - x.addr) >> 4;
|
|
uval_t thisseg = insn.cs;
|
|
int iscall = has_insn_feature(insn.itype, CF_CALL);
|
|
if ( insn.itype == TMS_rptb && is_tail(get_flags(ea)) )
|
|
{
|
|
// small hack to display end_loop-1 instead of before_end_loop+1
|
|
ea++;
|
|
}
|
|
|
|
cref_t xtype = iscall
|
|
? (segbase == thisseg ? fl_CN : fl_CF)
|
|
: (segbase == thisseg ? fl_JN : fl_JF);
|
|
insn.add_cref(ea, x.offb, xtype);
|
|
if ( iscall && !func_does_return(ea) )
|
|
flow = false;
|
|
}
|
|
break;
|
|
default:
|
|
badTouch:
|
|
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static int isDelayedStop(ushort code)
|
|
{
|
|
switch ( code>>12 )
|
|
{
|
|
case 7:
|
|
return (code & 0xFF00u) == 0x7D00u;
|
|
case 0xB:
|
|
return code == 0xBE21u;
|
|
case 0xF:
|
|
return (code & 0xEFFFu) == 0xEF00u;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool tms320c5_t::can_flow(const insn_t &insn) const
|
|
{
|
|
if ( isC2() )
|
|
return true;
|
|
flags_t F = get_flags(insn.ea);
|
|
if ( !is_flow(F) )
|
|
return true; // no previous instructions
|
|
ea_t ea = prevInstruction(insn.ea);
|
|
if ( insn.size == 2 ) // our instruction is long
|
|
{
|
|
; // nothing to do
|
|
}
|
|
else
|
|
{ // our instruction short
|
|
if ( (insn.ea-ea) == 2 ) // prev instruction long
|
|
return true; // can flow always
|
|
F = get_flags(ea);
|
|
if ( !is_code(F) || !is_flow(F) )
|
|
return true; // no prev instr...
|
|
ea = prevInstruction(ea);
|
|
}
|
|
F = get_flags(ea);
|
|
return !is_code(F) || !isDelayedStop((ushort)get_wide_byte(ea));
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
int tms320c5_t::emu(const insn_t &insn)
|
|
{
|
|
uint32 Feature = insn.get_canon_feature(ph);
|
|
flow = ((Feature & CF_STOP) == 0);
|
|
|
|
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
|
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
|
|
if ( Feature & CF_JUMP )
|
|
remember_problem(PR_JUMP, insn.ea);
|
|
|
|
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
|
|
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
|
|
|
|
if ( flow && can_flow(insn) )
|
|
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
|
|
|
switch ( insn.itype )
|
|
{
|
|
case TMS_ldp: // change DP register
|
|
case TMS2_ldp: // change DP register
|
|
case TMS2_ldpk: // change DP register
|
|
{
|
|
uint v = (insn.Op1.type == o_imm) ? uint(insn.Op1.value) : -1u;
|
|
split_sreg_range(get_item_end(insn.ea), rDP, v, SR_auto);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|