update to ida 7.6, add builds
This commit is contained in:
783
idasdk76/module/oakdsp/ana.cpp
Normal file
783
idasdk76/module/oakdsp/ana.cpp
Normal file
@@ -0,0 +1,783 @@
|
||||
#include "oakdsp.hpp"
|
||||
|
||||
#define FUNCS_COUNT 5
|
||||
|
||||
struct funcdesc_t
|
||||
{
|
||||
bool (oakdsp_t:: *func)(insn_t &, int, int);
|
||||
uint32 mask;
|
||||
uint32 param;
|
||||
uint32 shift;
|
||||
};
|
||||
|
||||
struct opcode_t
|
||||
{
|
||||
const char *recog;
|
||||
ushort itype;
|
||||
funcdesc_t funcs[FUNCS_COUNT]; //lint !e958 padding is required to align members
|
||||
uchar cycles; // Number of cycles
|
||||
uint32 mask; //lint !e958 padding is required to align members
|
||||
uint32 value;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static uint32 ua_32bits(const insn_t &insn)
|
||||
{
|
||||
return ((get_wide_byte(insn.ea) << 0) & 0x0000FFFF)
|
||||
| ((get_wide_byte(insn.ea+1) << 16) & 0xFFFF0000);
|
||||
|
||||
}
|
||||
|
||||
//lint -e1762 member function could be made const
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void oakdsp_t::opreg(int reg)
|
||||
{
|
||||
op->type = o_reg;
|
||||
op->reg = uint16(reg);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void oakdsp_t::make_o_mem(const insn_t &insn)
|
||||
{
|
||||
if ( !(op->amode & amode_x) )
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
|
||||
case OAK_Dsp_callr:
|
||||
case OAK_Dsp_call:
|
||||
case OAK_Dsp_br_u:
|
||||
case OAK_Dsp_br:
|
||||
case OAK_Dsp_brr_u:
|
||||
case OAK_Dsp_brr:
|
||||
case OAK_Dsp_bkrep:
|
||||
op->type = o_near;
|
||||
op->dtype = dt_code;
|
||||
return;
|
||||
}
|
||||
}
|
||||
op->type = o_mem;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::rrrrr(insn_t &, int value, int param)
|
||||
{
|
||||
uint idx;
|
||||
if ( param & mix_mode )
|
||||
param = (param & 0xff) + value;
|
||||
idx = param ? param : value;
|
||||
|
||||
if ( idx >= PAGE )
|
||||
return false;
|
||||
opreg(idx);
|
||||
if ( op->reg == uchar(-1) )
|
||||
return false;
|
||||
|
||||
op++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//lint -e{1764} 'insn' could be declared const ref
|
||||
bool oakdsp_t::sdirect(insn_t &insn, int value, int)
|
||||
{
|
||||
op->amode = amode_short;
|
||||
op->addr = value & 0x00ff;
|
||||
op->amode |= amode_x;
|
||||
|
||||
make_o_mem(insn);
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::ldirect(insn_t &insn, int value,int)
|
||||
{
|
||||
op->amode = amode_long;
|
||||
op->addr = value & 0xffff;
|
||||
insn.size++;
|
||||
op->amode |= amode_x;
|
||||
|
||||
make_o_mem(insn);
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::A(insn_t &insn, int value,int)
|
||||
{
|
||||
return rrrrr(insn, value & 0x01, A0 + mix_mode);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::B(insn_t &insn, int value,int)
|
||||
{
|
||||
return rrrrr(insn, value & 0x01, B0 + mix_mode);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::mmnnn(insn_t &, int value,int)
|
||||
{
|
||||
if ( (value & 0x07) > 0x05 )
|
||||
return false;
|
||||
|
||||
op->type = o_phrase;
|
||||
op->reg = value & 0x07;
|
||||
op->phtype = (value & 0x0018) >> 3;
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::nnn(insn_t &insn, int value, int)
|
||||
{
|
||||
return rrrrr(insn, value & 0x07, R0 + mix_mode);
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::ALU_ALM(insn_t &insn, int value, int param)
|
||||
{
|
||||
if ( param && (value == 0x04 || value == 0x05) )
|
||||
return false;
|
||||
|
||||
insn.itype = OAK_Dsp_or + (value & (param ? 0x07 : 0x0f));
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::ALB(insn_t &insn, int value, int)
|
||||
{
|
||||
insn.itype = OAK_Dsp_set + (value & 0x07);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::MUL(insn_t &insn, int value, int param)
|
||||
{
|
||||
if ( param && (value > 0x03) )
|
||||
return false;
|
||||
|
||||
insn.itype = OAK_Dsp_mpy + ((value & (param ? 0x03 : 0x07)) << (param ? 0x01 : 0x00));
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::MODA_B(insn_t &insn, int value, int param)
|
||||
{
|
||||
if ( value == 0x07 )
|
||||
return false;
|
||||
|
||||
insn.itype = OAK_Dsp_shr + (value & (param ? 0x07 : 0x0f));
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//lint -e{1764} 'insn' could be declared const ref
|
||||
bool oakdsp_t::s_Imm(insn_t &insn, int value, int)
|
||||
{
|
||||
op->type = o_imm;
|
||||
op->value = value;
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_mpyi:
|
||||
op->amode |= amode_signed;
|
||||
break;
|
||||
}
|
||||
|
||||
op++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::s_ImmS(insn_t &, int value, int param)
|
||||
{
|
||||
uint mask1 = 1 << (param - 1);
|
||||
uint mask2 = 0;
|
||||
for ( int i = 0; i < param; i++ )
|
||||
mask2 |= (1 << i);
|
||||
|
||||
op->type = o_imm;
|
||||
op->value = (value & mask2);
|
||||
op->amode |= amode_signed;
|
||||
|
||||
if ( value & mask1 )
|
||||
op->value = - ((value^mask2) + 1);
|
||||
|
||||
op++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::l_Imm(insn_t &insn, int value, int)
|
||||
{
|
||||
op->type = o_imm;
|
||||
op->value = value & 0xffff;
|
||||
insn.size++;
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_maa:
|
||||
case OAK_Dsp_mac:
|
||||
case OAK_Dsp_macus:
|
||||
case OAK_Dsp_mpy:
|
||||
case OAK_Dsp_msu:
|
||||
op->amode |= amode_signed;
|
||||
break;
|
||||
}
|
||||
|
||||
op++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::rb_rel_short(insn_t &, int value, int)
|
||||
{
|
||||
op->type = o_local;
|
||||
op->phtype = 0; // "rb + #displ"
|
||||
op->amode |= amode_signed;
|
||||
|
||||
value &= 0x7f;
|
||||
|
||||
if ( value & 0x40 )
|
||||
value = - ((value^0x7f) + 1);
|
||||
|
||||
op->addr = value;
|
||||
op->amode |= amode_x;
|
||||
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::rb_rel_long(insn_t &insn, int value, int)
|
||||
{
|
||||
int16 tmp;
|
||||
|
||||
insn.size++;
|
||||
op->type = o_local;
|
||||
op->phtype = 0; // "rb + #displ"
|
||||
op->amode |= amode_signed;
|
||||
tmp = (value & 0xffff);
|
||||
op->addr = tmp;
|
||||
op->amode |= amode_x;
|
||||
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::Cond(insn_t &insn, int value, int param)
|
||||
{
|
||||
insn.auxpref |= value & 0x0f;
|
||||
|
||||
if ( (!param) && ((value & 0x0f) > 0x00) )
|
||||
insn.auxpref |= aux_comma_cc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::xe_xt(insn_t &insn, int value, int param)
|
||||
{
|
||||
static const uchar regs[] = { cc_ge, cc_gt, cc_le, cc_lt };
|
||||
|
||||
insn.auxpref |= regs[(value & 0x01) + (param ? 2 : 0)];
|
||||
insn.auxpref |= aux_comma_cc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::lim_xx(insn_t &, int value, int)
|
||||
{
|
||||
static const uchar regs1[] = { A0, A0, A1, A1 };
|
||||
static const uchar regs2[] = { uchar(-1), A1, A0, uchar(-1) };
|
||||
|
||||
opreg(regs1[value & 0x03]);
|
||||
|
||||
if ( regs2[value & 0x03] != uchar(-1) )
|
||||
{
|
||||
op++;
|
||||
opreg(regs2[value & 0x03]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::rJ_rI(insn_t &, int value,int param)
|
||||
{
|
||||
// jjiiwqq
|
||||
|
||||
op->type = o_phrase;
|
||||
op->reg = param ? (value & 0x03) : ((value & 0x04) >> 2) + 4;
|
||||
op->phtype = param ? (value & 0x0018) >> 3 : (value & 0x0060) >> 5;
|
||||
op++;
|
||||
|
||||
op->type = o_phrase;
|
||||
op->reg = param ? ((value & 0x04) >> 2) + 4 : (value & 0x03);
|
||||
op->phtype = param ? (value & 0x0060) >> 5 : (value & 0x0018) >> 3;
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::rI(insn_t &, int value,int)
|
||||
{
|
||||
// iiqq
|
||||
|
||||
op->type = o_phrase;
|
||||
op->reg = (value & 0x03);
|
||||
op->phtype = (value & 0x0c) >> 2;
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::AB(insn_t &, int value,int)
|
||||
{
|
||||
static const uchar regs[] = { B0, B1, A0, A1 };
|
||||
|
||||
opreg(regs[value & 0x03]);
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::ABLH(insn_t &, int value,int)
|
||||
{
|
||||
static const uchar regs[] = { B0L, B0H, B1L, B1H, A0L, A0H, A1L, A1H };
|
||||
|
||||
opreg(regs[value & 0x07]);
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::indir_reg(insn_t &, int value,int param)
|
||||
{
|
||||
op->type = o_phrase;
|
||||
op->reg = uint16(param + value);
|
||||
op->phtype = 4;
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::laddr_pgm(insn_t &insn, int value,int)
|
||||
{
|
||||
op->amode |= amode_p;
|
||||
op->addr = value & 0xffff;
|
||||
insn.size++;
|
||||
|
||||
make_o_mem(insn);
|
||||
op++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//lint -e{1764} 'insn' could be declared const ref
|
||||
bool oakdsp_t::addr_rel_pgm(insn_t &insn, int value, int)
|
||||
{
|
||||
value = (value & 0x7f);
|
||||
op->amode |= amode_p;
|
||||
|
||||
if ( value & 0x40 )
|
||||
{
|
||||
value = (value^0x7f) + 1;
|
||||
op->addr = insn.ea + 1 - value;
|
||||
}
|
||||
else
|
||||
{
|
||||
op->addr = insn.ea + 1 + value;
|
||||
}
|
||||
|
||||
make_o_mem(insn);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::ext_XX(insn_t &insn, int value, int)
|
||||
{
|
||||
return rrrrr(insn, (value & 0x01) + ((value & 0x04) >> 1), EXT0 + mix_mode);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::context(insn_t &insn, int value,int)
|
||||
{
|
||||
if ( value )
|
||||
insn.auxpref |= aux_iret_context;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::swap(insn_t &, int value,int)
|
||||
{
|
||||
op->type = o_textphrase;
|
||||
op->phrase = value & 0x0f;
|
||||
op->phtype = text_swap;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::banke(insn_t &, int value,int)
|
||||
{
|
||||
op->type = o_textphrase;
|
||||
op->phrase = value & 0x0f;
|
||||
op->phtype = text_banke;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::cntx(insn_t &, int value,int)
|
||||
{
|
||||
op->type = o_textphrase;
|
||||
op->phrase = (uint16)value;
|
||||
op->phtype = text_cntx;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::dmod(insn_t &, int value,int)
|
||||
{
|
||||
op->type = o_textphrase;
|
||||
op->phrase = (uint16)value;
|
||||
op->phtype = text_dmod;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::eu(insn_t &, int,int)
|
||||
{
|
||||
op->type = o_textphrase;
|
||||
op->phtype = text_eu;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// singleton to init table thread-aware
|
||||
struct table_t
|
||||
{
|
||||
static int count() { return qnumber(table); }
|
||||
static const opcode_t &get(int opcode)
|
||||
{
|
||||
static const table_t instance; //lint !e1788 only by its constructor/destructor
|
||||
return instance.table[opcode]; //lint !e727 static local symbol 'instance' of type 'const struct table_t' not explicitly initialized
|
||||
}
|
||||
|
||||
private:
|
||||
opcode_t table[124] =
|
||||
{
|
||||
{ "0000000000000000", OAK_Dsp_nop, {{0}}, 1 },
|
||||
{ "0000000000100000", OAK_Dsp_trap, {{0}}, 1 },
|
||||
{ "0000000010fmmnnn", OAK_Dsp_modr, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::dmod, 0x0020}}, 1 },
|
||||
{ "0000000001arrrrr", OAK_Dsp_movp, {{&oakdsp_t::indir_reg, 0x20, A0}, {&oakdsp_t::rrrrr, 0x001f}}, 3 },
|
||||
{ "000000010abrrrrr", OAK_Dsp_movs, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "000000011abmmnnn", OAK_Dsp_movs, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "00000100vvvvvvvv", OAK_Dsp_lpg, {{&oakdsp_t::s_Imm, 0x00ff}}, 1 },
|
||||
{ "00001000vvvvvvvv", OAK_Dsp_mpyi, {{&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::s_Imm, 0x00ff}}, 1 },
|
||||
{ "00000101vvvvvvvv", OAK_Dsp_mov, {{&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::rrrrr, 0, SV}}, 1 },
|
||||
{ "00001001vvvvvvvv", OAK_Dsp_rets, {{&oakdsp_t::s_Imm, 0x00ff}}, 3 },
|
||||
{ "00001101---rrrrr", OAK_Dsp_rep, {{&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "00001100vvvvvvvv", OAK_Dsp_rep, {{&oakdsp_t::s_Imm, 0x00ff}}, 1 },
|
||||
{ "0000011iiqqmmnnn", OAK_Dsp_movp, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::rI, 0x01e0}}, 3 },
|
||||
{ "0000111adddddddd", OAK_Dsp_divs, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "0000x01vvvvvvvvv", OAK_Dsp_load, {{&oakdsp_t::s_Imm, 0x01ff}, {&oakdsp_t::rrrrr, 0x0800, MODI|mix_mode}}, 1 },
|
||||
{ "000110rrrrrmmnnn", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x03e0}, {&oakdsp_t::mmnnn, 0x001f}}, 1 },
|
||||
{ "000111rrrrrmmnnn", OAK_Dsp_mov, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::rrrrr, 0x03e0}}, 1 },
|
||||
{ "00010ooooooocccc", OAK_Dsp_callr, {{&oakdsp_t::addr_rel_pgm, 0x07f0}, {&oakdsp_t::Cond, 0x000f}}, 2 },
|
||||
{ "0010nnn0dddddddd", OAK_Dsp_mov, {{&oakdsp_t::nnn, 0x0e00}, {&oakdsp_t::sdirect, 0x00ff}}, 1 },
|
||||
{ "001a0001vvvvvvvv", OAK_Dsp_mov, {{&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::rrrrr, 0x1000, A0L|mix_mode}}, 1 },
|
||||
{ "001a0101vvvvvvvv", OAK_Dsp_mov, {{&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::rrrrr, 0x1000, A0H|mix_mode}}, 1 },
|
||||
{ "001nnn11vvvvvvvv", OAK_Dsp_mov, {{&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::nnn, 0x1c00}}, 1 },
|
||||
{ "001x1x01vvvvvvvv", OAK_Dsp_mov, {{&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::ext_XX, 0x1400}}, 1 },
|
||||
{ "0011ABL0dddddddd", OAK_Dsp_mov, {{&oakdsp_t::ABLH, 0x0e00}, {&oakdsp_t::sdirect, 0x00ff}}, 1 },
|
||||
{ "0100001110000000", OAK_Dsp_eint, {{0}}, 1 },
|
||||
{ "0100001111000000", OAK_Dsp_dint, {{0}}, 1 },
|
||||
{ "0100000110000000", OAK_Dsp_br_u, {{&oakdsp_t::laddr_pgm, 0xffff0000}}, 2 },
|
||||
{ "0100010110000000", OAK_Dsp_ret_u, {{0}}, 2 },
|
||||
{ "01001101100000vv", OAK_Dsp_load, {{&oakdsp_t::s_Imm, 0x0003}, {&oakdsp_t::rrrrr, 0, PS}}, 1 },
|
||||
{ "01000101110f0000", OAK_Dsp_reti_u, {{&oakdsp_t::context, 0x0010}}, 2 },
|
||||
{ "010001011000cccc", OAK_Dsp_ret, {{&oakdsp_t::Cond, 0x000f, 1}}, 2 },
|
||||
{ "010000011000cccc", OAK_Dsp_br, {{&oakdsp_t::laddr_pgm, 0xffff0000}, {&oakdsp_t::Cond, 0x000f}}, 2 },
|
||||
{ "010000011100cccc", OAK_Dsp_call, {{&oakdsp_t::laddr_pgm, 0xffff0000}, {&oakdsp_t::Cond, 0x000f}}, 2 },
|
||||
{ "01000111110rrrrr", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0, MIXP}, {&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "01000111111rrrrr", OAK_Dsp_mov, {{&oakdsp_t::indir_reg, 0, SP}, {&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "01000101110fcccc", OAK_Dsp_reti, {{&oakdsp_t::Cond, 0x000f, 1}, {&oakdsp_t::context, 0x0010}}, 1 },
|
||||
{ "0100100110--swap", OAK_Dsp_swap, {{&oakdsp_t::swap, 0x000f}}, 1 },
|
||||
{ "0100111111-rrrrr", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::rrrrr, 0, ICR}}, 1 },
|
||||
{ "0100111110-vvvvv", OAK_Dsp_mov, {{&oakdsp_t::s_Imm, 0x001f}, {&oakdsp_t::rrrrr, 0, ICR}}, 1 },
|
||||
{ "0100100111xx----", OAK_Dsp_lim, {{&oakdsp_t::lim_xx, 0x0030}}, 1 },
|
||||
{ "010010111---bank", OAK_Dsp_banke, {{&oakdsp_t::banke, 0x000f}}, 1 },
|
||||
{ "0100nnn01abvvvvv", OAK_Dsp_movsi, {{&oakdsp_t::nnn, 0x0e00}, {&oakdsp_t::AB, 0x0060}, {&oakdsp_t::s_ImmS, 0x001f, 5}}, 1 },
|
||||
{ "0100xxxa0ooooooo", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x0e00, 1}, {&oakdsp_t::rb_rel_short, 0x007f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "0101111101000000", OAK_Dsp_push, {{&oakdsp_t::l_Imm, 0xffff0000}}, 2 },
|
||||
{ "01011110010rrrrr", OAK_Dsp_push, {{&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "01011110011rrrrr", OAK_Dsp_pop, {{&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "01011110100rrrrr", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::rrrrr, 0, MIXP}}, 1 },
|
||||
{ "0101111011brrrrr", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::B, 0x0020}}, 1 },
|
||||
{ "01011101000rrrrr", OAK_Dsp_bkrep, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::laddr_pgm, 0xffff0000}}, 2 },
|
||||
{ "0101111-000rrrrr", OAK_Dsp_mov, {{&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::rrrrr, 0x001f}}, 2 },
|
||||
{ "0101111b001-----", OAK_Dsp_mov, {{&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::B, 0x0100}}, 2 },
|
||||
{ "010111111jjiiwqq", OAK_Dsp_movd, {{&oakdsp_t::rJ_rI, 0x007f, 1}}, 4 },
|
||||
{ "01011100vvvvvvvv", OAK_Dsp_bkrep, {{&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::laddr_pgm, 0xffff0000}}, 2 },
|
||||
{ "010110RRRRRrrrrr", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::rrrrr, 0x03e0}}, 1 },
|
||||
{ "01010ooooooo0000", OAK_Dsp_brr_u, {{&oakdsp_t::addr_rel_pgm, 0x07f0}}, 2 },
|
||||
{ "01010ooooooocccc", OAK_Dsp_brr, {{&oakdsp_t::addr_rel_pgm, 0x07f0}, {&oakdsp_t::Cond, 0x000f}}, 2 },
|
||||
{ "01101101dddddddd", OAK_Dsp_mov, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::rrrrr, 0, SV}}, 1 },
|
||||
{ "011nnn00dddddddd", OAK_Dsp_mov, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::nnn, 0x1c00}}, 1 },
|
||||
{ "011AB001dddddddd", OAK_Dsp_mov, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::AB, 0x1800}}, 1 },
|
||||
{ "011ABL10dddddddd", OAK_Dsp_mov, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::ABLH, 0x1c00}}, 1 },
|
||||
{ "011A0101dddddddd", OAK_Dsp_mov_eu, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::A, 0x1000}, {&oakdsp_t::eu, 0x0}}, 1 },
|
||||
{ "011ab011dddddddd", OAK_Dsp_movs, {{&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::AB, 0x1800}}, 1 },
|
||||
{ "011b11110fffcccc", OAK_Dsp_proc, {{&oakdsp_t::MODA_B, 0x0070, 1}, {&oakdsp_t::B, 0x1000}, {&oakdsp_t::Cond, 0x000f}}, 1 },
|
||||
{ "011a0111ffffcccc", OAK_Dsp_proc, {{&oakdsp_t::MODA_B, 0x00f0}, {&oakdsp_t::A, 0x1000}, {&oakdsp_t::Cond, 0x000f}}, 1 },
|
||||
{ "01111101dddddddd", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0, SV}, {&oakdsp_t::sdirect, 0x00ff}}, 1 },
|
||||
{ "100000fa011mm000", OAK_Dsp_maxd, {{&oakdsp_t::A, 0x0100}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::xe_xt, 0x0200, 0}}, 1 },
|
||||
{ "100001fa011mm000", OAK_Dsp_max, {{&oakdsp_t::A, 0x0100}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::xe_xt, 0x0200, 0}}, 1 },
|
||||
{ "10001-fa011mm000", OAK_Dsp_min, {{&oakdsp_t::A, 0x0100}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::xe_xt, 0x0200, 1}}, 1 },
|
||||
{ "1000xxxa11000000", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x0e00, 1}, {&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::A, 0x0100}}, 2 },
|
||||
{ "1000xxx0111mmnnn", OAK_Dsp_proc, {{&oakdsp_t::ALB, 0x0e00}, {&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::mmnnn, 0x001f}}, 2 },
|
||||
{ "1000xxx1111rrrrr", OAK_Dsp_proc, {{&oakdsp_t::ALB, 0x0e00}, {&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::rrrrr, 0x001f}}, 2 },
|
||||
{ "1000-00x001mmnnn", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::mmnnn, 0x001f}}, 1 },
|
||||
{ "1000axxx001mmnnn", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::A, 0x0800}}, 1 },
|
||||
{ "1000-00x010rrrrr", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "1000axxx010rrrrr", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::A, 0x0800}}, 1 },
|
||||
{ "1000-00x000mmnnn", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::l_Imm, 0xffff0000}}, 2 },
|
||||
{ "1000axxx000mmnnn", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::A, 0x0800}}, 2 },
|
||||
{ "100xxxxa100mmnnn", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x1e00}, {&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "100xxxxa101rrrrr", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x1e00}, {&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1001000a110mmnnn", OAK_Dsp_msu, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::A, 0x0100}}, 2 },
|
||||
{ "1001010a110mmnnn", OAK_Dsp_norm, {{&oakdsp_t::A, 0x0100}, {&oakdsp_t::mmnnn, 0x001f}}, 2 },
|
||||
{ "1001bbbb001mmnnn", OAK_Dsp_tstb, {{&oakdsp_t::s_Imm, 0x0f00}, {&oakdsp_t::mmnnn, 0x001f}}, 1 },
|
||||
{ "1001bbbb000rrrrr", OAK_Dsp_tstb, {{&oakdsp_t::s_Imm, 0x0f00}, {&oakdsp_t::rrrrr, 0x001f}}, 1 },
|
||||
{ "1001ab1AB1vvvvvv", OAK_Dsp_shfi, {{&oakdsp_t::AB, 0x0c00}, {&oakdsp_t::AB, 0x0180}, {&oakdsp_t::s_ImmS, 0x003f, 6}}, 1 },
|
||||
{ "1001100a010mmnnn", OAK_Dsp_exp, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1001000a010rrrrr", OAK_Dsp_exp, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1001000a0110000b", OAK_Dsp_exp, {{&oakdsp_t::B, 0x0001}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "10011100010mmnnn", OAK_Dsp_exp, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::rrrrr, 0, SV}}, 1 },
|
||||
{ "10010100010rrrrr", OAK_Dsp_exp, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::rrrrr, 0, SV}}, 1 },
|
||||
{ "100101000110000b", OAK_Dsp_exp, {{&oakdsp_t::B, 0x0001}, {&oakdsp_t::rrrrr, 0, SV}}, 1 },
|
||||
{ "1001100b110mmnnn", OAK_Dsp_mov, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::B, 0x0100}}, 1 },
|
||||
{ "1001110a110rrrrr", OAK_Dsp_movr, {{&oakdsp_t::rrrrr, 0x001f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1001110a111mmnnn", OAK_Dsp_movr, {{&oakdsp_t::mmnnn, 0x001f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "101xxxxadddddddd", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x1e00}, {&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1100xxxavvvvvvvv", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x0e00, 1}, {&oakdsp_t::s_Imm, 0x00ff}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1101001111000000", OAK_Dsp_break, {{0}}, 1 },
|
||||
{ "1101011110000000", OAK_Dsp_retd, {{0}}, 1 },
|
||||
{ "1101011111000000", OAK_Dsp_retid, {{0}}, 1 },
|
||||
{ "1101010a10000000", OAK_Dsp_calla, {{&oakdsp_t::A, 0x0100}}, 3 },
|
||||
{ "11010011100f0000", OAK_Dsp_cntx, {{&oakdsp_t::cntx, 0x0010}}, 1 },
|
||||
{ "110101001ab10000", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0,REPC}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "110101001ab10001", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0,DVM}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "110101001ab10010", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0,ICR}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "110101001ab10011", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0,X}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "1101010a101110--", OAK_Dsp_mov, {{&oakdsp_t::ldirect, 0xffff0000}, {&oakdsp_t::A, 0x0100}}, 2 },
|
||||
{ "1101010a101111--", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x0100, A0L|mix_mode}, {&oakdsp_t::ldirect, 0xffff0000}}, 2 },
|
||||
{ "1101010a100110--", OAK_Dsp_mov, {{&oakdsp_t::rb_rel_long,0xffff0000}, {&oakdsp_t::A, 0x0100}}, 2 },
|
||||
{ "1101010a100111--", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x0100, A0L|mix_mode}, {&oakdsp_t::rb_rel_long,0xffff0000}}, 2 },
|
||||
{ "1101010a11011xxx", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x0007, 1}, {&oakdsp_t::rb_rel_long, 0xffff0000}, {&oakdsp_t::A, 0x0100}}, 2 },
|
||||
{ "1101010a11111xxx", OAK_Dsp_proc, {{&oakdsp_t::ALU_ALM, 0x0007, 1}, {&oakdsp_t::ldirect, 0xffff0000}, {&oakdsp_t::A, 0x0100}}, 2 },
|
||||
{ "1101AB1011011000", OAK_Dsp_mov, {{&oakdsp_t::AB, 0x0c00}, {&oakdsp_t::rrrrr, 0x0000, X}}, 1 },
|
||||
{ "1101AB1010011000", OAK_Dsp_mov, {{&oakdsp_t::AB, 0x0c00}, {&oakdsp_t::rrrrr, 0x0000, DVM}}, 1 },
|
||||
{ "1101ab101AB10000", OAK_Dsp_mov, {{&oakdsp_t::AB, 0x0c00}, {&oakdsp_t::AB, 0x0060}}, 1 },
|
||||
{ "1101000a1jjiiwqq", OAK_Dsp_msu, {{&oakdsp_t::rJ_rI, 0x007f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1101ab101AB0cccc", OAK_Dsp_shfc, {{&oakdsp_t::AB, 0x0c00}, {&oakdsp_t::AB, 0x0060}, {&oakdsp_t::Cond, 0x000f}}, 1 },
|
||||
{ "1101100a1ooooooo", OAK_Dsp_mov, {{&oakdsp_t::rb_rel_short, 0x007f}, {&oakdsp_t::A, 0x0100}}, 1 },
|
||||
{ "1101110a1ooooooo", OAK_Dsp_mov, {{&oakdsp_t::rrrrr, 0x0100, A0L|mix_mode}, {&oakdsp_t::rb_rel_short, 0x007f}}, 1 },
|
||||
{ "11011x111vvvvvvv", OAK_Dsp_load, {{&oakdsp_t::s_Imm, 0x007f}, {&oakdsp_t::rrrrr, 0x0400, STEPI|mix_mode}}, 1 },
|
||||
{ "1101-00x0jjiiwqq", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::rJ_rI, 0x007f}}, 1 },
|
||||
{ "1101axxx0jjiiwqq", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0700}, {&oakdsp_t::rJ_rI, 0x007f}, {&oakdsp_t::A, 0x0800}}, 1 },
|
||||
{ "1110xxx1dddddddd", OAK_Dsp_proc, {{&oakdsp_t::ALB, 0x0e00}, {&oakdsp_t::l_Imm, 0xffff0000}, {&oakdsp_t::sdirect, 0x00ff}}, 2 },
|
||||
{ "1110-000dddddddd", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0600, 1}, {&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::sdirect, 0x00ff}}, 1 },
|
||||
{ "1110axx0dddddddd", OAK_Dsp_proc, {{&oakdsp_t::MUL, 0x0600, 1}, {&oakdsp_t::rrrrr, 0, Y}, {&oakdsp_t::sdirect, 0x00ff}, {&oakdsp_t::A, 0x0800}}, 1 },
|
||||
{ "1111bbbbdddddddd", OAK_Dsp_tstb, {{&oakdsp_t::s_Imm, 0x0f00}, {&oakdsp_t::sdirect, 0x00ff}}, 1 },
|
||||
};
|
||||
|
||||
table_t()
|
||||
{
|
||||
gen_masks();
|
||||
}
|
||||
~table_t() = default;
|
||||
table_t(const table_t&) = delete;
|
||||
table_t &operator=(const table_t&) = delete;
|
||||
|
||||
void gen_masks()
|
||||
{
|
||||
for ( auto &te : table )
|
||||
{
|
||||
int len = strlen(te.recog);
|
||||
for ( int b = 0; b < len; b++ )
|
||||
{
|
||||
te.value <<= 1;
|
||||
te.mask <<= 1;
|
||||
|
||||
if ( te.recog[b] == '1' || te.recog[b] == '0' )
|
||||
te.mask++;
|
||||
|
||||
if ( te.recog[b] == '1' )
|
||||
te.value++;
|
||||
}
|
||||
|
||||
for ( int j = 0; j < FUNCS_COUNT; j++ )
|
||||
{
|
||||
if ( te.funcs[j].func )
|
||||
{
|
||||
for ( int b = 0; b < 32; b++ )
|
||||
{
|
||||
if ( te.funcs[j].mask & (1 << b) )
|
||||
break;
|
||||
else
|
||||
te.funcs[j].shift++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool oakdsp_t::use_table(insn_t &insn, const opcode_t &ptr, uint code, int start, int end)
|
||||
{
|
||||
for ( int j = start; j <= end; j++ )
|
||||
{
|
||||
if ( !ptr.funcs[j].func )
|
||||
break;
|
||||
int value = (code & ptr.funcs[j].mask) >> ptr.funcs[j].shift;
|
||||
if ( !(this->*ptr.funcs[j].func)(insn, value, ptr.funcs[j].param) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void oakdsp_t::reset_ops(insn_t &insn)
|
||||
{
|
||||
op = &insn.Op1;
|
||||
for ( int i=0; i < UA_MAXOP; i++ )
|
||||
insn.ops[i].type = o_void;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int oakdsp_t::ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
uint code = ua_32bits(insn);
|
||||
uint prev_inst_code;
|
||||
op = &insn.Op1;
|
||||
int move_rb_to_reg = 0;
|
||||
|
||||
int cnt = table_t::count();
|
||||
for ( int i = 0; i < cnt; i++ )
|
||||
{
|
||||
const auto &te = table_t::get(i);
|
||||
if ( (code & te.mask) == te.value )
|
||||
{
|
||||
insn.itype = te.itype;
|
||||
insn.cmd_cycles = te.cycles;
|
||||
insn.size = 1;
|
||||
|
||||
if ( !use_table(insn, te, code, 0, FUNCS_COUNT - 1) )
|
||||
{
|
||||
reset_ops(insn);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mov #imm, pc --> near jump
|
||||
if ( insn.itype == OAK_Dsp_mov
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == PC )
|
||||
{
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.addr = insn.Op1.value;
|
||||
insn.Op1.amode = amode_p;
|
||||
}
|
||||
|
||||
|
||||
// add(sub) #imm, reg after mov rb, reg instruction
|
||||
// #imm --> local var
|
||||
|
||||
if ( insn.ea != 0 )
|
||||
{
|
||||
prev_inst_code = get_wide_byte(insn.ea - 1);
|
||||
|
||||
if ( ((prev_inst_code & 0xfc1f) == 0x5806)
|
||||
|| ((prev_inst_code & 0xffdf) == 0x5ec6) )
|
||||
{
|
||||
if ( (prev_inst_code & 0xfc1f) == 0x5806 ) // mov reg, reg
|
||||
move_rb_to_reg = (prev_inst_code >> 5) & 0x1f;
|
||||
else if ( (prev_inst_code & 0xffdf) == 0x5ec6 ) // mov reg, bx
|
||||
move_rb_to_reg = B0 + ((prev_inst_code >> 5) & 0x01);
|
||||
|
||||
if ( insn.Op1.type == o_imm
|
||||
&& (insn.Op2.reg == move_rb_to_reg
|
||||
|| (insn.Op2.reg == A0L && move_rb_to_reg == A0)
|
||||
|| (insn.Op2.reg == A1L && move_rb_to_reg == A1)
|
||||
|| (insn.Op2.reg == B0L && move_rb_to_reg == B0)
|
||||
|| (insn.Op2.reg == B1L && move_rb_to_reg == B1)) )
|
||||
{
|
||||
int16 tmp = insn.Op1.value;
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_sub:
|
||||
case OAK_Dsp_subv:
|
||||
tmp = - tmp;
|
||||
//no break
|
||||
case OAK_Dsp_add:
|
||||
case OAK_Dsp_addv:
|
||||
insn.Op1.addr = tmp;
|
||||
insn.Op1.type = o_local;
|
||||
insn.Op1.phtype = 1; // "#"
|
||||
insn.Op1.amode |= amode_signed;
|
||||
insn.Op1.amode |= amode_x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add(sub) #imm, SP
|
||||
// #imm --> signed imm
|
||||
|
||||
if ( insn.Op1.type == o_imm && insn.Op2.type == o_reg && insn.Op2.reg == SP )
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_add:
|
||||
case OAK_Dsp_addv:
|
||||
case OAK_Dsp_sub:
|
||||
case OAK_Dsp_subv:
|
||||
insn.Op1.amode |= amode_signed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void interr(const insn_t &insn, const char *module)
|
||||
{
|
||||
const char *name = NULL;
|
||||
if ( insn.itype < OAK_Dsp_last )
|
||||
name = Instructions[insn.itype].name;
|
||||
warning("%a(%s): internal error in %s", insn.ea, name, module);
|
||||
}
|
||||
420
idasdk76/module/oakdsp/emu.cpp
Normal file
420
idasdk76/module/oakdsp/emu.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
|
||||
#include "oakdsp.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <frame.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t oakdsp_t::calc_mem(const insn_t &insn, const op_t &x) const
|
||||
{
|
||||
uint xaddr;
|
||||
|
||||
if ( x.amode & amode_x )
|
||||
{
|
||||
if ( x.amode & amode_short )
|
||||
{
|
||||
sel_t dpage = get_sreg(insn.ea, PAGE);
|
||||
if ( dpage == BADSEL )
|
||||
return BADSEL;
|
||||
xaddr = ((dpage & 0xFF) << 8) | uint(x.addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
xaddr = (uint)x.addr;
|
||||
}
|
||||
return xmem == BADADDR ? BADADDR : xmem + xaddr;
|
||||
}
|
||||
|
||||
return to_ea(insn.cs, x.addr);
|
||||
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void oakdsp_t::init_emu(void)
|
||||
{
|
||||
delayed = false;
|
||||
cycles = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline bool is_stkreg(int r)
|
||||
{
|
||||
return r == SP;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &x)
|
||||
{
|
||||
return OP_SP_ADD | (x.phrase == SP ? OP_SP_BASED : OP_FP_BASED);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void process_immediate_number(const insn_t &insn, int n)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(get_flags(insn.ea), n) )
|
||||
return;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_shfi:
|
||||
case OAK_Dsp_movsi:
|
||||
|
||||
op_dec(insn.ea, n);
|
||||
break;
|
||||
|
||||
case OAK_Dsp_lpg:
|
||||
case OAK_Dsp_mpyi:
|
||||
case OAK_Dsp_mov:
|
||||
case OAK_Dsp_rets:
|
||||
case OAK_Dsp_rep:
|
||||
case OAK_Dsp_load:
|
||||
case OAK_Dsp_push:
|
||||
case OAK_Dsp_bkrep:
|
||||
case OAK_Dsp_msu:
|
||||
case OAK_Dsp_tstb:
|
||||
case OAK_Dsp_or:
|
||||
case OAK_Dsp_and:
|
||||
case OAK_Dsp_xor:
|
||||
case OAK_Dsp_add:
|
||||
case OAK_Dsp_alm_tst0:
|
||||
case OAK_Dsp_alm_tst1:
|
||||
case OAK_Dsp_cmp:
|
||||
case OAK_Dsp_sub:
|
||||
case OAK_Dsp_alm_msu:
|
||||
case OAK_Dsp_addh:
|
||||
case OAK_Dsp_addl:
|
||||
case OAK_Dsp_subh:
|
||||
case OAK_Dsp_subl:
|
||||
case OAK_Dsp_sqr:
|
||||
case OAK_Dsp_sqra:
|
||||
case OAK_Dsp_cmpu:
|
||||
case OAK_Dsp_set:
|
||||
case OAK_Dsp_rst:
|
||||
case OAK_Dsp_chng:
|
||||
case OAK_Dsp_addv:
|
||||
case OAK_Dsp_alb_tst0:
|
||||
case OAK_Dsp_alb_tst1:
|
||||
case OAK_Dsp_cmpv:
|
||||
case OAK_Dsp_subv:
|
||||
case OAK_Dsp_mpy:
|
||||
case OAK_Dsp_mpysu:
|
||||
case OAK_Dsp_mac:
|
||||
case OAK_Dsp_macus:
|
||||
case OAK_Dsp_maa:
|
||||
case OAK_Dsp_macuu:
|
||||
case OAK_Dsp_macsu:
|
||||
case OAK_Dsp_maasu:
|
||||
|
||||
op_num(insn.ea, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void oakdsp_t::add_near_ref(const insn_t &insn, const op_t &x, ea_t ea)
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void oakdsp_t::handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
default:
|
||||
break;
|
||||
case o_imm:
|
||||
process_immediate_number(insn, x.n);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, x.amode & amode_signed ? OOF_SIGNED : 0);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
if ( !is_forced && op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
{
|
||||
ea_t ea = insn.add_off_drefs(x, isload ? dr_R : dr_W, OOF_ADDR|OOFW_16);
|
||||
if ( ea != BADADDR )
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = calc_mem(insn, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_near:
|
||||
add_near_ref(insn, x, calc_mem(insn, x));
|
||||
break;
|
||||
case o_textphrase:
|
||||
break;
|
||||
|
||||
case o_local: // local variables
|
||||
if ( may_create_stkvars() )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL
|
||||
&& (pfn->flags & FUNC_FRAME) != 0
|
||||
&& insn.create_stkvar(x, x.addr, STKVAR_VALID_SIZE) )
|
||||
{
|
||||
op_stkvar(insn.ea, x.n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
|
||||
int16 frame;
|
||||
|
||||
// trace SP changes
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_reti_u:
|
||||
case OAK_Dsp_retid:
|
||||
case OAK_Dsp_reti:
|
||||
add_stkpnt(insn, 1);
|
||||
break;
|
||||
|
||||
case OAK_Dsp_ret_u:
|
||||
case OAK_Dsp_retd:
|
||||
case OAK_Dsp_ret:
|
||||
add_stkpnt(insn, 1);
|
||||
break;
|
||||
|
||||
case OAK_Dsp_rets:
|
||||
add_stkpnt(insn, 1 + insn.Op1.value);
|
||||
break;
|
||||
|
||||
case OAK_Dsp_pop:
|
||||
add_stkpnt(insn, 1);
|
||||
break;
|
||||
|
||||
case OAK_Dsp_push:
|
||||
add_stkpnt(insn, -1);
|
||||
break;
|
||||
|
||||
case OAK_Dsp_addv:
|
||||
if ( insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == SP )
|
||||
{
|
||||
frame = (uint16)insn.Op1.value;
|
||||
add_stkpnt(insn, frame);
|
||||
}
|
||||
break;
|
||||
|
||||
case OAK_Dsp_subv:
|
||||
if ( insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == SP )
|
||||
{
|
||||
frame = (uint16)insn.Op1.value;
|
||||
add_stkpnt(insn, -frame);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int oakdsp_t::emu(const insn_t &insn)
|
||||
{
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
return 1;
|
||||
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
// Determine if the next instruction should be executed
|
||||
flow = (has_insn_feature(insn.itype, CF_STOP) != true);
|
||||
|
||||
if ( has_insn_feature(insn.itype,CF_USE1) ) handle_operand(insn, insn.Op1, flag1, true);
|
||||
if ( has_insn_feature(insn.itype,CF_USE2) ) handle_operand(insn, insn.Op2, flag2, true);
|
||||
if ( has_insn_feature(insn.itype,CF_USE3) ) handle_operand(insn, insn.Op3, flag3, true);
|
||||
|
||||
if ( has_insn_feature(insn.itype,CF_CHG1) ) handle_operand(insn, insn.Op1, flag1, false);
|
||||
if ( has_insn_feature(insn.itype,CF_CHG2) ) handle_operand(insn, insn.Op2, flag2, false);
|
||||
if ( has_insn_feature(insn.itype,CF_CHG3) ) handle_operand(insn, insn.Op3, flag3, false);
|
||||
|
||||
|
||||
// check for DP changes
|
||||
if ( insn.itype == OAK_Dsp_lpg )
|
||||
split_sreg_range(get_item_end(insn.ea), PAGE, insn.Op1.value & 0xFF, SR_auto);
|
||||
if ( insn.itype == OAK_Dsp_mov
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == ST1 )
|
||||
{
|
||||
split_sreg_range(get_item_end(insn.ea), PAGE, insn.Op1.value & 0xFF, SR_auto);
|
||||
}
|
||||
|
||||
// Delayed Return
|
||||
|
||||
cycles = insn.cmd_cycles;
|
||||
delayed = false;
|
||||
|
||||
insn_t prev_ins;
|
||||
if ( decode_prev_insn(&prev_ins, insn.ea) != BADADDR )
|
||||
{
|
||||
if ( prev_ins.itype == OAK_Dsp_retd || prev_ins.itype == OAK_Dsp_retid )
|
||||
delayed = true;
|
||||
else
|
||||
cycles += prev_ins.cmd_cycles;
|
||||
|
||||
if ( !delayed )
|
||||
if ( decode_prev_insn(&prev_ins, prev_ins.ea) != BADADDR )
|
||||
if ( prev_ins.itype == OAK_Dsp_retd || prev_ins.itype == OAK_Dsp_retid )
|
||||
delayed = true;
|
||||
}
|
||||
|
||||
if ( delayed && (cycles > 1) )
|
||||
flow = false;
|
||||
|
||||
// mov #imm, pc
|
||||
|
||||
if ( insn.itype == OAK_Dsp_mov && insn.Op2.type == o_reg && insn.Op2.reg == PC )
|
||||
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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int may_be_func(const insn_t &) // can a function start here?
|
||||
// arg: none, the instruction is in 'insn'
|
||||
// returns: probability 0..100
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int oakdsp_t::is_sane_insn(const insn_t &insn, int /*nocrefs*/) const
|
||||
{
|
||||
// disallow jumps to nowhere
|
||||
if ( insn.Op1.type == o_near && !is_mapped(calc_mem(insn, insn.Op1)) )
|
||||
return 0;
|
||||
|
||||
// disallow many nops in a now
|
||||
int i = 0;
|
||||
for ( ea_t ea=insn.ea; i < 32; i++,ea++ )
|
||||
if ( get_byte(ea) != 0 )
|
||||
break;
|
||||
if ( i == 32 )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
return 0;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_nop:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool idaapi create_func_frame(func_t *pfn) // create frame of newly created function
|
||||
{
|
||||
bool std_vars_func = true;
|
||||
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
if ( pfn->frame == BADNODE )
|
||||
{
|
||||
ea_t ea = pfn->start_ea;
|
||||
int regsize = 0;
|
||||
|
||||
insn_t insn;
|
||||
while ( ea < pfn->end_ea ) // check for register pushes
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
ea += insn.size; // count pushes
|
||||
if ( (insn.itype == OAK_Dsp_push) && (insn.Op1.type == o_reg) )
|
||||
regsize++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ea = pfn->start_ea;
|
||||
int16 localsize = 0;
|
||||
while ( ea < pfn->end_ea ) // check for frame creation
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
ea += insn.size; // try to detect ADDV #,SP
|
||||
if ( (insn.itype == OAK_Dsp_addv) && (insn.Op1.type == o_imm) && (insn.Op2.type == o_reg) && (insn.Op2.reg == SP) )
|
||||
{
|
||||
localsize = (uint16)insn.Op1.value;
|
||||
break;
|
||||
}
|
||||
|
||||
// if found mov #, rb --> do not create frame
|
||||
if ( (insn.itype == OAK_Dsp_mov) && (insn.Op1.type == o_imm) && (insn.Op2.type == o_reg) && (insn.Op2.reg == RB) )
|
||||
{
|
||||
std_vars_func = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( std_vars_func )
|
||||
{
|
||||
pfn->flags |= FUNC_FRAME;
|
||||
update_func(pfn);
|
||||
}
|
||||
|
||||
add_frame(pfn, -localsize, (ushort)regsize, 0);
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi OAK_get_frame_retsize(const func_t * /*pfn*/)
|
||||
{
|
||||
return 1; // 1 'byte' for the return address
|
||||
}
|
||||
123
idasdk76/module/oakdsp/ins.cpp
Normal file
123
idasdk76/module/oakdsp/ins.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
|
||||
#include "oakdsp.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
{ "", 0 }, // cmd need further process
|
||||
// ALU-ALM subcodes
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG2 }, // 000 Logical Or
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG2 }, // 001 And
|
||||
{ "xor", CF_USE1|CF_USE2|CF_CHG2 }, // 010 Exclusive Or
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG2 }, // 011 Add
|
||||
{ "tst0", CF_USE1|CF_USE2 }, // 100 Test Bit-field for Zeros
|
||||
{ "tst1", CF_USE1|CF_USE2 }, // 101 Test Bit-field for Ones
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // 110 Compare
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG2 }, // 111 Subtract
|
||||
// ALM subcodes
|
||||
{ "msu", CF_USE1|CF_USE2|CF_CHG2 }, // 1000 Multiply and Subtract Previous Product
|
||||
{ "addh", CF_USE1|CF_USE2|CF_CHG2 }, // 1001 Add to High Accumulator
|
||||
{ "addl", CF_USE1|CF_USE2|CF_CHG2 }, // 1010 Add to Low Accumulator
|
||||
{ "subh", CF_USE1|CF_USE2|CF_CHG2 }, // 1011 Subtract from High Accumulator
|
||||
{ "subl", CF_USE1|CF_USE2|CF_CHG2 }, // 1100 Subtract from Low Accumulator
|
||||
{ "sqr", CF_USE1|CF_USE2|CF_CHG2 }, // 1101 Square
|
||||
{ "sqra", CF_USE1|CF_USE2|CF_CHG2 }, // 1110 Square and Accumulate Previous Product
|
||||
{ "cmpu", CF_USE1|CF_USE2 }, // 1111 Compare Unsigned
|
||||
// MODA-MODB subcodes conditional
|
||||
{ "shr", CF_USE1|CF_CHG1 }, // 000 Shift Accumulator Right
|
||||
{ "shr4", CF_USE1|CF_CHG1 }, // 001 Shift Accumulator Right by 4 Bits
|
||||
{ "shl", CF_USE1|CF_CHG1 }, // 010 Shift Accumulator Left
|
||||
{ "shl4", CF_USE1|CF_CHG1 }, // 011 Shift Accumulator Left by 4 Bits
|
||||
{ "ror", CF_USE1|CF_CHG1 }, // 100 Rotate Accumulator Right through Carry
|
||||
{ "rol", CF_USE1|CF_CHG1 }, // 101 Rotate Accumulator Left through Carry
|
||||
{ "clr", CF_CHG1 }, // 110 Clear Accumulator
|
||||
{ "", 0 }, // 111 Mod Reserved
|
||||
// MODA subcodes conditional
|
||||
{ "not", CF_USE1|CF_CHG1 }, // 1000 Logical Not
|
||||
{ "neg", CF_USE1|CF_CHG1 }, // 1001 2's Complement of aX-accumulator
|
||||
{ "rnd", CF_USE1|CF_CHG1 }, // 1010 Round Upper 20 Bits of aX-accumulator
|
||||
{ "pacr", CF_USE1|CF_CHG1 }, // 1011 Product Move and Round to aX-accumulator
|
||||
{ "clrr", CF_USE1|CF_CHG1 }, // 1100 Clear and Round aX-accumulator
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // 1101 Increment Accumulator by One
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // 1110 Decrement aX-accumulator by One
|
||||
{ "copy", CF_USE1|CF_CHG1 }, // 1111 Copy aX-accumulator
|
||||
// ---
|
||||
{ "norm", CF_USE1|CF_CHG1|CF_USE2 }, // Normalize
|
||||
{ "divs", CF_USE1|CF_USE2|CF_CHG2 }, // Division Step
|
||||
// ALB subcodes
|
||||
{ "set", CF_USE1|CF_USE2|CF_CHG2 }, // 000 Set Bit-field
|
||||
{ "rst", CF_USE1|CF_USE2|CF_CHG2 }, // 001 Reset Bit-field
|
||||
{ "chng", CF_USE1|CF_USE2|CF_CHG2 }, // 010 Change Bit-field
|
||||
{ "addv", CF_USE1|CF_USE2|CF_CHG2 }, // 011 Add Long Immediate Value or Data Memory Location
|
||||
{ "tst0", CF_USE1|CF_USE2 }, // 100 Test Bit-field for Zeros
|
||||
{ "tst1", CF_USE1|CF_USE2 }, // 101 Test Bit-field for Ones
|
||||
{ "cmpv", CF_USE1|CF_USE2 }, // 110 Compare Long Immediate Value to Register or Data Memory Location
|
||||
{ "subv", CF_USE1|CF_USE2|CF_CHG2 }, // 111 Subtract Long Immediate Value from a Register or a Data Memory Location
|
||||
// ---
|
||||
{ "maxd", CF_USE1|CF_CHG1|CF_USE2 }, // Maximum between Data Memory Location and Accumulator
|
||||
{ "max", CF_USE1|CF_CHG1|CF_USE2 }, // Maximum between Two Accumulators
|
||||
{ "min", CF_USE1|CF_CHG1|CF_USE2 }, // Minimum between Two Accumulators
|
||||
{ "lim", CF_USE1|CF_CHG1|CF_USE2 }, // Limit Accumulator (lim aX[, aX])
|
||||
// MUL subcodes
|
||||
{ "mpy", CF_USE1|CF_USE2 }, // 000 Multiply
|
||||
{ "mpysu", CF_USE1|CF_USE2 }, // 001 Multiply Signed by Unsigned
|
||||
{ "mac", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 010 Multiply and Accumulate Previous Product
|
||||
{ "macus", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 011 Multiply Unsigned by Signed and Accumulate Previous Product
|
||||
{ "maa", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 100 Multiply and Accumulate Aligned Previous Product
|
||||
{ "macuu", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 101 Multiply Unsigned by Unsigned and Accumulate Previous Product
|
||||
{ "macsu", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 110 Multiply Signed by Unsigned and Accumulate Previous Product
|
||||
{ "maasu", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 111 Multiply Signed by Unsigned and Accumulate Aligned Previous Product
|
||||
//---
|
||||
{ "mpyi", CF_USE1|CF_USE2 }, // Multiply Signed Short Immediate
|
||||
{ "msu", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Multiply and Subtract Previous Product
|
||||
{ "tstb", CF_USE1|CF_USE2 }, // Test Specific Bit
|
||||
{ "shfc", CF_USE1|CF_USE2|CF_CHG2 }, // Shift Accumulators according to Shift Value Register
|
||||
{ "shfi", CF_USE1|CF_USE2|CF_CHG2|CF_USE3 }, // Shift Accumulators by an Immediate Shift Value
|
||||
{ "exp", CF_USE1|CF_USE2|CF_CHG2 }, // Evaluate the Exponent Value
|
||||
//---
|
||||
{ "mov", CF_USE1|CF_CHG2 }, // Move Data
|
||||
{ "movp", CF_USE1|CF_CHG2 }, // Move from Program Memory into Data Memory
|
||||
{ "movs", CF_USE1|CF_CHG2 }, // Move and Shift According to Shift Value Register
|
||||
{ "movsi", CF_USE1|CF_USE2|CF_CHG2|CF_USE3 }, // Move and Shift According to an Immediate Shift Value
|
||||
{ "movr", CF_USE1|CF_CHG2 }, // Move and Round
|
||||
{ "movd", CF_USE1|CF_CHG2 }, // Move from Data Memory into Program Memory
|
||||
//---
|
||||
{ "push", CF_USE1 }, // Push Register or Long Immediate Value onto Stack
|
||||
{ "pop", CF_USE1|CF_CHG1 }, // Pop from Stack into Register
|
||||
//---
|
||||
{ "swap", CF_USE1 }, // Swap aX- and bX-accumulators
|
||||
{ "banke", CF_USE1 }, // Bank Exchange
|
||||
{ "rep", CF_USE1 }, // Repeat Next Instruction
|
||||
{ "bkrep", CF_USE1|CF_USE2 }, // Block-Repeat
|
||||
{ "break", 0 }, // Break from Block-repeat
|
||||
//---
|
||||
{ "br", CF_USE1|CF_JUMP }, // Conditional Branch
|
||||
{ "brr", CF_USE1|CF_JUMP }, // Relative Conditional Branch
|
||||
{ "br", CF_USE1|CF_STOP|CF_JUMP }, // UnConditional Branch
|
||||
{ "brr", CF_USE1|CF_STOP|CF_JUMP }, // Relative UnConditional Branch
|
||||
{ "call", CF_USE1|CF_CALL }, // Conditional Call Subroutine
|
||||
{ "callr", CF_USE1|CF_CALL }, // Relative Conditional Call Subroutine
|
||||
{ "calla", CF_USE1 }, // Call Subroutine at Location Specified by Accumulator
|
||||
//---
|
||||
{ "ret", 0 }, // Return Conditionally
|
||||
{ "ret", CF_STOP }, // Return UnConditionally
|
||||
{ "retd", 0 }, // Delayed Return
|
||||
{ "reti", 0 }, // Return from Interrupt Conditionally
|
||||
{ "reti", CF_STOP }, // Return from Interrupt UnConditionally
|
||||
{ "retid", 0 }, // Delayed Return from Interrupt
|
||||
{ "rets", CF_USE1|CF_STOP }, // Return with Short Immediate Parameter
|
||||
//---
|
||||
{ "cntx", CF_USE1 }, // Context Switching Store or Restore
|
||||
{ "nop", 0 }, // No operation
|
||||
{ "modr", CF_USE1|CF_USE2 }, // Modify rN
|
||||
{ "dint", 0 }, // Disable Interrupt
|
||||
{ "eint", 0 }, // Enable Interrupt
|
||||
//---
|
||||
{ "trap", CF_STOP }, // Software Interrupt
|
||||
//---
|
||||
{ "lpg", CF_USE1 }, // Load the Page Bits
|
||||
{ "load", CF_USE1|CF_CHG2 }, // Load Specific Fields into Registers
|
||||
{ "mov", CF_USE1|CF_CHG2|CF_USE3 }, // Move Data, eu
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == OAK_Dsp_last);
|
||||
128
idasdk76/module/oakdsp/ins.hpp
Normal file
128
idasdk76/module/oakdsp/ins.hpp
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum
|
||||
{
|
||||
OAK_Dsp_null = 0, // Unknown Operation
|
||||
OAK_Dsp_proc, // cmd need further process
|
||||
// ALU-ALM subcodes
|
||||
OAK_Dsp_or, // 000 Logical Or
|
||||
OAK_Dsp_and, // 001 And
|
||||
OAK_Dsp_xor, // 010 Exclusive Or
|
||||
OAK_Dsp_add, // 011 Add
|
||||
OAK_Dsp_alm_tst0, // 100 Test Bit-field for Zeros
|
||||
OAK_Dsp_alm_tst1, // 101 Test Bit-field for Ones
|
||||
OAK_Dsp_cmp, // 110 Compare
|
||||
OAK_Dsp_sub, // 111 Subtract
|
||||
// ALM subcodes
|
||||
OAK_Dsp_alm_msu, // 1000 Multiply and Subtract Previous Product
|
||||
OAK_Dsp_addh, // 1001 Add to High Accumulator
|
||||
OAK_Dsp_addl, // 1010 Add to Low Accumulator
|
||||
OAK_Dsp_subh, // 1011 Subtract from High Accumulator
|
||||
OAK_Dsp_subl, // 1100 Subtract from Low Accumulator
|
||||
OAK_Dsp_sqr, // 1101 Square
|
||||
OAK_Dsp_sqra, // 1110 Square and Accumulate Previous Product
|
||||
OAK_Dsp_cmpu, // 1111 Compare Unsigned
|
||||
// MODA-MODB subcodes conditional
|
||||
OAK_Dsp_shr, // 000 Shift Accumulator Right
|
||||
OAK_Dsp_shr4, // 001 Shift Accumulator Right by 4 Bits
|
||||
OAK_Dsp_shl, // 010 Shift Accumulator Left
|
||||
OAK_Dsp_shl4, // 011 Shift Accumulator Left by 4 Bits
|
||||
OAK_Dsp_ror, // 100 Rotate Accumulator Right through Carry
|
||||
OAK_Dsp_rol, // 101 Rotate Accumulator Left through Carry
|
||||
OAK_Dsp_clr, // 110 Clear Accumulator
|
||||
OAK_Dsp_mod_reserved, // 111 Mod Reserved
|
||||
// MODA subcodes conditional
|
||||
OAK_Dsp_not, // 1000 Logical Not
|
||||
OAK_Dsp_neg, // 1001 2's Complement of aX-accumulator
|
||||
OAK_Dsp_rnd, // 1010 Round Upper 20 Bits of aX-accumulator
|
||||
OAK_Dsp_pacr, // 1011 Product Move and Round to aX-accumulator
|
||||
OAK_Dsp_clrr, // 1100 Clear and Round aX-accumulator
|
||||
OAK_Dsp_inc, // 1101 Increment Accumulator by One
|
||||
OAK_Dsp_dec, // 1110 Decrement aX-accumulator by One
|
||||
OAK_Dsp_copy, // 1111 Copy aX-accumulator
|
||||
// ---
|
||||
OAK_Dsp_norm, // Normalize
|
||||
OAK_Dsp_divs, // Division Step
|
||||
// ALB subcodes
|
||||
OAK_Dsp_set, // 000 Set Bit-field
|
||||
OAK_Dsp_rst, // 001 Reset Bit-field
|
||||
OAK_Dsp_chng, // 010 Change Bit-field
|
||||
OAK_Dsp_addv, // 011 Add Long Immediate Value or Data Memory Location
|
||||
OAK_Dsp_alb_tst0, // 100 Test Bit-field for Zeros
|
||||
OAK_Dsp_alb_tst1, // 101 Test Bit-field for Ones
|
||||
OAK_Dsp_cmpv, // 110 Compare Long Immediate Value to Register or Data Memory Location
|
||||
OAK_Dsp_subv, // 111 Subtract Long Immediate Value from a Register or a Data Memory Location
|
||||
// ---
|
||||
OAK_Dsp_maxd, // Maximum between Data Memory Location and Accumulator
|
||||
OAK_Dsp_max, // Maximum between Two Accumulators
|
||||
OAK_Dsp_min, // Minimum between Two Accumulators
|
||||
OAK_Dsp_lim, // Limit Accumulator (lim aX[, aX])
|
||||
// MUL subcodes
|
||||
OAK_Dsp_mpy, // 000 Multiply
|
||||
OAK_Dsp_mpysu, // 001 Multiply Signed by Unsigned
|
||||
OAK_Dsp_mac, // 010 Multiply and Accumulate Previous Product
|
||||
OAK_Dsp_macus, // 011 Multiply Unsigned by Signed and Accumulate Previous Product
|
||||
OAK_Dsp_maa, // 100 Multiply and Accumulate Aligned Previous Product
|
||||
OAK_Dsp_macuu, // 101 Multiply Unsigned by Unsigned and Accumulate Previous Product
|
||||
OAK_Dsp_macsu, // 110 Multiply Signed by Unsigned and Accumulate Previous Product
|
||||
OAK_Dsp_maasu, // 111 Multiply Signed by Unsigned and Accumulate Aligned Previous Product
|
||||
//---
|
||||
OAK_Dsp_mpyi, // Multiply Signed Short Immediate
|
||||
OAK_Dsp_msu, // Multiply and Subtract Previous Product
|
||||
OAK_Dsp_tstb, // Test Specific Bit
|
||||
OAK_Dsp_shfc, // Shift Accumulators according to Shift Value Register
|
||||
OAK_Dsp_shfi, // Shift Accumulators by an Immediate Shift Value
|
||||
OAK_Dsp_exp, // Evaluate the Exponent Value
|
||||
//---
|
||||
OAK_Dsp_mov, // Move Data
|
||||
OAK_Dsp_movp, // Move from Program Memory into Data Memory
|
||||
OAK_Dsp_movs, // Move and Shift According to Shift Value Register
|
||||
OAK_Dsp_movsi, // Move and Shift According to an Immediate Shift Value
|
||||
OAK_Dsp_movr, // Move and Round
|
||||
OAK_Dsp_movd, // Move from Data Memory into Program Memory
|
||||
//---
|
||||
OAK_Dsp_push, // Push Register or Long Immediate Value onto Stack
|
||||
OAK_Dsp_pop, // Pop from Stack into Register
|
||||
//---
|
||||
OAK_Dsp_swap, // Swap aX- and bX-accumulators
|
||||
OAK_Dsp_banke, // Bank Exchange
|
||||
OAK_Dsp_rep, // Repeat Next Instruction
|
||||
OAK_Dsp_bkrep, // Block-Repeat
|
||||
OAK_Dsp_break, // Break from Block-repeat
|
||||
//---
|
||||
OAK_Dsp_br, // Conditional Branch
|
||||
OAK_Dsp_brr, // Relative Conditional Branch
|
||||
OAK_Dsp_br_u, // UnConditional Branch
|
||||
OAK_Dsp_brr_u, // Relative UnConditional Branch
|
||||
OAK_Dsp_call, // Conditional Call Subroutine
|
||||
OAK_Dsp_callr, // Relative Conditional Call Subroutine
|
||||
OAK_Dsp_calla, // Call Subroutine at Location Specified by Accumulator
|
||||
//---
|
||||
OAK_Dsp_ret, // Return Conditionally
|
||||
OAK_Dsp_ret_u, // Return UnConditionally
|
||||
OAK_Dsp_retd, // Delayed Return
|
||||
OAK_Dsp_reti, // Return from Interrupt Conditionally
|
||||
OAK_Dsp_reti_u, // Return from Interrupt UnConditionally
|
||||
OAK_Dsp_retid, // Delayed Return from Interrupt
|
||||
OAK_Dsp_rets, // Return with Short Immediate Parameter
|
||||
//---
|
||||
OAK_Dsp_cntx, // Context Switching Store or Restore
|
||||
OAK_Dsp_nop, // No operation
|
||||
OAK_Dsp_modr, // Modify rN
|
||||
OAK_Dsp_dint, // Disable Interrupt
|
||||
OAK_Dsp_eint, // Enable Interrupt
|
||||
//---
|
||||
OAK_Dsp_trap, // Software Interrupt
|
||||
//---
|
||||
OAK_Dsp_lpg, // Load the Page Bits
|
||||
OAK_Dsp_load, // Load Specific Fields into Registers
|
||||
OAK_Dsp_mov_eu, // Move Data, eu
|
||||
OAK_Dsp_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
58
idasdk76/module/oakdsp/makefile
Normal file
58
idasdk76/module/oakdsp/makefile
Normal file
@@ -0,0 +1,58 @@
|
||||
PROC=oakdsp
|
||||
CONFIGS=oakdsp.cfg
|
||||
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
ana.cpp ins.hpp oakdsp.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp emu.cpp ins.hpp oakdsp.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
ins.cpp ins.hpp oakdsp.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)struct.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp ins.hpp oakdsp.hpp \
|
||||
out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp ins.hpp oakdsp.hpp reg.cpp
|
||||
23
idasdk76/module/oakdsp/oakdsp.cfg
Normal file
23
idasdk76/module/oakdsp/oakdsp.cfg
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
; This file describes the standard addresses for OAK DSP based systems
|
||||
|
||||
.default at75c220
|
||||
|
||||
entry RESET 0x0000 Hardware RESET
|
||||
entry TRAP 0x0002 Software interrupt
|
||||
entry NMI 0x0004 NMI Vector
|
||||
entry INT0 0x0006 INT0 vector
|
||||
entry INT1 0x000E INT1 vector
|
||||
entry INT2 0x0016 INT2 vector
|
||||
entry INT3 0x001E INT3 vector
|
||||
|
||||
CODCNT 0xEC00
|
||||
CODFRM 0xEC02
|
||||
CODSCK 0xEC04
|
||||
CODSTS 0xEC06
|
||||
CODTX 0xEC08
|
||||
CODRX 0xEC0A
|
||||
|
||||
.at75c220
|
||||
|
||||
XMEMSIZE = 0x10000
|
||||
231
idasdk76/module/oakdsp/oakdsp.hpp
Normal file
231
idasdk76/module/oakdsp/oakdsp.hpp
Normal file
@@ -0,0 +1,231 @@
|
||||
|
||||
#ifndef _OAKDSP_HPP
|
||||
#define _OAKDSP_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
#define aux_cc 0x000F // condition code
|
||||
#define aux_comma_cc 0x0010 // comma before cond
|
||||
#define aux_iret_context 0x0020
|
||||
|
||||
#define cmd_cycles insnpref
|
||||
|
||||
#define phtype specflag1 // o_phrase: phrase type
|
||||
// 0 (Rn)
|
||||
// 1 (Rn)+1
|
||||
// 2 (Rn)-1
|
||||
// 3 (Rn)+s
|
||||
// 4 (any_reg)
|
||||
|
||||
#define amode specflag2 // addressing options & other
|
||||
#define amode_short 0x01
|
||||
#define amode_long 0x02
|
||||
#define amode_x 0x04 // X:
|
||||
#define amode_p 0x08 // P:
|
||||
#define amode_neg 0x10 // -
|
||||
#define amode_signed 0x10 // - if x<0
|
||||
|
||||
|
||||
#define o_textphrase o_idpspec0 // text type
|
||||
#define o_local o_idpspec1
|
||||
|
||||
#define textphtype specflag1 // o_texttype: phrase type
|
||||
|
||||
#define text_swap 0x01
|
||||
// (a0, b0)
|
||||
// (a0, b1)
|
||||
// (a1, b0)
|
||||
// (a1, b1)
|
||||
// (a0, b0), (a1, b1)
|
||||
// (a0, b1), (a1, b0)
|
||||
// (a0, b0, a1)
|
||||
// (a0, b1, a1)
|
||||
// (a1, b0, a0)
|
||||
// (a1, b1, a0)
|
||||
// (b0, a0, b1)
|
||||
// (b0, a1, b1)
|
||||
// (b1, a0, b0)
|
||||
// (b1, a1, b0)
|
||||
|
||||
#define text_banke 0x02
|
||||
//[r0], [r1], [r4], [cfgi]
|
||||
|
||||
#define text_cntx 0x03
|
||||
// s
|
||||
// r
|
||||
|
||||
#define text_dmod 0x04
|
||||
// dmod
|
||||
|
||||
#define text_eu 0x05
|
||||
// eu
|
||||
|
||||
#define mix_mode 0x80000000 // Func rrrrr should use both input value and param
|
||||
|
||||
//------------------------------------------------------------------
|
||||
#define UAS_GNU 0x0001 // GNU assembler
|
||||
//------------------------------------------------------------------
|
||||
enum RegNo
|
||||
{
|
||||
R0, R1, R2, R3, R4, R5, // DAAU Registers
|
||||
RB, // Base Register
|
||||
Y, // Input Register
|
||||
ST0, ST1, ST2, // Status Registers
|
||||
P, // Output Register
|
||||
PC, // Program Counter
|
||||
SP, // Software Stack Pointer
|
||||
CFGI, CFGJ, // DAAU Configuration Registers
|
||||
B0H, B1H, B0L, B1L, // Accumulator B
|
||||
EXT0, EXT1, EXT2, EXT3, // External registers
|
||||
A0, A1, A0L, A1L, A0H, A1H, // Accumulator A
|
||||
LC, // Loop Counter
|
||||
SV, // Shift Value Register
|
||||
X, // Input Register
|
||||
DVM, // Data Value Match Register
|
||||
MIXP, // Minimal/Maximal Pointer Register
|
||||
ICR, // Internal Configuration Register
|
||||
PS, // Product Shifter Control
|
||||
REPC, // Internal Repeat Counter
|
||||
B0, B1, // Accumulator B
|
||||
MODI,MODJ, // Modulo Modifier
|
||||
STEPI, STEPJ, // Linear (Step) Modifier
|
||||
PAGE, // Short Direct Addressing Mode Page
|
||||
vCS, vDS, // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// condition codes
|
||||
enum cc_t
|
||||
{
|
||||
cc_true, // Always
|
||||
cc_eq, // Equal to zero Z = 1
|
||||
cc_neq, // Not equal to zero Z = 0
|
||||
cc_gt, // Greater than zero M = 0 and Z = 0
|
||||
cc_ge, // Greater than or equal to zero M = 0
|
||||
cc_lt, // Less than zero M =1
|
||||
cc_le, // Less than or equal to zero M = 1 or Z = 1
|
||||
cc_nn, // Normalized flag is cleared N = 0
|
||||
cc_v, // Overflow flag is set V = 1
|
||||
cc_c, // Carry flag is set C = 1
|
||||
cc_e, // Extension flag is set E = 1
|
||||
cc_l, // Limit flag is set L = 1
|
||||
cc_nr, // flag is cleared R = 0
|
||||
cc_niu0, // Input user pin 0 is cleared
|
||||
cc_iu0, // Input user pin 0 is set
|
||||
cc_iu1, // Input user pin 1 is set
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void interr(const insn_t &insn, const char *module);
|
||||
|
||||
int idaapi is_align_insn(ea_t ea);
|
||||
bool idaapi create_func_frame(func_t *pfn);
|
||||
int idaapi is_sp_based(const insn_t &insn, const op_t &x);
|
||||
int idaapi OAK_get_frame_retsize(const func_t *pfn);
|
||||
|
||||
int is_jump_func(const func_t *pfn, ea_t *jump_target);
|
||||
int may_be_func(const insn_t &insn); // can a function start here?
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct opcode_t;
|
||||
|
||||
struct oakdsp_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct oakdsp_t ±
|
||||
oakdsp_iohandler_t(oakdsp_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line) override;
|
||||
};
|
||||
|
||||
struct oakdsp_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
oakdsp_iohandler_t ioh = oakdsp_iohandler_t(*this, helper);
|
||||
ea_t xmem = BADADDR;
|
||||
int xmemsize = 0x1000;
|
||||
int procnum = -1;
|
||||
|
||||
op_t *op = nullptr; // current operand
|
||||
|
||||
bool flow = false;
|
||||
bool delayed = false;
|
||||
int cycles = 0;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
const ioport_t *find_port(ea_t address);
|
||||
void create_xmem(void);
|
||||
void select_device(const char *dname, int lrespect_info);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/);
|
||||
ea_t add_data_segm(size_t size, int offset, const char *name) const;
|
||||
|
||||
inline void opreg(int reg);
|
||||
void make_o_mem(const insn_t &insn);
|
||||
bool rrrrr(insn_t &, int value, int param);
|
||||
bool sdirect(insn_t &insn, int value, int);
|
||||
bool ldirect(insn_t &insn, int value,int);
|
||||
bool A(insn_t &insn, int value,int);
|
||||
bool B(insn_t &insn, int value,int);
|
||||
bool mmnnn(insn_t &, int value,int);
|
||||
bool nnn(insn_t &insn, int value, int);
|
||||
bool ALU_ALM(insn_t &insn, int value, int param);
|
||||
bool ALB(insn_t &insn, int value, int);
|
||||
bool MUL(insn_t &insn, int value, int param);
|
||||
bool MODA_B(insn_t &insn, int value, int param);
|
||||
bool s_Imm(insn_t &insn, int value, int);
|
||||
bool s_ImmS(insn_t &, int value, int param);
|
||||
bool l_Imm(insn_t &insn, int value, int);
|
||||
bool rb_rel_short(insn_t &, int value, int);
|
||||
bool rb_rel_long(insn_t &insn, int value, int);
|
||||
bool Cond(insn_t &insn, int value, int param);
|
||||
bool xe_xt(insn_t &insn, int value, int param);
|
||||
bool lim_xx(insn_t &, int value, int);
|
||||
bool rJ_rI(insn_t &, int value,int param);
|
||||
bool rI(insn_t &, int value,int);
|
||||
bool AB(insn_t &, int value,int);
|
||||
bool ABLH(insn_t &, int value,int);
|
||||
bool indir_reg(insn_t &, int value,int param);
|
||||
bool laddr_pgm(insn_t &insn, int value,int);
|
||||
bool addr_rel_pgm(insn_t &insn, int value, int);
|
||||
bool ext_XX(insn_t &insn, int value, int);
|
||||
bool context(insn_t &insn, int value,int);
|
||||
bool swap(insn_t &, int value,int);
|
||||
bool banke(insn_t &, int value,int);
|
||||
bool cntx(insn_t &, int value,int);
|
||||
bool dmod(insn_t &, int value,int);
|
||||
bool eu(insn_t &, int,int);
|
||||
bool use_table(insn_t &insn, const opcode_t &ptr, uint code, int start, int end);
|
||||
void reset_ops(insn_t &insn);
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void init_emu(void);
|
||||
ea_t calc_mem(const insn_t &insn, const op_t &x) const;
|
||||
int is_sane_insn(const insn_t &insn, int nocrefs) const;
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload);
|
||||
void add_near_ref(const insn_t &insn, const op_t &x, ea_t ea);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void oakdsp_header(outctx_t &ctx);
|
||||
void oakdsp_assumes(outctx_t &ctx);
|
||||
void print_segment_register(outctx_t &ctx, int reg, sel_t value);
|
||||
void oakdsp_segstart(outctx_t &ctx, segment_t *Srange) const;
|
||||
void oakdsp_segend(outctx_t &ctx, segment_t *Srange) const;
|
||||
void oakdsp_footer(outctx_t &ctx) const;
|
||||
void gen_stkvar_def(outctx_t &ctx, const member_t *mptr, sval_t v) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ oakdsp"
|
||||
#define PROCMOD_NAME oakdsp
|
||||
#endif // _OAKDSP_HPP
|
||||
511
idasdk76/module/oakdsp/out.cpp
Normal file
511
idasdk76/module/oakdsp/out.cpp
Normal file
@@ -0,0 +1,511 @@
|
||||
|
||||
#include "oakdsp.hpp"
|
||||
#include <frame.hpp>
|
||||
#include <segregs.hpp>
|
||||
#include <struct.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const cc_text[] =
|
||||
{
|
||||
"", // Always
|
||||
"eq", // Equal to zero Z = 1
|
||||
"neq", // Not equal to zero Z = 0
|
||||
"gt", // Greater than zero M = 0 and Z = 0
|
||||
"ge", // Greater than or equal to zero M = 0
|
||||
"lt", // Less than zero M =1
|
||||
"le", // Less than or equal to zero M = 1 or Z = 1
|
||||
"nn", // Normalized flag is cleared N = 0
|
||||
"v", // Overflow flag is set V = 1
|
||||
"c", // Carry flag is set C = 1
|
||||
"e", // Extension flag is set E = 1
|
||||
"l", // Limit flag is set L = 1
|
||||
"nr", // flag is cleared R = 0
|
||||
"niu0", // Input user pin 0 is cleared
|
||||
"iu0", // Input user pin 0 is set
|
||||
"iu1", // Input user pin 1 is set
|
||||
|
||||
};
|
||||
|
||||
|
||||
static const char *const formats[] =
|
||||
{
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")+1", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")-1", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")+s", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("reg", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
};
|
||||
|
||||
// 0 (Rn)
|
||||
// 1 (Rn)+1
|
||||
// 2 (Rn)-1
|
||||
// 3 (Rn)+s
|
||||
// 4 (any_reg)
|
||||
|
||||
static const char *const formats2[] =
|
||||
{
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("rb+#", SCOLOR_REG),
|
||||
COLSTR("#", SCOLOR_REG),
|
||||
};
|
||||
// 0 (rb + #)
|
||||
// 1 #
|
||||
|
||||
static const char *const swap_formats[] =
|
||||
{
|
||||
COLSTR("(a0, b0)", SCOLOR_REG),
|
||||
COLSTR("(a0, b1)", SCOLOR_REG),
|
||||
COLSTR("(a1, b0)", SCOLOR_REG),
|
||||
COLSTR("(a1, b1)", SCOLOR_REG),
|
||||
COLSTR("(a0, b0), (a1, b1)", SCOLOR_REG),
|
||||
COLSTR("(a0, b1), (a1, b0)", SCOLOR_REG),
|
||||
COLSTR("(a0, b0, a1)", SCOLOR_REG),
|
||||
COLSTR("(a0, b1, a1)", SCOLOR_REG),
|
||||
COLSTR("(a1, b0, a0)", SCOLOR_REG),
|
||||
COLSTR("(a1, b1, a0)", SCOLOR_REG),
|
||||
COLSTR("(b0, a0, b1)", SCOLOR_REG),
|
||||
COLSTR("(b0, a1, b1)", SCOLOR_REG),
|
||||
COLSTR("(b1, a0, b0)", SCOLOR_REG),
|
||||
COLSTR("(b1, a1, b0)", SCOLOR_REG),
|
||||
};
|
||||
|
||||
// (a0, b0)
|
||||
// (a0, b1)
|
||||
// (a1, b0)
|
||||
// (a1, b1)
|
||||
// (a0, b0), (a1, b1)
|
||||
// (a0, b1), (a1, b0)
|
||||
// (a0, b0, a1)
|
||||
// (a0, b1, a1)
|
||||
// (a1, b0, a0)
|
||||
// (a1, b1, a0)
|
||||
// (b0, a0, b1)
|
||||
// (b0, a1, b1)
|
||||
// (b1, a0, b0)
|
||||
// (b1, a1, b0)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_oakdsp_t : public outctx_t
|
||||
{
|
||||
out_oakdsp_t(void) = delete; // not used
|
||||
oakdsp_t &pm() { return *static_cast<oakdsp_t *>(procmod); }
|
||||
public:
|
||||
void outreg(int r) { out_register(ph.reg_names[r]); }
|
||||
bool out_port_address(ea_t addr);
|
||||
void out_bad_address(ea_t addr);
|
||||
void out_address(ea_t ea, const op_t &x);
|
||||
void out_ip_rel(int displ)
|
||||
{
|
||||
out_printf(COLSTR("%s+", SCOLOR_SYMBOL) COLSTR("%d", SCOLOR_NUMBER),
|
||||
ash.a_curip, displ);
|
||||
}
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_oakdsp_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_oakdsp_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_oakdsp_t::out_port_address(ea_t addr)
|
||||
{
|
||||
const ioport_t *port = pm().find_port(addr);
|
||||
if ( port != NULL && !port->name.empty() )
|
||||
{
|
||||
out_line(port->name.c_str(), COLOR_IMPNAME);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_oakdsp_t::out_bad_address(ea_t addr)
|
||||
{
|
||||
if ( !out_port_address(addr) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(addr, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_oakdsp_t::out_address(ea_t ea, const op_t &x)
|
||||
{
|
||||
if ( !out_name_expr(x, ea,/* ea */ BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFW_16);
|
||||
out_printf(" (ea = %a)", ea);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_oakdsp_t::out_operand(const op_t & x)
|
||||
{
|
||||
ea_t ea;
|
||||
char buf[MAXSTR];
|
||||
|
||||
if ( x.type == o_imm )
|
||||
out_symbol('#');
|
||||
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_imm:
|
||||
if ( x.amode & amode_signed )
|
||||
out_value(x, OOF_SIGNED|OOFW_IMM);
|
||||
else
|
||||
out_value(x, OOFS_IFSIGN|OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_reg:
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
// no break;
|
||||
ea = pm().calc_mem(insn, x);
|
||||
if ( ea != BADADDR )
|
||||
out_address(ea, x);
|
||||
else
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFW_16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
ea_t lea = pm().calc_mem(insn, x);
|
||||
// xmem ioports
|
||||
if ( x.amode & (amode_x) && out_port_address(x.addr) )
|
||||
{
|
||||
const ioport_t *port = pm().find_port(x.addr);
|
||||
if ( port != NULL && !has_user_name(get_flags(lea)) )
|
||||
set_name(lea, port->name.c_str(), SN_NODUMMY);
|
||||
break;
|
||||
}
|
||||
if ( lea == insn.ea+insn.size )
|
||||
out_ip_rel(insn.size);
|
||||
else if ( !out_name_expr(x, lea, x.addr) )
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
{
|
||||
if ( x.phtype < 4 )
|
||||
{
|
||||
nowarn_qsnprintf(buf, sizeof(buf), formats[uchar(x.phtype)], x.phrase);
|
||||
out_colored_register_line(buf);
|
||||
}
|
||||
if ( x.phtype == 4 )
|
||||
{
|
||||
out_symbol('(');
|
||||
outreg(x.reg);
|
||||
out_symbol(')');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_local:
|
||||
{
|
||||
out_colored_register_line(formats2[uchar(x.phtype)]);
|
||||
out_value(x, OOF_SIGNED|OOF_ADDR|OOFW_16);
|
||||
if ( x.phtype == 0 )
|
||||
out_symbol(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case o_textphrase:
|
||||
{
|
||||
switch ( x.textphtype )
|
||||
{
|
||||
case text_swap:
|
||||
out_line(swap_formats[x.phrase], COLOR_REG);
|
||||
break;
|
||||
|
||||
case text_banke:
|
||||
|
||||
int comma;
|
||||
char r0[10], r1[10], r4[10], cfgi[10];
|
||||
comma = 0;
|
||||
|
||||
|
||||
r0[0]=r1[0]=r4[0]=cfgi[0]='\0';
|
||||
|
||||
if ( x.phrase & 0x01 ) // cfgi
|
||||
{
|
||||
qsnprintf(cfgi, sizeof(cfgi), "cfgi");
|
||||
comma = 1;
|
||||
}
|
||||
|
||||
if ( x.phrase & 0x02 ) // r4
|
||||
{
|
||||
qsnprintf(r4, sizeof(r4), "r4%s", (comma?", ":""));
|
||||
comma = 1;
|
||||
}
|
||||
|
||||
if ( x.phrase & 0x04 ) // r1
|
||||
{
|
||||
qsnprintf(r1, sizeof(r1), "r1%s", (comma?", ":""));
|
||||
comma = 1;
|
||||
}
|
||||
|
||||
if ( x.phrase & 0x08 ) // r0
|
||||
qsnprintf(r0, sizeof(r0), "r0%s", (comma?", ":""));
|
||||
|
||||
qsnprintf(buf, sizeof(buf), "%s%s%s%s", r0, r1, r4, cfgi);
|
||||
out_line(buf, COLOR_REG);
|
||||
|
||||
break;
|
||||
case text_cntx:
|
||||
out_symbol(x.phrase ? 'r': 's');
|
||||
break;
|
||||
case text_dmod:
|
||||
if ( x.phrase )
|
||||
qsnprintf(buf, sizeof(buf), " no modulo");
|
||||
else
|
||||
qsnprintf(buf, sizeof(buf), " modulo");
|
||||
|
||||
out_line(buf, COLOR_REG);
|
||||
|
||||
break;
|
||||
case text_eu:
|
||||
qsnprintf(buf, sizeof(buf), " eu");
|
||||
out_line(buf, COLOR_REG);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
interr(insn, "out");
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_oakdsp_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
bool comma = out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
if ( comma )
|
||||
out_symbol(',');
|
||||
out_one_operand(1);
|
||||
}
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_one_operand(2);
|
||||
}
|
||||
out_immchar_cmts();
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case OAK_Dsp_callr:
|
||||
case OAK_Dsp_ret:
|
||||
case OAK_Dsp_br:
|
||||
case OAK_Dsp_call:
|
||||
case OAK_Dsp_reti:
|
||||
case OAK_Dsp_brr:
|
||||
case OAK_Dsp_shfc:
|
||||
case OAK_Dsp_shr:
|
||||
case OAK_Dsp_shr4:
|
||||
case OAK_Dsp_shl:
|
||||
case OAK_Dsp_shl4:
|
||||
case OAK_Dsp_ror:
|
||||
case OAK_Dsp_rol:
|
||||
case OAK_Dsp_clr:
|
||||
case OAK_Dsp_not:
|
||||
case OAK_Dsp_neg:
|
||||
case OAK_Dsp_rnd:
|
||||
case OAK_Dsp_pacr:
|
||||
case OAK_Dsp_clrr:
|
||||
case OAK_Dsp_inc:
|
||||
case OAK_Dsp_dec:
|
||||
case OAK_Dsp_copy:
|
||||
case OAK_Dsp_maxd:
|
||||
case OAK_Dsp_max:
|
||||
case OAK_Dsp_min:
|
||||
char buf[MAXSTR];
|
||||
qsnprintf(buf,
|
||||
sizeof(buf),
|
||||
"%s%s%s",
|
||||
(insn.auxpref & aux_comma_cc) ? ", ": "",
|
||||
cc_text[insn.auxpref & aux_cc],
|
||||
(insn.auxpref & aux_iret_context) ? ", context": "");
|
||||
out_line(buf, COLOR_REG);
|
||||
break;
|
||||
}
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Srange) could be made const
|
||||
void oakdsp_t::oakdsp_segstart(outctx_t &ctx, segment_t *Srange) const
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
if ( is_spec_segm(Srange->type) )
|
||||
return;
|
||||
|
||||
qstring sname;
|
||||
qstring sclas;
|
||||
get_segm_name(&sname, Srange);
|
||||
get_segm_class(&sclas, Srange);
|
||||
|
||||
if ( ash.uflag & UAS_GNU )
|
||||
{
|
||||
const char *const predefined[] =
|
||||
{
|
||||
".text", // Text section
|
||||
".data", // Data sections
|
||||
".rdata",
|
||||
".comm",
|
||||
};
|
||||
|
||||
if ( !print_predefined_segname(ctx, &sname, predefined, qnumber(predefined)) )
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR(".section %s", SCOLOR_ASMDIR) " " COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sname.c_str(),
|
||||
ash.cmnt,
|
||||
sclas.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
validate_name(&sname, VNT_IDENT);
|
||||
if ( sname == "XMEM" )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), ea-get_segm_base(Srange));
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s %c:%s", SCOLOR_ASMDIR),
|
||||
ash.origin,
|
||||
qtolower(sname[0]),
|
||||
buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("section %s", SCOLOR_ASMDIR) " " COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sname.c_str(),
|
||||
ash.cmnt,
|
||||
sclas.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::print_segment_register(outctx_t &ctx, int reg, sel_t value)
|
||||
{
|
||||
if ( reg == ph.reg_data_sreg )
|
||||
return;
|
||||
if ( value != BADADDR )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), value);
|
||||
ctx.gen_cmt_line("assume %s = %s", ph.reg_names[reg], buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("drop %s", ph.reg_names[reg]);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// function to produce assume directives
|
||||
void oakdsp_t::oakdsp_assumes(outctx_t &ctx)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
segment_t *seg = getseg(ea);
|
||||
if ( seg == NULL || (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 )
|
||||
return;
|
||||
bool seg_started = (ea == seg->start_ea);
|
||||
|
||||
for ( int i = ph.reg_first_sreg; i <= ph.reg_last_sreg; ++i )
|
||||
{
|
||||
if ( i == ph.reg_code_sreg )
|
||||
continue;
|
||||
sreg_range_t sra;
|
||||
if ( !get_sreg_range(&sra, ea, i) )
|
||||
continue;
|
||||
sel_t now = get_sreg(ea, i);
|
||||
if ( seg_started || sra.start_ea == ea )
|
||||
{
|
||||
sreg_range_t prev_sra;
|
||||
bool prev_exists = get_sreg_range(&prev_sra, ea - 1, i);
|
||||
if ( seg_started || (prev_exists && get_sreg(prev_sra.start_ea, i) != now) )
|
||||
print_segment_register(ctx, i, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::oakdsp_segend(outctx_t &ctx, segment_t *Srange) const
|
||||
{
|
||||
if ( !is_spec_segm(Srange->type) && (ash.uflag & UAS_GNU) == 0 )
|
||||
{
|
||||
qstring sname;
|
||||
get_segm_name(&sname, Srange);
|
||||
if ( sname != "XMEM" )
|
||||
ctx.gen_printf(DEFAULT_INDENT, "endsec");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::oakdsp_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL, NULL, ioh.device.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::oakdsp_footer(outctx_t &ctx) const
|
||||
{
|
||||
qstring nbuf = get_colored_name(inf_get_start_ea());
|
||||
const char *name = nbuf.c_str();
|
||||
const char *end = ash.end;
|
||||
if ( end == NULL )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s end %s",SCOLOR_AUTOCMT), ash.cmnt, name);
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
|
||||
ash.end, ash.cmnt, name);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::gen_stkvar_def(outctx_t &ctx, const member_t *mptr, sval_t v) const
|
||||
{
|
||||
char sign = ' ';
|
||||
if ( v < 0 )
|
||||
{
|
||||
sign = '-';
|
||||
v = -v;
|
||||
}
|
||||
|
||||
qstring name = get_member_name(mptr->id);
|
||||
|
||||
char vstr[MAX_NUMBUF];
|
||||
btoa(vstr, sizeof(vstr), v);
|
||||
ctx.out_printf(COLSTR("%s",SCOLOR_KEYWORD) " "
|
||||
COLSTR("%c%s",SCOLOR_DNUM)
|
||||
COLSTR(",",SCOLOR_SYMBOL) " "
|
||||
COLSTR("%s",SCOLOR_LOCNAME),
|
||||
ash.a_equ,
|
||||
sign,
|
||||
vstr,
|
||||
name.c_str());
|
||||
}
|
||||
556
idasdk76/module/oakdsp/reg.cpp
Normal file
556
idasdk76/module/oakdsp/reg.cpp
Normal file
@@ -0,0 +1,556 @@
|
||||
#include "oakdsp.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <segregs.hpp>
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const register_names[] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", // DAAU Registers
|
||||
"rb", // Base Register
|
||||
"y", // Input Register
|
||||
"st0", "st1", "st2", // Status Registers
|
||||
"p", // Output Register
|
||||
"pc", // Program Counter
|
||||
"sp", // Software Stack Pointer
|
||||
"cfgi", "cfgj", // DAAU Configuration Registers
|
||||
"b0h", "b1h", "b0l", "b1l", // Accumulator B
|
||||
"ext0","ext1", "ext2", "ext3", // External registers
|
||||
"a0", "a1", "a0l", "a1l", "a0h", "a1h", // Accumulator A
|
||||
"lc", // Loop Counter
|
||||
"sv", // Shift Value Register
|
||||
"x", // Input Register
|
||||
"dvm", // Data Value Match Register
|
||||
"mixp", // Minimal/Maximal Pointer Register
|
||||
"icr", // Internal Configuration Register
|
||||
"ps", // Product Shifter Control
|
||||
"repc", // Internal Repeat Counter
|
||||
"b0", "b1", // Accumulator B
|
||||
"modi", "modj", // Modulo Modifier
|
||||
"stepi","stepj", // Linear (Step) Modifier
|
||||
"page", // Short Direct Addressing Mode Page
|
||||
"cs","ds", // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcode_0[] = { 0x45, 0xc0 };
|
||||
static const uchar retcode_1[] = { 0x45, 0xd0 };
|
||||
static const uchar retcode_2[] = { 0x45, 0x80 };
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_0), retcode_0 },
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Dsp Group OAK DSP Assembler
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t oakasm =
|
||||
{
|
||||
ASH_HEXF4 // $34
|
||||
|ASD_DECF0 // 34
|
||||
|ASB_BINF2 // %01010
|
||||
|ASO_OCTF1 // 0123
|
||||
|AS_COLON
|
||||
|AS_N2CHR
|
||||
|AS_NCMAS
|
||||
|AS_ONEDUP,
|
||||
0,
|
||||
"Dsp Group OAK DSP Assembler",
|
||||
0,
|
||||
NULL, // header lines
|
||||
"org", // org
|
||||
"end", // end
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\"'", // special symbols in char and string constants
|
||||
|
||||
"dc", // ascii string directive
|
||||
"dcb", // byte directive
|
||||
"dc", // word directive
|
||||
NULL, // double words
|
||||
NULL, // qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
"bs#s(c,) #d, #v", // arrays (#h,#d,#v,#s(...)
|
||||
"ds %s", // uninited arrays
|
||||
"equ", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
"*", // current IP (instruction pointer)
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
"global", // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
"xref", // "extrn" name keyword
|
||||
// .extern directive requires an explicit object size
|
||||
NULL, // "comm" (communal variable)
|
||||
NULL, // const char *(*get_type_name)(int32 flag,uint32 id);
|
||||
NULL, // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"~", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
AS2_BYTE1CHAR,// One symbol per processor byte
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// GNU ASM
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t gas =
|
||||
{
|
||||
AS_ASCIIC
|
||||
|ASH_HEXF4 // $34
|
||||
|ASD_DECF0 // 34
|
||||
|ASB_BINF3 // 0b01010
|
||||
|ASO_OCTF1 // 0123
|
||||
|AS_COLON
|
||||
|AS_N2CHR
|
||||
|AS_NCMAS
|
||||
|AS_ONEDUP,
|
||||
UAS_GNU,
|
||||
"GNU-like hypothetical assembler",
|
||||
0,
|
||||
NULL, // header lines
|
||||
".org", // org
|
||||
NULL, // end
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\"'", // special symbols in char and string constants
|
||||
|
||||
".string", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".short", // word directive
|
||||
".long", // double words
|
||||
NULL, // qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
".ds.#s(b,w,l,d) #d, #v", // arrays (#h,#d,#v,#s(...)
|
||||
".space %s", // uninited arrays
|
||||
"=", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
".", // current IP (instruction pointer)
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
".global", // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
".extern", // "extrn" name keyword
|
||||
// .extern directive requires an explicit object size
|
||||
".comm", // "comm" (communal variable)
|
||||
NULL, // const char *(*get_type_name)(int32 flag,uint32 id);
|
||||
".align", // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
"mod", // mod
|
||||
"and", // and
|
||||
"or", // or
|
||||
"xor", // xor
|
||||
"not", // not
|
||||
"shl", // shl
|
||||
"shr", // shr
|
||||
NULL, // sizeof
|
||||
AS2_BYTE1CHAR,// One symbol per processor byte
|
||||
NULL, // cmnt2
|
||||
NULL, // low8
|
||||
NULL, // high8
|
||||
NULL, // low16
|
||||
NULL, // high16
|
||||
"#include \"%s\"", // a_include_fmt
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &oakasm, &gas, NULL };
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t oakdsp_t::add_data_segm(size_t size, int offset, const char *name) const
|
||||
{
|
||||
segment_t s;
|
||||
s.start_ea = free_chunk(0x1000000, size, 0xF);
|
||||
s.end_ea = s.start_ea + size;
|
||||
s.sel = allocate_selector((s.start_ea-offset) >> 4);
|
||||
s.type = SEG_DATA;
|
||||
s.bitness = ph.dnbits > 16;
|
||||
add_segm_ex(&s, name, "DATA", ADDSEG_NOSREG|ADDSEG_OR_DIE);
|
||||
return s.start_ea - offset;
|
||||
}
|
||||
|
||||
inline ea_t get_start(const segment_t *s)
|
||||
{ return s ? s->start_ea : BADADDR; }
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *oakdsp_iohandler_t::iocallback(const ioports_t &lports, const char *line)
|
||||
{
|
||||
int size;
|
||||
if ( qsscanf(line, "XMEMSIZE = %i", &size) == 1 )
|
||||
{
|
||||
pm.xmemsize = size;
|
||||
pm.ioh.deviceparams.sprnt("XMEM=0x%X", pm.xmemsize);
|
||||
return NULL;
|
||||
}
|
||||
return standard_callback(lports, line);
|
||||
}
|
||||
|
||||
const ioport_t *oakdsp_t::find_port(ea_t address)
|
||||
{
|
||||
return find_ioport(ioh.ports, address);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::create_xmem(void)
|
||||
{
|
||||
if ( xmem == BADADDR )
|
||||
xmem = add_data_segm(xmemsize, 0, "XMEM");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::select_device(const char *dname, int lrespect_info)
|
||||
{
|
||||
ioh.set_device_name(dname, lrespect_info);
|
||||
|
||||
create_xmem();
|
||||
|
||||
for ( int i=0; i < ioh.ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ioh.ports[i];
|
||||
ea_t ea = xmem + p.address;
|
||||
const char *name = p.name.c_str();
|
||||
ea_t nameea = get_name_ea(BADADDR, name);
|
||||
if ( nameea != ea )
|
||||
{
|
||||
set_name(nameea, "");
|
||||
if ( !set_name(ea, name, SN_NOCHECK|SN_NOWARN|SN_NODUMMY) )
|
||||
set_cmt(ea, name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *oakdsp_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/)
|
||||
{
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
if ( choose_ioport_device(&ioh.device, cfgfile) )
|
||||
select_device(ioh.device.c_str(), IORESP_INT);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// We always return "yes" because of the messy problem that
|
||||
// there are additional operands with a wrong operand number (always 1)
|
||||
static bool idaapi can_have_type(const op_t &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(oakdsp_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void oakdsp_t::load_from_idb()
|
||||
{
|
||||
xmem = get_start(get_segm_by_name("XMEM"));
|
||||
char dev[MAXSTR];
|
||||
char *pdev = helper.supstr(-1, dev, sizeof(dev)) > 0 ? dev : NULL;
|
||||
select_device(pdev, IORESP_NONE);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi oakdsp_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
init_emu();
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile: // new file loaded
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgfile, &cb) )
|
||||
select_device(ioh.device.c_str(), IORESP_AREA|IORESP_INT);
|
||||
else
|
||||
create_xmem();
|
||||
|
||||
segment_t *s0 = get_first_seg();
|
||||
if ( s0 != NULL )
|
||||
{
|
||||
segment_t *s1 = get_next_seg(s0->start_ea);
|
||||
for ( int i = PAGE; i <= vDS; i++ )
|
||||
{
|
||||
set_default_sreg_value(s0, i, BADSEL);
|
||||
set_default_sreg_value(s1, i, BADSEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
procnum = ph.get_proc_index();
|
||||
//fall through
|
||||
case processor_t::ev_oldfile: // old file loaded
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc: // new processor type
|
||||
{
|
||||
int n = va_arg(va, int);
|
||||
// bool keep_cfg = va_argi(va, bool);
|
||||
if ( procnum == -1 )
|
||||
{
|
||||
procnum = n;
|
||||
}
|
||||
else if ( procnum != n ) // can't change the processor type
|
||||
{ // after the initial set up
|
||||
warning("Sorry, processor type cannot be changed after loading");
|
||||
code = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case processor_t::ev_is_sane_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
int nocrefs = va_arg(va, int);
|
||||
return is_sane_insn(*insn, nocrefs) == 1 ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_may_be_func:
|
||||
// can a function start here?
|
||||
// arg: instruction
|
||||
// returns: probability 0..100
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
return may_be_func(*insn);
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
oakdsp_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
oakdsp_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 *);
|
||||
oakdsp_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 *);
|
||||
oakdsp_segend(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_assumes:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
oakdsp_assumes(*ctx);
|
||||
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_can_have_type:
|
||||
{
|
||||
const op_t *_op = va_arg(va, const op_t *);
|
||||
return can_have_type(*_op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_sp_based:
|
||||
{
|
||||
int *mode = va_arg(va, int *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
const op_t *_op = va_arg(va, const op_t *);
|
||||
*mode = is_sp_based(*insn, *_op);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
create_func_frame(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_get_frame_retsize:
|
||||
{
|
||||
int *frsize = va_arg(va, int *);
|
||||
const func_t *pfn = va_arg(va, const func_t *);
|
||||
*frsize = OAK_get_frame_retsize(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_gen_stkvar_def:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const member_t *mptr = va_arg(va, const member_t *);
|
||||
sval_t v = va_arg(va, sval_t);
|
||||
gen_stkvar_def(*ctx, mptr, v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
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;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "Atmel OAK DSP:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"oakdsp",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Dsp Group OAK DSP",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_OAKDSP, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_SEGS // has segment registers
|
||||
| PR_ALIGN // data items must be aligned
|
||||
| PR_BINMEM // module knows about memory organization
|
||||
| PR_ALIGN_INSN, // allow align instructions
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
16, // 16 bits in a byte for code segments
|
||||
16, // 16 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
register_names, // Register names
|
||||
qnumber(register_names), // Number of registers
|
||||
|
||||
PAGE, // first
|
||||
vDS, // last
|
||||
1, // size of a segment register
|
||||
vCS, vDS,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
OAK_Dsp_null,
|
||||
OAK_Dsp_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, 7, 15, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
OAK_Dsp_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
Reference in New Issue
Block a user