784 lines
39 KiB
C++
784 lines
39 KiB
C++
#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);
|
|
}
|