Repository URL to install this package:
Version:
9.0~241217-2.fc42 ▾
|
idapro-debugsource
/
usr
/
src
/
debug
/
idapro-9.0~241217-2.fc42.x86_64
/
module
/
oakdsp
/
ana.cpp
|
---|
#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 = 0 - ((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 = nullptr;
if ( insn.itype < OAK_Dsp_last )
name = Instructions[insn.itype].name;
warning("%a(%s): internal error in %s", insn.ea, name, module);
}