162 lines
4.8 KiB
C++
162 lines
4.8 KiB
C++
/*
|
|
* Disassembler for Samsung SAM87 processors
|
|
*/
|
|
|
|
#include "sam8.hpp"
|
|
|
|
//----------------------------------------------------------------------
|
|
// Handle an operand. What this function usually does:
|
|
// - creates cross-references from the operand
|
|
// (the kernel deletes all xrefs before calling emu())
|
|
// - creates permanent comments
|
|
// - if possible, specifies the operand type (for example, it may
|
|
// create stack variables)
|
|
// - anything else you might need to emulate or trace
|
|
void sam8_t::handle_operand(const insn_t &insn, const op_t &x, bool loading)
|
|
{
|
|
switch ( x.type )
|
|
{
|
|
case o_phrase: // no special handling for these types
|
|
case o_reg:
|
|
case o_reg_bit:
|
|
break;
|
|
|
|
case o_imm:
|
|
// this can't happen!
|
|
if ( !loading )
|
|
goto BAD_LOGIC;
|
|
|
|
// set immediate flag
|
|
set_immd(insn.ea);
|
|
|
|
// if the value was converted to an offset, then create a data xref:
|
|
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
|
insn.add_off_drefs(x, dr_O, 0);
|
|
break;
|
|
|
|
case o_displ:
|
|
if ( x.phrase == fIdxCAddr )
|
|
{
|
|
insn.create_op_data(x.addr, x);
|
|
insn.add_dref(x.addr, x.offb, loading ? dr_R : dr_W);
|
|
}
|
|
else
|
|
{
|
|
// create name
|
|
char buf[256];
|
|
qsnprintf(buf, sizeof(buf), "emem_%a", x.addr);
|
|
set_name(SAM8_EDATASEG_START + x.addr, buf, SN_NOCHECK|SN_AUTO);
|
|
|
|
// setup data xrefs etc
|
|
insn.create_op_data(SAM8_EDATASEG_START + x.addr, x);
|
|
insn.add_dref(SAM8_EDATASEG_START + x.addr, x.offb, loading ? dr_R : dr_W);
|
|
}
|
|
break;
|
|
|
|
case o_emem:
|
|
{
|
|
// create variable name
|
|
char buf[256];
|
|
qsnprintf(buf, sizeof(buf), "emem_%a", x.addr);
|
|
set_name(SAM8_EDATASEG_START + x.addr, buf, SN_NOCHECK|SN_AUTO);
|
|
|
|
// setup data xrefs etc
|
|
insn.create_op_data(SAM8_EDATASEG_START + x.addr, x);
|
|
insn.add_dref(SAM8_EDATASEG_START + x.addr, x.offb, loading ? dr_R : dr_W);
|
|
break;
|
|
}
|
|
|
|
case o_cmem:
|
|
insn.create_op_data(x.addr, x);
|
|
insn.add_dref(x.addr, x.offb, loading ? dr_R : dr_W);
|
|
break;
|
|
|
|
case o_near:
|
|
{
|
|
// work out if it is a CALL, and add in a code xref
|
|
bool iscall = has_insn_feature(insn.itype, CF_CALL);
|
|
insn.add_cref(x.addr, x.offb, iscall ? fl_CN : fl_JN);
|
|
|
|
// if dest is a non-returning function, don't flow onto next op
|
|
if ( flow && iscall )
|
|
{
|
|
if ( !func_does_return(x.addr) )
|
|
flow = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case o_cmem_ind:
|
|
// setup code xref/variable
|
|
insn.create_op_data(x.addr, x.offb, dt_word);
|
|
insn.add_dref(x.addr, x.offb, loading ? dr_R : dr_W);
|
|
|
|
// Now, since we KNOW this is an indirect code jump, turn
|
|
// the word at the x.addr into an offset into a subroutine
|
|
if ( is_mapped(x.addr) )
|
|
{
|
|
// get value stored in that address
|
|
ushort destAddr = get_word(x.addr);
|
|
|
|
// add in cref & turn into offset
|
|
add_cref(x.addr, destAddr, fl_JN);
|
|
op_plain_offset(x.addr, 0, 0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BAD_LOGIC:
|
|
warning("%a (%s): bad optype", insn.ea, insn.get_canon_mnem(ph));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Emulate an instruction
|
|
// This function should:
|
|
// - create all xrefs from the instruction
|
|
// - perform any additional analysis of the instruction/program
|
|
// and convert the instruction operands, create comments, etc.
|
|
// - create stack variables
|
|
// - analyze the delayed branches and similar constructs
|
|
|
|
int sam8_t::emu(const insn_t &insn)
|
|
{
|
|
// setup
|
|
uint32 Feature = insn.get_canon_feature(ph);
|
|
flow = true;
|
|
|
|
// disable flow if CF_STOP set
|
|
if ( Feature & CF_STOP )
|
|
flow = false;
|
|
|
|
// you may emulate selected instructions with a greater care:
|
|
switch ( insn.itype )
|
|
{
|
|
case SAM8_JR: case SAM8_JP:
|
|
// Do extended condition code checking on these instructions
|
|
if ( insn.c_condition == ccNone || insn.c_condition == ccT )
|
|
flow = false;
|
|
break;
|
|
}
|
|
|
|
// deal with operands
|
|
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
|
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
|
|
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, 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 ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, false);
|
|
|
|
// if the execution flow is not stopped here, then create
|
|
// a xref to the next instruction.
|
|
// Thus we plan to analyze the next instruction.
|
|
if ( flow )
|
|
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
|
|
|
// OK (actual code unimportant)
|
|
return 1;
|
|
}
|