update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

View 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);
}

View 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
}

View 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);

View 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

View 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

View 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

View 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 &pm;
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

View 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());
}

View 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
};