Files
sigmaker-ida/idasdk76/module/tms320c6/reg.cpp
2021-10-31 21:20:46 +02:00

416 lines
11 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
*
* TMS320C6xx - VLIW (very long instruction word) architecture
*
*/
#include "tms6.hpp"
int data_id;
//--------------------------------------------------------------------------
// B14 - data page pointer
// B15 - stack pointer
static const char *const RegNames[] =
{
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
"A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15",
"A16", "A17", "A18", "A19", "A20", "A21", "A22", "A23",
"A24", "A25", "A26", "A27", "A28", "A29", "A30", "A31",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
"B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15",
"B16", "B17", "B18", "B19", "B20", "B21", "B22", "B23",
"B24", "B25", "B26", "B27", "B28", "B29", "B30", "B31",
"AMR",
"CSR",
"IFR",
"ISR",
"ICR",
"IER",
"ISTP",
"IRP",
"NRP",
"ACR", // undocumented, info from Jeff Bailey <jeff_bailey@infinitek.com>
"ADR", // undocumented, info from Jeff Bailey <jeff_bailey@infinitek.com>
"PCE1",
"FADCR",
"FAUCR",
"FMCR",
"TSCL",
"TSCH",
"ILC",
"RILC",
"REP",
"DNUM",
"SSR",
"GPLYA",
"GPLYB",
"GFPGFR",
"TSR",
"ITSR",
"NTSR",
"ECR",
"EFR",
"IERR",
"CS", "DS"
};
//--------------------------------------------------------------------------
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list va)
{
switch ( code )
{
case idb_event::segm_moved: // A segment is moved
// Fix processor dependent address sensitive information
{
ea_t from = va_arg(va, ea_t);
ea_t to = va_arg(va, ea_t);
asize_t size = va_arg(va, asize_t);
bool changed_netmap = va_argi(va, bool);
if ( !changed_netmap )
{
nodeidx_t ndx1 = ea2node(from);
nodeidx_t ndx2 = ea2node(to);
pm.helper.altshift(ndx1, ndx2, size);
// like altadjust()
for ( nodeidx_t ndx = pm.helper.supfirst();
ndx != BADADDR;
ndx = pm.helper.supnext(ndx) )
{
tgtinfo_t tgt;
ea_t ea = node2ea(ndx);
tgt.restore_from_idb(pm, ea);
if ( tgt.has_target() )
{
tgt.target = correct_address(tgt.target, from, to, size);
tgt.save_to_idb(pm, ea);
}
}
}
}
break;
}
return 0;
}
//----------------------------------------------------------------------
// 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(tms6_t));
return 0;
}
//--------------------------------------------------------------------------
ssize_t idaapi tms6_t::on_event(ssize_t msgid, va_list va)
{
int code = 0;
switch ( msgid )
{
case processor_t::ev_init:
hook_event_listener(HT_IDB, &idb_listener, &LPH);
helper.create(PROCMOD_NODE_NAME);
break;
case processor_t::ev_term:
unhook_event_listener(HT_IDB, &idb_listener);
clr_module_data(data_id);
break;
case processor_t::ev_oldfile:
{
netnode old_tnode("$ tms node");
if ( old_tnode != BADNODE )
{
upgrade_tnode(old_tnode);
old_tnode.kill();
}
}
// no break
case processor_t::ev_ending_undo:
case processor_t::ev_newfile:
break;
case processor_t::ev_out_header:
{
outctx_t *ctx = va_arg(va, outctx_t *);
header(*ctx);
return 1;
}
case processor_t::ev_out_footer:
{
outctx_t *ctx = va_arg(va, outctx_t *);
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 *);
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 *);
segend(*ctx, seg);
return 1;
}
case processor_t::ev_ana_insn:
{
insn_t *out = va_arg(va, insn_t *);
return ana(out);
}
case processor_t::ev_emu_insn:
{
const insn_t *insn = va_arg(va, const insn_t *);
return 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_out_data:
{
outctx_t *ctx = va_arg(va, outctx_t *);
bool analyze_only = va_argi(va, bool);
data(*ctx, analyze_only);
return 1;
}
case processor_t::ev_out_special_item:
{
outctx_t *ctx = va_arg(va, outctx_t *);
uchar seg_type = va_argi(va, uchar);
outspec(*ctx, seg_type);
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;
}
//-------------------------------------------------------------------------
void tms6_t::upgrade_tnode(const netnode &old_tnode)
{
// copy branch/call info to HELPER
for ( nodeidx_t ndx = old_tnode.altfirst();
ndx != BADADDR;
ndx = old_tnode.altnext(ndx) )
{
nodeidx_t ndx2 = old_tnode.altval(ndx);
if ( ndx2 == 0 )
continue;
tgtinfo_t tgt;
switch ( ndx2 )
{
case 1:
tgt.type = tgtinfo_t::IND_BRANCH;
break;
case 2:
tgt.type = tgtinfo_t::IND_CALL;
break;
default:
{
ea_t target = node2ea(ndx2);
tgt.type = (target & 1) != 0
? tgtinfo_t::BRANCH
: tgtinfo_t::CALL;
tgt.target = target & ~1;
}
break;
}
tgt.save_to_idb(*this, node2ea(ndx));
}
}
//-------------------------------------------------------------------------
const char *tgtinfo_t::get_type_name() const
{
switch ( type )
{
case tgtinfo_t::CALL: return "CALL";
case tgtinfo_t::BRANCH: return "BRANCH";
case tgtinfo_t::IND_CALL: return "INDIRECT CALL";
case tgtinfo_t::IND_BRANCH: return "INDIRECT BRANCH";
}
return "";
}
//-------------------------------------------------------------------------
#define TGTINFO_MAX_SIZE (1 + ea_packed_size)
void tgtinfo_t::save_to_idb(tms6_t &pm, ea_t ea) const
{
uchar buf[TGTINFO_MAX_SIZE];
uchar *ptr = buf;
uchar *end = buf + sizeof(buf);
ptr = pack_db(ptr, end, uchar(type));
if ( has_target() )
ptr = pack_ea(ptr, end, ea2node(target));
pm.helper.supset_ea(ea, buf, ptr - buf);
}
//-------------------------------------------------------------------------
bool tgtinfo_t::restore_from_idb(const tms6_t &pm, ea_t ea)
{
uchar buf[TGTINFO_MAX_SIZE];
ssize_t code = pm.helper.supval_ea(ea, buf, sizeof(buf));
if ( code < 1 )
return false;
memory_deserializer_t mmdsr(buf, code);
uchar t = mmdsr.unpack_db();
if ( t > IND_BRANCH )
return false;
type = type_t(t);
if ( has_target() )
target = node2ea(mmdsr.unpack_ea());
return true;
}
//-----------------------------------------------------------------------
// TMS320C6x COFF Assembler
//-----------------------------------------------------------------------
static const asm_t dspasm =
{
AS_COLON | ASH_HEXF0 | ASD_DECF0 | ASB_BINF0 | ASO_OCTF5,
0,
"TMS320C6x COFF Assembler",
0,
NULL, // header lines
NULL, // org
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".string", // ascii string directive
".char", // byte directive
".short", // word directive
".long", // double words
NULL, // no qwords
NULL, // oword (16 bytes)
NULL, // 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
".set", // equ
NULL, // 'seg' prefix (example: push seg seg001)
"$", // current IP (instruction pointer)
NULL, // func_header
NULL, // func_footer
".def", // "public" name keyword
NULL, // "weak" name keyword
".ref", // "extrn" name keyword
".usect", // "comm" (communal variable)
NULL, // get_type_name
".align", // "align" keyword
'(', ')', // lbrace, rbrace
NULL, // mod
"&", // and
"|", // or
"^", // xor
"!", // not
"<<", // shl
">>", // shr
NULL, // sizeof
};
static const asm_t *const asms[] = { &dspasm, NULL };
//-----------------------------------------------------------------------
#define FAMILY "TMS320C6 series:"
static const char *const shnames[] = { "TMS320C6", NULL };
static const char *const lnames[] =
{
FAMILY"Texas Instruments TMS320C6xxx",
NULL
};
//--------------------------------------------------------------------------
static const uchar retcode_1[] = { 0x62, 0x63, 0x0C, 0x00 };
static const bytes_t retcodes[] =
{
{ sizeof(retcode_1), retcode_1 },
{ 0, NULL }
};
//-----------------------------------------------------------------------
// Processor Definition
//-----------------------------------------------------------------------
processor_t LPH =
{
IDP_INTERFACE_VERSION, // version
PLFM_TMSC6, // id
// flag
PR_USE32
| PR_DEFSEG32
| PR_DELAYED
| PR_ALIGN_INSN, // allow align instructions
// flag2
0,
8, // 8 bits in a byte for code segments
8, // 8 bits in a byte for other segments
shnames,
lnames,
asms,
notify,
RegNames, // Register names
qnumber(RegNames), // Number of registers
rVcs, // first
rVds, // last
0, // size of a segment register
rVcs, rVds,
NULL, // No known code start sequences
retcodes,
TMS6_null,
TMS6_last,
Instructions, // instruc
0, // int tbyte_size;
{ 2, 4, 8, 12 }, // char real_width[4];
TMS6_null, // Icode of return instruction. It is ok to give any of possible return instructions
};