2066 lines
62 KiB
C++
2066 lines
62 KiB
C++
/*
|
|
* Interactive disassembler (IDA).
|
|
* Copyright (c) Hex-Rays
|
|
* ALL RIGHTS RESERVED.
|
|
*
|
|
* Instruction decoder
|
|
*
|
|
*/
|
|
#include "ins.hpp"
|
|
|
|
static const int bcond_map[16] =
|
|
{
|
|
NEC850_BV, NEC850_BL,
|
|
NEC850_BZ, NEC850_BNH,
|
|
NEC850_BN, NEC850_BR,
|
|
NEC850_BLT, NEC850_BLE,
|
|
NEC850_BNV, NEC850_BNC,
|
|
NEC850_BNZ, NEC850_BH,
|
|
NEC850_BP, NEC850_BSA,
|
|
NEC850_BGE, NEC850_BGT
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// The instruction formats 5 to 10 have bit10 and bit9 on and are a word
|
|
// The rest of the instructions are half-word and their format is 1 to 4
|
|
int detect_inst_len(uint16 w)
|
|
{
|
|
return ((w & 0x600) == 0x600) ? 4 : 2;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Fetchs an instruction (uses ua_next_xxx(insn)) of a correct size (ready for decoding)
|
|
// Returns the size of the instruction
|
|
int fetch_instruction(uint32 *w, insn_t &insn)
|
|
{
|
|
uint16 hw = insn.get_next_word();
|
|
int r = detect_inst_len(hw);
|
|
if ( r == 4 )
|
|
*w = (insn.get_next_word() << 16) | hw;
|
|
else
|
|
*w = hw;
|
|
return r;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
static sval_t fetch_disp32(const uint32 w, insn_t &ins)
|
|
{
|
|
// 15 0 31 16 47 32
|
|
// xxxxxxxxxxxxxxxx ddddddddddddddd0 DDDDDDDDDDDDDDDD
|
|
uint32 d_low = (w >> 16);// ddddddddddddddd0
|
|
if ( ins.size == 2 )
|
|
d_low = ins.get_next_word();
|
|
else if ( ins.size != 4 )
|
|
{
|
|
// bad format
|
|
ins.size = 0;
|
|
ins.itype = 0;
|
|
return 1;
|
|
}
|
|
uint16 d_high = ins.get_next_word(); // DDDDDDDDDDDDDDDD
|
|
int32 addr = (d_high<<16) | d_low;
|
|
return sval_t(addr);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
static bool decode_disp23(const uint32 w, insn_t &ins, int opidx, op_dtype_t dt)
|
|
{
|
|
// LD.B disp23 [reg1] , reg3
|
|
// 00000111100RRRRR wwwwwddddddd0101 DDDDDDDDDDDDDDDD
|
|
// ddddddd is the lower 7 bits of disp23.
|
|
// DDDDDDDDDDDDDDDD is the higher 16 bits of disp23
|
|
// LD.H disp23[reg1], reg3
|
|
// 00000111100RRRRR wwwwwdddddd00111 DDDDDDDDDDDDDDDD
|
|
// dddddd is the lower side bits 6 to 1 of disp23.
|
|
// DDDDDDDDDDDDDDDD is the higher 16 bits of disp23.
|
|
|
|
// we need at least 32 bits of opcode here
|
|
if ( ins.size != 4 )
|
|
return false;
|
|
|
|
uint16 d_low = ( w >> 20 ) & 0x7F; // ddddddd
|
|
if ( dt != dt_byte && ( d_low & 1 ) != 0 )
|
|
return false;
|
|
uint16 d_high = ins.get_next_word(); // DDDDDDDDDDDDDDDD
|
|
sval_t addr = ( d_high << 7 ) | d_low;
|
|
SIGN_EXTEND(sval_t, addr, 23);
|
|
|
|
op_t &op = ins.ops[opidx];
|
|
op.type = o_displ;
|
|
op.reg = w & 0x1F;
|
|
op.addr = addr;
|
|
op.dtype = dt;
|
|
op.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED | N850F_VAL32;
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
static void set_opreg(op_t &op, int reg, op_dtype_t dtyp = dt_dword)
|
|
{
|
|
op.type = o_reg;
|
|
op.dtype = dtyp;
|
|
op.reg = reg;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Create operand of condition type
|
|
inline void set_opcond(op_t &x, uval_t value)
|
|
{
|
|
x.type = o_cond;
|
|
x.dtype = dt_qword;
|
|
x.value = value;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
static void set_opimm(op_t &op, uval_t value, int dtyp = dt_dword)
|
|
{
|
|
op.type = o_imm;
|
|
op.dtype = dtyp;
|
|
op.value = value;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Decodes an instruction "w" into cmd structure
|
|
bool nec850_t::decode_coprocessor(const uint32 w, insn_t &ins) const
|
|
{ // 11111 1 33222 2 222 22 2111 1
|
|
// 54321 098765 43210 10987 6 543 21 0987 6
|
|
// reg2 |opcode|reg1 |reg3 |b|cat|ty|subo|b|
|
|
// ..... |111111|.....|.....|1|...|..|....|0|
|
|
int r1 = w & 0x1F;
|
|
int r2 = ( w & 0xF800 ) >> 11;
|
|
int r3 = ( w & 0xF8000000 ) >> 27;
|
|
int cat = ( w >> 23 ) & 7;
|
|
int typ = ( w >> 21 ) & 3;
|
|
int subop = ( w >> 17 ) & 0xF;
|
|
ins.itype = NEC850_NULL;
|
|
// we only support V850E2M and RH850 FP instructions
|
|
if ( !is_v850e2m() )
|
|
return false;
|
|
if ( typ == 0 && cat == 0 )
|
|
{
|
|
// CMOVF.D: cat = 000, type = 00, subop = 1fff, reg3 != 0
|
|
// CMOVF.S : cat = 000, type = 00, subop = 0fff, reg3 != 0
|
|
// TRFSR: cat = 000, type = 00, subop = 0fff, reg1 = 0, reg3 = 0
|
|
if ( r3 != 0 )
|
|
{
|
|
// CMOVF.S|D fcbit, reg1, reg2, reg3
|
|
ins.itype = ( subop & 8 ) ? NEC850_CMOVF_D : NEC850_CMOVF_S;
|
|
int fcbit = subop & 7;
|
|
set_opimm(ins.Op1, fcbit);
|
|
set_opreg(ins.Op2, r1);
|
|
set_opreg(ins.Op3, r2);
|
|
set_opreg(ins.Op4, r3);
|
|
}
|
|
else if ( subop < 8 )
|
|
{
|
|
ins.itype = NEC850_TRFSR;
|
|
int fcbit = subop & 7;
|
|
set_opimm(ins.Op1, fcbit);
|
|
}
|
|
}
|
|
else if ( typ == 1 && cat == 0 && r3 < 0x10 )
|
|
{
|
|
// CMPF.D: cat = 000, type = 01, subop = 1fff, reg3 = 0FFFF
|
|
// CMPF.S : cat = 000, type = 01, subop = 0fff, reg3 = 0FFFF
|
|
// CMPF.S|D fcond, reg2, reg1, fcbit
|
|
ins.itype = ( subop & 8 ) ? NEC850_CMPF_D : NEC850_CMPF_S;
|
|
int fcbit = subop & 7;
|
|
set_opcond(ins.Op1, r3);
|
|
set_opreg(ins.Op2, r2);
|
|
set_opreg(ins.Op3, r1);
|
|
set_opimm(ins.Op4, fcbit);
|
|
}
|
|
else if ( typ == 3 )
|
|
{
|
|
// reg1, reg2, reg3
|
|
if ( cat == 0 )
|
|
{
|
|
switch ( subop & 7 )
|
|
{
|
|
case 0:
|
|
ins.itype = ( subop & 8 ) ? NEC850_ADDF_D : NEC850_ADDF_S;
|
|
break;
|
|
case 1:
|
|
ins.itype = ( subop & 8 ) ? NEC850_SUBF_D : NEC850_SUBF_S;
|
|
break;
|
|
case 2:
|
|
ins.itype = ( subop & 8 ) ? NEC850_MULF_D : NEC850_MULF_S;
|
|
break;
|
|
case 4:
|
|
ins.itype = ( subop & 8 ) ? NEC850_MAXF_D : NEC850_MAXF_S;
|
|
break;
|
|
case 5:
|
|
ins.itype = ( subop & 8 ) ? NEC850_MINF_D : NEC850_MINF_S;
|
|
break;
|
|
case 7:
|
|
ins.itype = ( subop & 8 ) ? NEC850_DIVF_D : NEC850_DIVF_S;
|
|
break;
|
|
|
|
}
|
|
}
|
|
else if ( cat == 1 && subop < 4 )
|
|
{
|
|
if ( is_rh850() )
|
|
{
|
|
uint16 itypes[] = { NEC850_FMAF_S, NEC850_FMSF_S, NEC850_FNMAF_S, NEC850_FNMSF_S };
|
|
ins.itype = itypes[subop];
|
|
}
|
|
}
|
|
if ( ins.itype != NEC850_NULL )
|
|
{
|
|
bool dbl = ( subop & 8 ) != 0;
|
|
op_dtype_t dt = dbl ? dt_double : dt_float;
|
|
set_opreg(ins.Op1, r1, dt);
|
|
set_opreg(ins.Op2, r2, dt);
|
|
set_opreg(ins.Op3, r3, dt);
|
|
}
|
|
}
|
|
else if ( typ == 2 && cat == 0 )
|
|
{
|
|
// reg2, reg3 conversions
|
|
op_dtype_t dtsrc = dt_float, dtdst = dt_float;
|
|
switch ( subop )
|
|
{
|
|
case 0:
|
|
{
|
|
// TRNCF.SW cat = 0 type = 2 subop = 0 reg1 = 1
|
|
// CEILF.SW cat = 0 type = 2 subop = 0 reg1 = 2
|
|
// FLOORF.SW cat = 0 type = 2 subop = 0 reg1 = 3
|
|
// CVTF.SW cat = 0 type = 2 subop = 0 reg1 = 4
|
|
// TRNCF.SUW cat = 0 type = 2 subop = 0 reg1 = 17
|
|
// CEILF.SUW cat = 0 type = 2 subop = 0 reg1 = 18
|
|
// FLOORF.SUW cat = 0 type = 2 subop = 0 reg1 = 19
|
|
// CVTF.SUW cat = 0 type = 2 subop = 0 reg1 = 20
|
|
static const int ops[] =
|
|
{
|
|
NEC850_NULL, NEC850_TRNCF_SW, NEC850_CEILF_SW, NEC850_FLOORF_SW, // 0-3
|
|
NEC850_CVTF_SW, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 4-7
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 8-11
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 12-15
|
|
NEC850_NULL, NEC850_TRNCF_SUW, NEC850_CEILF_SUW, NEC850_FLOORF_SUW, // 16-19
|
|
NEC850_CVTF_SUW // 20
|
|
};
|
|
if ( r1 < qnumber(ops) )
|
|
ins.itype = ops[r1];
|
|
dtsrc = dt_float;
|
|
dtdst = dt_dword;
|
|
}
|
|
break;
|
|
case 1:
|
|
{
|
|
// CVTF.WS cat=0 type=2 subop=1 reg1=0 dw f
|
|
// CVTF.LS cat=0 type=2 subop=1 reg1=1 dq f
|
|
// CVTF.HS cat=0 type=2 subop=1 reg1=2 h f
|
|
// CVTF.SH cat=0 type=2 subop=1 reg1=3 f h
|
|
// CVTF.UWS cat=0 type=2 subop=1 reg1=16 dw f
|
|
// CVTF.ULS cat=0 type=2 subop=1 reg1=17 dq f
|
|
static const int ops[] =
|
|
{
|
|
NEC850_CVTF_WS, NEC850_CVTF_LS, NEC850_CVTF_HS, NEC850_CVTF_SH, // 0-3
|
|
NEC850_CVTF_SW, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 4-7
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 8-11
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 12-15
|
|
NEC850_CVTF_UWS, NEC850_CVTF_ULS // 16-17
|
|
};
|
|
if ( r1 < qnumber(ops) )
|
|
ins.itype = ops[r1];
|
|
// NB: we use dt_float for half-precision
|
|
op_dtype_t srct[] = { dt_dword, dt_qword, dt_float, dt_float };
|
|
dtsrc = srct[r1&3];
|
|
dtdst = dt_float;
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
// TRNCF.SL cat=0 type=2 subop=2 reg1=1
|
|
// CEILF.SL cat=0 type=2 subop=2 reg1=2
|
|
// FLOORF.SL cat=0 type=2 subop=2 reg1=3
|
|
// CVTF.SL cat=0 type=2 subop=2 reg1=4
|
|
// TRNCF.SUL cat=0 type=2 subop=2 reg1=17
|
|
// CEILF.SUL cat=0 type=2 subop=2 reg1=18
|
|
// FLOORF.SUL cat=0 type=2 subop=2 reg1=19
|
|
// CVTF.SUL cat=0 type=2 subop=2 reg1=20
|
|
static const int ops[] =
|
|
{
|
|
NEC850_NULL, NEC850_TRNCF_SL, NEC850_CEILF_SL, NEC850_FLOORF_SL, // 0-3
|
|
NEC850_CVTF_SL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 4-7
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 8-11
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 12-15
|
|
NEC850_NULL, NEC850_TRNCF_SUL, NEC850_CEILF_SUL, NEC850_FLOORF_SUL, // 16-19
|
|
NEC850_CVTF_SUL // 20
|
|
};
|
|
if ( r1 < qnumber(ops) )
|
|
ins.itype = ops[r1];
|
|
dtsrc = dt_float;
|
|
dtdst = dt_qword;
|
|
}
|
|
break;
|
|
case 4:
|
|
case 12:
|
|
{
|
|
// ABSF.S cat = 0 type = 2 subop = 4 reg1 = 0
|
|
// NEGF.S cat = 0 type = 2 subop = 4 reg1 = 1
|
|
// ABSF.D cat = 0 type = 2 subop = 12 reg1 = 0
|
|
// NEGF.D cat = 0 type = 2 subop = 12 reg1 = 1
|
|
if ( r1 == 0 )
|
|
ins.itype = subop == 4 ? NEC850_ABSF_S : NEC850_ABSF_D;
|
|
else if ( r1 == 1 )
|
|
ins.itype = subop == 4 ? NEC850_NEGF_S : NEC850_NEGF_D;
|
|
|
|
dtsrc = subop == 4 ? dt_float: dt_double;
|
|
dtdst = dtsrc;
|
|
}
|
|
break;
|
|
case 7:
|
|
case 15:
|
|
{
|
|
// SQRTF.S cat=0 type=2 subop=7 reg1=0
|
|
// RECIPF.S cat=0 type=2 subop=7 reg1=1
|
|
// RSQRTF.S cat=0 type=2 subop=7 reg1=2
|
|
// SQRTF.D cat=0 type=2 subop=15 reg1=0
|
|
// RECIPF.D cat=0 type=2 subop=15 reg1=1
|
|
// RSQRTF.D cat=0 type=2 subop=15 reg1=2
|
|
|
|
if ( r1 == 0 )
|
|
ins.itype = subop == 7 ? NEC850_SQRTF_S : NEC850_SQRTF_D;
|
|
else if ( r1 == 1 )
|
|
ins.itype = subop == 7 ? NEC850_RECIPF_S : NEC850_RECIPF_D;
|
|
else if ( r1 == 2 )
|
|
ins.itype = subop == 7 ? NEC850_RSQRTF_S : NEC850_RSQRTF_D;
|
|
|
|
dtsrc = subop == 7 ? dt_float : dt_double;
|
|
dtdst = dtsrc;
|
|
}
|
|
break;
|
|
case 8:
|
|
{
|
|
// TRNCF.DW cat=0 type=2 subop=8 reg1=1
|
|
// CEILF.DW cat=0 type=2 subop=8 reg1=2
|
|
// FLOORF.DW cat=0 type=2 subop=8 reg1=3
|
|
// CVTF.DW cat=0 type=2 subop=8 reg1=4
|
|
// TRNCF.DUW cat=0 type=2 subop=8 reg1=17
|
|
// CEILF.DUW cat=0 type=2 subop=8 reg1=18
|
|
// FLOORF.DUW cat=0 type=2 subop=8 reg1=19
|
|
// CVTF.DUW cat=0 type=2 subop=8 reg1=20
|
|
static const int ops[] =
|
|
{
|
|
NEC850_NULL, NEC850_TRNCF_DW, NEC850_CEILF_DW, NEC850_FLOORF_DW, // 0-3
|
|
NEC850_CVTF_DW, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 4-7
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 8-11
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 12-15
|
|
NEC850_NULL, NEC850_TRNCF_DUW, NEC850_CEILF_DUW, NEC850_FLOORF_DUW, // 16-19
|
|
NEC850_CVTF_DUW // 20
|
|
};
|
|
if ( r1 < qnumber(ops) )
|
|
ins.itype = ops[r1];
|
|
dtsrc = dt_double;
|
|
dtdst = dt_dword;
|
|
}
|
|
break;
|
|
case 9:
|
|
{
|
|
// CVTF.WD cat=0 type=2 subop=9 reg1=0 dw d
|
|
// CVTF.LD cat=0 type=2 subop=9 reg1=1 dq d
|
|
// CVTF.SD cat=0 type=2 subop=9 reg1=2 f d
|
|
// CVTF.DS cat=0 type=2 subop=9 reg1=3 d f
|
|
// CVTF.UWD cat=0 type=2 subop=9 reg1=16 dw d
|
|
// CVTF.ULD cat=0 type=2 subop=9 reg1=17 dq d
|
|
static const int ops[] =
|
|
{
|
|
NEC850_CVTF_WD, NEC850_CVTF_LD, NEC850_CVTF_SD, NEC850_CVTF_DS, // 0-3
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 4-7
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 8-11
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 12-15
|
|
NEC850_CVTF_UWD, NEC850_CVTF_ULD // 16-17
|
|
};
|
|
if ( r1 < qnumber(ops) )
|
|
ins.itype = ops[r1];
|
|
op_dtype_t srct[] = { dt_dword, dt_qword, dt_float, dt_double };
|
|
dtsrc = srct[r1 & 3];
|
|
dtdst = r1 == 3 ? dt_float : dt_double;
|
|
}
|
|
break;
|
|
case 10:
|
|
{
|
|
// TRNCF.DL cat=0 type=2 subop=10 reg1=1
|
|
// CEILF.DL cat=0 type=2 subop=10 reg1=2
|
|
// FLOORF.DL cat=0 type=2 subop=10 reg1=3
|
|
// CVTF.DL cat=0 type=2 subop=10 reg1=4
|
|
// TRNCF.DUL cat=0 type=2 subop=10 reg1=17
|
|
// CEILF.DUL cat=0 type=2 subop=10 reg1=18
|
|
// FLOORF.DUL cat=0 type=2 subop=10 reg1=19
|
|
// CVTF.DUL cat=0 type=2 subop=10 reg1=20
|
|
static const int ops[] =
|
|
{
|
|
NEC850_NULL, NEC850_TRNCF_DL, NEC850_CEILF_DL, NEC850_FLOORF_DL, // 0-3
|
|
NEC850_CVTF_DL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 4-7
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 8-11
|
|
NEC850_NULL, NEC850_NULL, NEC850_NULL, NEC850_NULL, // 12-15
|
|
NEC850_NULL, NEC850_TRNCF_DUL, NEC850_CEILF_DUL, NEC850_FLOORF_DUL, // 16-19
|
|
NEC850_CVTF_DUL // 20
|
|
};
|
|
if ( r1 < qnumber(ops) )
|
|
ins.itype = ops[r1];
|
|
dtsrc = dt_double;
|
|
dtdst = dt_qword;
|
|
}
|
|
break;
|
|
}
|
|
if ( ins.itype != NEC850_NULL )
|
|
{
|
|
set_opreg(ins.Op1, r2, dtsrc);
|
|
set_opreg(ins.Op2, r3, dtdst);
|
|
}
|
|
}
|
|
if ( ins.itype == NEC850_NULL && is_v850e2m() && ( cat >> 1 ) == 1 )
|
|
{
|
|
// reg1, reg2, reg3, reg4
|
|
// MADDF.S: cat = 01W type = 00, subop = WWWW
|
|
// MSUBF.S : cat = 01W type = 01, subop = WWWW
|
|
// NMADDF.S : cat = 01W type = 10, subop = WWWW
|
|
// NMSUBF.S : cat = 01W type = 11, subop = WWWW
|
|
// WWWWW: reg4. (The least significant bit of reg4 is bit 23.)
|
|
|
|
int r4 = (subop << 1) | (cat & 1);
|
|
static const uint16 itypes[] = { NEC850_MADDF_S, NEC850_MSUBF_S, NEC850_NMADDF_S, NEC850_NMSUBF_S };
|
|
ins.itype = itypes[typ];
|
|
set_opreg(ins.Op1, r1, dt_float);
|
|
set_opreg(ins.Op2, r2, dt_float);
|
|
set_opreg(ins.Op3, r3, dt_float);
|
|
set_opreg(ins.Op4, r4, dt_float);
|
|
}
|
|
|
|
|
|
if ( ins.itype != NEC850_NULL )
|
|
{
|
|
ins.auxpref |= N850F_FP;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Decodes an instruction "w" into cmd structure
|
|
bool nec850_t::decode_instruction(const uint32 w, insn_t &ins)
|
|
{
|
|
#define PARSE_L12 (((w & 1) << 11) | (w >> 21))
|
|
#define PARSE_R1 (w & 0x1F)
|
|
#define PARSE_R2 ((w & 0xF800) >> 11)
|
|
|
|
typedef struct
|
|
{
|
|
int itype;
|
|
int flags;
|
|
} itype_flags_t;
|
|
// If an instruction deals with displacement it should
|
|
// initialize this pointer to the operand location.
|
|
// At the end we will transform the operand to o_mem
|
|
// if we know how to resolve its address
|
|
op_t *displ_op = NULL;
|
|
|
|
do
|
|
{
|
|
uint32 op;
|
|
|
|
//
|
|
// Format I
|
|
//
|
|
op = (w & 0x7E0) >> 5; // Take bit5->bit10
|
|
if ( op <= 0xF )
|
|
{
|
|
static const int inst_1[] =
|
|
{
|
|
/* MOV reg1, reg2 */ NEC850_MOV, /* NOT reg1, reg2 */ NEC850_NOT,
|
|
/* DIVH reg1, reg2 */ NEC850_DIVH, /* JMP [reg1] */ NEC850_JMP,
|
|
/* SATSUBR reg1, reg2 */ NEC850_SATSUBR, /* SATSUB reg1, reg2 */ NEC850_SATSUB,
|
|
/* SATADD reg1, reg2 */ NEC850_SATADD, /* MULH reg1, reg2 */ NEC850_MULH,
|
|
/* OR reg1, reg2 */ NEC850_OR, /* XOR reg1, reg2 */ NEC850_XOR,
|
|
/* AND reg1, reg2 */ NEC850_AND, /* TST reg1, reg2 */ NEC850_TST,
|
|
/* SUBR reg1, reg2 */ NEC850_SUBR, /* SUB reg1, reg2 */ NEC850_SUB,
|
|
/* ADD reg1, reg2 */ NEC850_ADD, /* CMP reg1, reg2 */ NEC850_CMP
|
|
};
|
|
|
|
//
|
|
// NOP, Equivalent to MOV R, r (where R=r=0)
|
|
if ( w == 0 )
|
|
{
|
|
ins.itype = NEC850_NOP;
|
|
ins.Op1.type = o_void;
|
|
ins.Op1.dtype = dt_void;
|
|
break;
|
|
}
|
|
|
|
uint16 r1 = PARSE_R1;
|
|
uint16 r2 = PARSE_R2;
|
|
if ( is_v850e() && op == 2 && r1 == 0 )
|
|
{
|
|
switch ( r2 )
|
|
{
|
|
case 0:
|
|
if ( is_v850e2m() )
|
|
ins.itype = NEC850_RIE;
|
|
break;
|
|
case 0x1C:
|
|
if ( is_rh850() )
|
|
ins.itype = NEC850_DBHVTRAP;
|
|
break;
|
|
case 0x1D:
|
|
if ( is_rh850() )
|
|
ins.itype = NEC850_DBCP;
|
|
break;
|
|
case 0x1E:
|
|
if ( is_v850e2m() )
|
|
ins.itype = NEC850_RMTRAP;
|
|
break;
|
|
case 0x1F:
|
|
ins.itype = NEC850_DBTRAP;
|
|
break;
|
|
default:
|
|
if ( is_v850e2() && r2 < 0x10 )
|
|
{
|
|
ins.itype = NEC850_FETRAP;
|
|
set_opimm(ins.Op1, r2);
|
|
}
|
|
break;
|
|
}
|
|
if ( ins.itype != 0 )
|
|
break;
|
|
}
|
|
|
|
ins.itype = inst_1[op];
|
|
set_opreg(ins.Op1, r1);
|
|
|
|
if ( is_v850e() )
|
|
{
|
|
if ( r2 == 0 )
|
|
{
|
|
if ( is_v850e2m() && op == 0 )
|
|
{
|
|
switch ( r1 )
|
|
{
|
|
case 0x1C:
|
|
if ( is_rh850() )
|
|
ins.itype = NEC850_SYNCI;
|
|
else
|
|
ins.itype = NEC850_NULL;
|
|
break;
|
|
case 0x1D:
|
|
ins.itype = NEC850_SYNCE;
|
|
break;
|
|
case 0x1E:
|
|
ins.itype = NEC850_SYNCM;
|
|
break;
|
|
case 0x1F:
|
|
ins.itype = NEC850_SYNCP;
|
|
break;
|
|
default:
|
|
ins.itype = NEC850_NULL;
|
|
break;
|
|
}
|
|
if ( ins.itype != NEC850_NULL )
|
|
{
|
|
ins.Op1.type = o_void;
|
|
ins.Op2.type = o_void;
|
|
break;
|
|
}
|
|
}
|
|
else if ( ins.itype == NEC850_DIVH )
|
|
{
|
|
ins.itype = NEC850_SWITCH;
|
|
break;
|
|
}
|
|
else if ( ins.itype == NEC850_SATSUBR )
|
|
{
|
|
ins.itype = NEC850_ZXB;
|
|
break;
|
|
}
|
|
else if ( ins.itype == NEC850_SATSUB )
|
|
{
|
|
ins.itype = NEC850_SXB;
|
|
break;
|
|
}
|
|
else if ( ins.itype == NEC850_SATADD )
|
|
{
|
|
ins.itype = NEC850_ZXH;
|
|
break;
|
|
}
|
|
else if ( ins.itype == NEC850_MULH )
|
|
{
|
|
ins.itype = NEC850_SXH;
|
|
break;
|
|
}
|
|
}
|
|
// case when r2 != 0
|
|
else
|
|
{
|
|
// SLD.BU / SLD.HU
|
|
if ( ins.itype == NEC850_JMP )
|
|
{
|
|
bool sld_hu = (w >> 4) & 1;
|
|
uint32 addr = w & 0xF;
|
|
|
|
if ( sld_hu )
|
|
{
|
|
ins.itype = NEC850_SLD_HU;
|
|
ins.Op1.dtype = dt_word;
|
|
addr <<= 1;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_SLD_BU;
|
|
ins.Op1.dtype = dt_byte;
|
|
}
|
|
|
|
ins.Op1.type = o_displ;
|
|
displ_op = &ins.Op1;
|
|
ins.Op1.reg = rEP;
|
|
ins.Op1.addr = addr;
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS;
|
|
|
|
set_opreg(ins.Op2, r2);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( ins.itype == NEC850_JMP && r2 == 0 )
|
|
{
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS;
|
|
}
|
|
else
|
|
{
|
|
set_opreg(ins.Op2, r2);
|
|
}
|
|
break;
|
|
}
|
|
// Format II
|
|
else if ( op <= 0x17 )
|
|
{
|
|
if ( PARSE_R2 == 0 && op == 0x17 && is_v850e2m() )
|
|
{
|
|
// 48-bit Format VI jr/jarl
|
|
// JARL disp32, reg1: 00000010111RRRRR ddddddddddddddd0 DDDDDDDDDDDDDDDD
|
|
// JR disp32: 0000001011100000 ddddddddddddddd0 DDDDDDDDDDDDDDDD
|
|
uint16 reg = PARSE_R1;
|
|
sval_t addr = fetch_disp32(w, ins);
|
|
if ( (addr & 1) != 0 )
|
|
return false;
|
|
ins.Op1.addr = ins.ip + addr;
|
|
ins.Op1.type = o_near;
|
|
ins.Op1.specflag1 = N850F_VAL32;
|
|
if ( reg == 0 )
|
|
{
|
|
ins.itype = NEC850_JR;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_JARL;
|
|
set_opreg(ins.Op2, reg);
|
|
}
|
|
break;
|
|
}
|
|
// flag used for sign extension
|
|
static const itype_flags_t inst_2[] =
|
|
{
|
|
{ NEC850_MOV, 1 }, /* MOV imm5, reg2 */
|
|
{ NEC850_SATADD, 1 }, /* SATADD imm5, reg2 */
|
|
{ NEC850_ADD, 1 }, /* ADD imm5, reg2 */
|
|
{ NEC850_CMP, 1 }, /* CMP imm5, reg2 */
|
|
{ NEC850_SHR, 0 }, /* SHR imm5, reg2 */
|
|
{ NEC850_SAR, 0 }, /* SAR imm5, reg2 */
|
|
{ NEC850_SHL, 0 }, /* SHL imm5, reg2 */
|
|
{ NEC850_MULH, 1 }, /* MULH imm5, reg2 */
|
|
};
|
|
op -= 0x10;
|
|
|
|
ins.itype = inst_2[op].itype;
|
|
uint16 r2 = PARSE_R2;
|
|
|
|
if ( is_v850e() )
|
|
{
|
|
//
|
|
// CALLT
|
|
//
|
|
if ( r2 == 0 && (ins.itype == NEC850_SATADD || ins.itype == NEC850_MOV) )
|
|
{
|
|
ins.itype = NEC850_CALLT;
|
|
set_opimm(ins.Op1, w & 0x3F, dt_byte);
|
|
if ( g_ctbp_ea != BADADDR )
|
|
{
|
|
// resolve callt addr using ctbp
|
|
ea_t ctp = g_ctbp_ea + (ins.Op1.value << 1);
|
|
ins.Op1.type = o_near;
|
|
ins.Op1.addr = g_ctbp_ea + get_word(ctp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
sval_t v = PARSE_R1;
|
|
if ( inst_2[op].flags == 1 )
|
|
{
|
|
SIGN_EXTEND(sval_t, v, 5);
|
|
ins.Op1.specflag1 |= N850F_OUTSIGNED;
|
|
}
|
|
|
|
set_opimm(ins.Op1, v, dt_byte);
|
|
set_opreg(ins.Op2, r2);
|
|
|
|
// ADD imm, reg -> reg = reg + imm
|
|
if ( ins.itype == NEC850_ADD && r2 == rSP )
|
|
ins.auxpref |= N850F_SP;
|
|
break;
|
|
}
|
|
// Format VI
|
|
else if ( op >= 0x30 && op <= 0x37 )
|
|
{
|
|
static const itype_flags_t inst_6[] =
|
|
{ // itype flags (1=signed)
|
|
{ NEC850_ADDI, 1 }, /* ADDI imm16, reg1, reg2 */
|
|
{ NEC850_MOVEA, 1 }, /* MOVEA imm16, reg1, reg2 */
|
|
{ NEC850_MOVHI, 0 }, /* MOVHI imm16, reg1, reg2 */
|
|
{ NEC850_SATSUBI, 1 }, /* SATSUBI imm16, reg1, reg2 */
|
|
{ NEC850_ORI, 0 }, /* ORI imm16, reg1, reg2 */
|
|
{ NEC850_XORI, 0 }, /* XORI imm16, reg1, reg2 */
|
|
{ NEC850_ANDI, 0 }, /* ANDI imm16, reg1, reg2 */
|
|
{ NEC850_MULHI, 0 }, /* MULHI imm16, reg1, reg2 */
|
|
};
|
|
op -= 0x30;
|
|
ins.itype = inst_6[op].itype;
|
|
|
|
uint16 r1 = PARSE_R1;
|
|
uint16 r2 = PARSE_R2;
|
|
uint32 imm = w >> 16;
|
|
|
|
//
|
|
// V850E instructions
|
|
if ( is_v850e() && r2 == 0 )
|
|
{
|
|
if ( ins.itype == NEC850_MULHI )
|
|
{
|
|
if ( !is_v850e2() )
|
|
return false; // "Do not specify r0 as the destination register reg2."
|
|
if ( ( imm & 1 ) != 0 )
|
|
{
|
|
// RH850: LOOP reg1,disp16
|
|
// 00000110111RRRRR ddddddddddddddd1
|
|
if ( !is_rh850() || r1 == 0 )
|
|
return false; // "Do not specify r0 for reg1."
|
|
ins.itype = NEC850_LOOP;
|
|
set_opreg(ins.Op1, r1);
|
|
imm ^= 1; // clear bit 0
|
|
sval_t addr = ins.ip - imm;
|
|
ins.Op2.addr = addr;
|
|
ins.Op2.type = o_near;
|
|
}
|
|
else
|
|
{
|
|
// V850E2: jmp disp32 [reg1]
|
|
// 00000110111RRRRR ddddddddddddddd0 DDDDDDDDDDDDDDDD
|
|
sval_t addr = fetch_disp32(w, ins);
|
|
if ( ( addr & 1 ) != 0 )
|
|
return false;
|
|
ins.Op1.addr = addr;
|
|
ins.Op1.type = o_displ;
|
|
ins.Op1.specflag1 = N850F_OUTSIGNED | N850F_VAL32 | N850F_USEBRACKETS;
|
|
ins.Op1.reg = r1;
|
|
ins.itype = NEC850_JMP;
|
|
}
|
|
break;
|
|
}
|
|
// MOV imm32, R
|
|
if ( ins.itype == NEC850_MOVEA )
|
|
{
|
|
imm |= ins.get_next_word() << 16;
|
|
set_opimm(ins.Op1, imm);
|
|
ins.itype = NEC850_MOV;
|
|
|
|
set_opreg(ins.Op2, r1);
|
|
break;
|
|
}
|
|
// DISPOSE imm5, list12 (reg1 == 0)
|
|
// DISPOSE imm5, list12, [reg1]
|
|
else if ( ins.itype == NEC850_SATSUBI || ins.itype == NEC850_MOVHI )
|
|
{
|
|
r1 = (w >> 16) & 0x1F;
|
|
uint16 L = PARSE_L12;
|
|
|
|
ins.auxpref |= N850F_SP; // SP reference
|
|
|
|
set_opimm(ins.Op1, (w & 0x3E) >> 1, dt_byte);
|
|
|
|
ins.Op2.value = L;
|
|
ins.Op2.type = o_reglist;
|
|
ins.Op2.dtype = dt_word;
|
|
|
|
if ( r1 != 0 )
|
|
{
|
|
set_opreg(ins.Op3, r1);
|
|
ins.Op3.specflag1 = N850F_USEBRACKETS;
|
|
|
|
ins.itype = NEC850_DISPOSE_r;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_DISPOSE_r0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
bool is_signed = inst_6[op].flags == 1;
|
|
set_opimm(ins.Op1, is_signed ? sval_t(int16(imm)) : imm);
|
|
ins.Op1.specflag1 |= N850F_OUTSIGNED;
|
|
|
|
set_opreg(ins.Op2, r1);
|
|
|
|
set_opreg(ins.Op3, r2);
|
|
|
|
// (ADDI|MOVEA) imm, sp, sp -> sp = sp + imm
|
|
if ( (ins.itype == NEC850_ADDI || ins.itype == NEC850_MOVEA)
|
|
&& ((r1 == rSP) && (r2 == rSP)) )
|
|
{
|
|
ins.auxpref |= N850F_SP;
|
|
}
|
|
break;
|
|
}
|
|
// Format VII - LD.x
|
|
else if ( op == 0x38 || op == 0x39 )
|
|
{
|
|
displ_op = &ins.Op1;
|
|
ins.Op1.type = o_displ;
|
|
ins.Op1.phrase = PARSE_R1; // R
|
|
|
|
set_opreg(ins.Op2, PARSE_R2);
|
|
|
|
uint32 addr;
|
|
// LD.B
|
|
if ( op == 0x38 )
|
|
{
|
|
addr = w >> 16;
|
|
ins.itype = NEC850_LD_B;
|
|
ins.Op1.dtype = dt_byte;
|
|
}
|
|
else
|
|
{
|
|
// Bit16 is cleared for LD.H
|
|
if ( (w & (1 << 16)) == 0 )
|
|
{
|
|
ins.itype = NEC850_LD_H;
|
|
ins.Op1.dtype = dt_word;
|
|
}
|
|
// LD.W
|
|
else
|
|
{
|
|
ins.itype = NEC850_LD_W;
|
|
ins.Op1.dtype = dt_dword;
|
|
}
|
|
addr = ((w & 0xFFFE0000) >> 17) << 1;
|
|
}
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED;
|
|
ins.Op1.addr = int16(addr);
|
|
|
|
break;
|
|
}
|
|
// Format VII - ST.x
|
|
else if ( op == 0x3A || op == 0x3B )
|
|
{
|
|
// (1) ST.B reg2, disp16 [reg1]
|
|
// (2) ST.H reg2, disp16 [reg1]
|
|
// (3) ST.W reg2, disp16 [reg1]
|
|
set_opreg(ins.Op1, PARSE_R2);
|
|
|
|
ins.Op2.type = o_displ;
|
|
displ_op = &ins.Op2;
|
|
ins.Op2.reg = PARSE_R1;
|
|
ins.Op2.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED;
|
|
// ST.B
|
|
uint32 addr;
|
|
if ( op == 0x3A )
|
|
{
|
|
addr = w >> 16;
|
|
ins.itype = NEC850_ST_B;
|
|
ins.Op2.dtype = dt_byte;
|
|
}
|
|
else
|
|
{
|
|
// Bit16 is cleared for ST.H
|
|
if ( (w & (1 << 16)) == 0 )
|
|
{
|
|
ins.itype = NEC850_ST_H;
|
|
ins.Op2.dtype = dt_word;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_ST_W;
|
|
ins.Op2.dtype = dt_dword;
|
|
}
|
|
addr = ((w & 0xFFFE0000) >> 17) << 1;
|
|
}
|
|
ins.Op2.addr = int16(addr);
|
|
break;
|
|
}
|
|
// Format XIII - PREPARE / LD.BU
|
|
else if ( is_v850e()
|
|
&& ((w >> 16) & 0x1) // this bit is important to differentiate between JARL/JR instructions
|
|
&& (op == 0x3C || op == 0x3D) )
|
|
{
|
|
uint16 r2 = PARSE_R2;
|
|
|
|
uint16 subop = (w >> 16) & 0x1F;
|
|
// PREPARE
|
|
if ( r2 == 0 && (subop == 1 || (subop & 7) == 3) )
|
|
{
|
|
ins.auxpref |= N850F_SP;
|
|
ins.Op1.value = PARSE_L12;
|
|
ins.Op1.type = o_reglist;
|
|
ins.Op1.dtype = dt_word;
|
|
|
|
set_opimm(ins.Op2, (w & 0x3E) >> 1, dt_byte);
|
|
|
|
if ( subop == 1 )
|
|
{
|
|
ins.itype = NEC850_PREPARE_i;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_PREPARE_sp;
|
|
uint16 ff = subop >> 3;
|
|
switch ( ff )
|
|
{
|
|
case 0:
|
|
// disassembles as: PREPARE list12, imm5, sp
|
|
// meaning: load sp into ep
|
|
set_opreg(ins.Op3, rSP);
|
|
break;
|
|
// the other cases disassemble with imm (the 3rd operand) directly processed:
|
|
// f=1->ep=sign_extend(imm16), f=2->ep=imm16 shl 16, f=3->ep=imm32
|
|
case 1:
|
|
// c: a8 07 0b 80 prepare {r24}, 20, 0x1
|
|
// 10: 01 00
|
|
set_opimm(ins.Op3, sval_t(int16(ins.get_next_word())));
|
|
break;
|
|
case 2:
|
|
// 2: a8 07 13 80 prepare {r24}, 20, 0x10000
|
|
// 6: 01 00
|
|
set_opimm(ins.Op3, ins.get_next_word() << 16);
|
|
break;
|
|
case 3:
|
|
// 2: a8 07 1b 80 prepare {r24}, 20, 0x1
|
|
// 6: 01 00 00 00
|
|
set_opimm(ins.Op3, ins.get_next_dword());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( r2 == 0 && is_v850e2m() )
|
|
{
|
|
// disp23 variants ( Format XIV)
|
|
// LD.BU disp23 [reg1] , reg3
|
|
// 00000111101RRRRR wwwwwddddddd0101 DDDDDDDDDDDDDDDD
|
|
// LD.HU disp23 [reg1] , reg3
|
|
// 00000111101RRRRR wwwwwdddddd00111 DDDDDDDDDDDDDDDD
|
|
// ST.H reg3, disp23 [reg1]
|
|
// 00000111101RRRRR wwwwwdddddd01101 DDDDDDDDDDDDDDDD
|
|
// ST.H reg3, disp23 [reg1]
|
|
// 00000111101RRRRR wwwwwdddddd01101 DDDDDDDDDDDDDDDD
|
|
// LD.B disp23 [reg1] , reg3
|
|
// 00000111100RRRRR wwwwwddddddd0101 DDDDDDDDDDDDDDDD
|
|
// LD.H disp23 [reg1] , reg3
|
|
// 00000111100RRRRR wwwwwdddddd00111 DDDDDDDDDDDDDDDD
|
|
// LD.W disp23 [reg1] , reg3
|
|
// 00000111100RRRRR wwwwwdddddd01001 DDDDDDDDDDDDDDDD
|
|
// LD.DW disp23[reg1], reg3
|
|
// 00000111101RRRRR wwwwwdddddd01001 DDDDDDDDDDDDDDDD
|
|
// ST.B reg3, disp23 [reg1]
|
|
// 00000111100RRRRR wwwwwddddddd1101 DDDDDDDDDDDDDDDD
|
|
// ST.W reg3, disp23 [reg1]
|
|
// 00000111100RRRRR wwwwwdddddd01111 DDDDDDDDDDDDDDDD
|
|
// ST.DW reg3, disp23[reg1]
|
|
// 00000111101RRRRR wwwwwdddddd01111 DDDDDDDDDDDDDDDD
|
|
// RRRRR = reg1, wwwww = reg3.
|
|
// ddddddd is the lower 7 bits of disp23.
|
|
// DDDDDDDDDDDDDDDD is the higher 16 bits of disp23.
|
|
subop = ( w >> 16 ) & 0xF;
|
|
bool sign = ( op & 1 ) == 0;
|
|
uint32 r3 = ( w & 0xF8000000 ) >> 27;
|
|
switch ( subop )
|
|
{
|
|
case 5:
|
|
ins.itype = sign ? NEC850_LD_B : NEC850_LD_BU;
|
|
if ( !decode_disp23(w, ins, 0, dt_byte) )
|
|
return false;
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
case 7:
|
|
ins.itype = sign ? NEC850_LD_H : NEC850_LD_HU;
|
|
if ( !decode_disp23(w, ins, 0, dt_word) )
|
|
return false;
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
case 9:
|
|
if ( !sign && !is_rh850() )
|
|
return false;
|
|
ins.itype = sign ? NEC850_LD_W : NEC850_LD_DW;
|
|
if ( !decode_disp23(w, ins, 0, dt_dword) )
|
|
return false;
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
case 13:
|
|
ins.itype = sign ? NEC850_ST_B : NEC850_ST_H;
|
|
if ( !decode_disp23(w, ins, 1, sign ? dt_byte : dt_word) )
|
|
return false;
|
|
set_opreg(ins.Op1, r3);
|
|
break;
|
|
case 15:
|
|
if ( !sign && !is_rh850() )
|
|
return false;
|
|
ins.itype = sign ? NEC850_ST_W : NEC850_ST_DW;
|
|
if ( !decode_disp23(w, ins, 1, dt_dword) )
|
|
return false;
|
|
set_opreg(ins.Op1, r3);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// LD.BU disp16 [reg1] , reg2
|
|
// rrrrr11110bRRRRR ddddddddddddddd1
|
|
// ddddddddddddddd is the higher 15 bits of disp16, and b is bit 0 of disp16.
|
|
// rrrrr != 00000 ( Do not specify r0 for reg2. )
|
|
if ( r2 == 0 )
|
|
return false;
|
|
uint16 r1 = PARSE_R1;
|
|
|
|
ins.itype = NEC850_LD_BU;
|
|
|
|
ins.Op1.type = o_displ;
|
|
displ_op = &ins.Op1;
|
|
ins.Op1.reg = r1;
|
|
ins.Op1.addr = int16(((w >> 16) & ~1) | ((w & 0x20) >> 5));
|
|
ins.Op1.dtype = dt_byte;
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED;
|
|
|
|
set_opreg(ins.Op2, r2);
|
|
}
|
|
break;
|
|
}
|
|
// Format VIII
|
|
else if ( op == 0x3E )
|
|
{
|
|
// parse sub-opcode (b15..b14)
|
|
op = ((w & 0xC000) >> 14);
|
|
static const int inst_8[] =
|
|
{
|
|
NEC850_SET1, NEC850_NOT1,
|
|
NEC850_CLR1, NEC850_TST1
|
|
};
|
|
ins.itype = inst_8[op];
|
|
set_opimm(ins.Op1, ((w & 0x3800) >> 11), dt_byte);
|
|
|
|
|
|
ins.Op2.type = o_displ;
|
|
displ_op = &ins.Op2;
|
|
ins.Op2.addr = int16(w >> 16);
|
|
ins.Op2.offb = 2;
|
|
ins.Op2.dtype = dt_byte;
|
|
ins.Op2.reg = PARSE_R1; // R
|
|
ins.Op2.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED;
|
|
break;
|
|
}
|
|
//
|
|
// Format IX, X
|
|
//
|
|
else if ( op == 0x3F )
|
|
{
|
|
if ( (w & ( 1 << 16 )) == 0 && ( w & ( 1 << 26 ) ) != 0 )
|
|
// coprocessor insn
|
|
return decode_coprocessor(w, ins);
|
|
//
|
|
// Format X
|
|
//
|
|
|
|
// Const opcodes
|
|
if ( w == 0x16087E0 ) // EI
|
|
ins.itype = NEC850_EI;
|
|
else if ( w == 0x16007E0 ) // DI
|
|
ins.itype = NEC850_DI;
|
|
else if ( w == 0x14007E0 ) // RETI
|
|
ins.itype = NEC850_RETI;
|
|
else if ( w == 0x12007E0 ) // HALT
|
|
ins.itype = NEC850_HALT;
|
|
else if ( w == 0xffffffff )
|
|
ins.itype = NEC850_BREAKPOINT;
|
|
else if ( (w >> 5) == 0x8003F ) //lint !e587 predicate always false // TRAP
|
|
{
|
|
ins.itype = NEC850_TRAP;
|
|
set_opimm(ins.Op1, PARSE_R1, dt_byte);
|
|
break;
|
|
}
|
|
if ( ins.itype != 0 )
|
|
break;
|
|
if ( is_v850e1f() && !is_v850e2m() )
|
|
{
|
|
// E1F opcodes (ref. U16374EJ1V0UM)
|
|
int subop = ( w >> 16 ) & 0x7FF;
|
|
int r3 = ( w & 0xF8000000 ) >> 27;
|
|
switch ( subop )
|
|
{
|
|
// Format F:I reg1, reg2, reg3
|
|
case 0x3E0:
|
|
ins.itype = NEC850_DIVF_S;
|
|
goto OPS_FI;
|
|
case 0x3E4:
|
|
ins.itype = NEC850_SUBF_S;
|
|
goto OPS_FI;
|
|
case 0x3E8:
|
|
ins.itype = NEC850_ADDF_S;
|
|
goto OPS_FI;
|
|
case 0x3EC:
|
|
ins.itype = NEC850_MULF_S;
|
|
goto OPS_FI;
|
|
case 0x3F0:
|
|
ins.itype = NEC850_MINF_S;
|
|
goto OPS_FI;
|
|
case 0x3F4:
|
|
ins.itype = NEC850_MAXF_S;
|
|
OPS_FI:
|
|
set_opreg(ins.Op1, PARSE_R1);
|
|
set_opreg(ins.Op2, PARSE_R2);
|
|
set_opreg(ins.Op3, r3);
|
|
break;
|
|
// Format F:II reg2, reg3
|
|
case 0x360:
|
|
ins.itype = NEC850_CVT_SW;
|
|
OPS_FII:
|
|
set_opreg(ins.Op1, PARSE_R2);
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
case 0x368:
|
|
ins.itype = NEC850_TRNC_SW;
|
|
goto OPS_FII;
|
|
case 0x370:
|
|
ins.itype = NEC850_CVT_WS;
|
|
goto OPS_FII;
|
|
case 0x3F8:
|
|
ins.itype = NEC850_NEGF_S;
|
|
goto OPS_FII;
|
|
case 0x3FC:
|
|
ins.itype = NEC850_ABSF_S;
|
|
goto OPS_FII;
|
|
|
|
// Format F:IV reg2 or reg3
|
|
case 0x378:
|
|
if ( r3 != 0 )
|
|
{
|
|
// STFF EFG,reg2
|
|
ins.itype = NEC850_STFF;
|
|
set_opreg(ins.Op1, EFG);
|
|
set_opreg(ins.Op2, r3);
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_TRFF;
|
|
// no operands
|
|
}
|
|
break;
|
|
case 0x37C:
|
|
// STFC ECT,reg2
|
|
ins.itype = NEC850_STFC;
|
|
set_opreg(ins.Op1, ECT);
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
|
|
case 0x37A:
|
|
if ( r3 == 0 )
|
|
{
|
|
// LDFF reg2,EFG
|
|
ins.itype = NEC850_LDFF;
|
|
set_opreg(ins.Op1, PARSE_R2);
|
|
set_opreg(ins.Op2, EFG);
|
|
}
|
|
break;
|
|
|
|
case 0x37E:
|
|
if ( r3 == 0 )
|
|
{
|
|
// LDFC reg2,ECT
|
|
ins.itype = NEC850_LDFC;
|
|
set_opreg(ins.Op1, PARSE_R2);
|
|
set_opreg(ins.Op2, ECT);
|
|
}
|
|
break;
|
|
|
|
}
|
|
if ( ins.itype != 0 )
|
|
break;
|
|
}
|
|
// Still in format 10 (op = 0x3F)
|
|
if ( is_v850e() )
|
|
{
|
|
if ( is_v850e2m() )
|
|
{
|
|
if ( w == 0x14807E0 )
|
|
ins.itype = NEC850_EIRET;
|
|
else if ( w == 0x14a07E0 )
|
|
ins.itype = NEC850_FERET;
|
|
else if ( ( w & 0xc7ffffe0 ) == 0x0160d7e0 )
|
|
{
|
|
ins.itype = NEC850_SYSCALL;
|
|
int v8 = (w & 0x1f) | ((w >> (27 - 5)) & 0xe0);
|
|
set_opimm(ins.Op1, v8);
|
|
}
|
|
else if ( is_rh850() )
|
|
{
|
|
int subop = ( w >> 16 ) & 0x7FF;
|
|
switch ( subop )
|
|
{
|
|
case 0x20:
|
|
case 0x40:
|
|
{
|
|
// LDSR reg2, regID, selID
|
|
// rrrrr111111RRRRR sssss00000100000
|
|
// rrrrr: regID, sssss: selID, RRRRR: reg2
|
|
// STSR regID, reg2, selID
|
|
// rrrrr111111RRRRR sssss00001000000
|
|
// rrrrr: regID, sssss: selID, RRRRR: reg2
|
|
bool is_ld = subop == 0x20;
|
|
ins.itype = is_ld ? NEC850_LDSR : NEC850_STSR;
|
|
uint32 selid = ( w & 0xF8000000 ) >> 27;
|
|
uint32 regid = PARSE_R1;
|
|
uint32 r2 = PARSE_R2;
|
|
if ( is_ld )
|
|
{
|
|
// In this instruction, general-purpose register reg2 is used as the source register, but, for
|
|
// mnemonic description convenience, the general - purpose register reg1 field is used in the
|
|
// opcode.The meanings of the register specifications in the mnemonic descriptions and
|
|
// opcode therefore differ from those of other instructions.
|
|
set_opreg(ins.Op1, regid);
|
|
set_opreg(ins.Op2, r2 + rSR0);
|
|
}
|
|
else
|
|
{
|
|
set_opreg(ins.Op1, regid + rSR0);
|
|
set_opreg(ins.Op2, r2);
|
|
}
|
|
if ( selid != 0 )
|
|
set_opimm(ins.Op3, selid);
|
|
}
|
|
break;
|
|
|
|
case 0x30:
|
|
case 0x50:
|
|
{
|
|
bool is_ld = subop == 0x30;
|
|
if ( is_ld )
|
|
{
|
|
ins.itype = NEC850_LDTC_SR;
|
|
set_opreg(ins.Op1, PARSE_R1);
|
|
set_opimm(ins.Op2, PARSE_R2);
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_STTC_SR;
|
|
set_opimm(ins.Op1, PARSE_R1);
|
|
set_opreg(ins.Op2, PARSE_R2);
|
|
}
|
|
uint32 selid = ( w & 0xF8000000 ) >> 27;
|
|
set_opimm(ins.Op3, selid);
|
|
}
|
|
break;
|
|
|
|
case 0x32:
|
|
case 0x52:
|
|
{
|
|
bool is_ld = subop == 0x32;
|
|
uint32 selid = ( w & 0xF8000000 ) >> 27;
|
|
switch ( selid )
|
|
{
|
|
case 0:
|
|
ins.itype = is_ld ? NEC850_LDTC_GR: NEC850_STTC_GR;
|
|
set_opreg(ins.Op2, PARSE_R2);
|
|
set_opreg(ins.Op1, PARSE_R1);
|
|
break;
|
|
case 1:
|
|
ins.itype = is_ld ? NEC850_LDTC_VR : NEC850_STTC_VR;
|
|
set_opreg(ins.Op1, is_ld ? PARSE_R2 : PARSE_R1);
|
|
set_opreg(ins.Op2, is_ld ? PARSE_R1 : PARSE_R2);
|
|
break;
|
|
case 31:
|
|
ins.itype = is_ld ? NEC850_LDTC_PC : NEC850_STTC_PC;
|
|
set_opreg(ins.Op1, is_ld ? PARSE_R1 : PARSE_R2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x34:
|
|
case 0x54:
|
|
{
|
|
bool is_ld = subop == 0x34;
|
|
if ( is_ld )
|
|
{
|
|
ins.itype = NEC850_LDVC_SR;
|
|
set_opreg(ins.Op1, PARSE_R1);
|
|
set_opimm(ins.Op2, PARSE_R2);
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_STVC_SR;
|
|
set_opimm(ins.Op1, PARSE_R1);
|
|
set_opreg(ins.Op2, PARSE_R2);
|
|
|
|
}
|
|
uint32 selid = ( w & 0xF8000000 ) >> 27;
|
|
set_opimm(ins.Op3, selid);
|
|
}
|
|
break;
|
|
|
|
case 0xC4:
|
|
case 0xC6:
|
|
{
|
|
// ROTL imm5, reg2, reg3
|
|
// rrrrr111111iiiii wwwww00011000100
|
|
// ROTL reg1, reg2, reg3
|
|
// rrrrr111111RRRRR wwwww00011000110
|
|
ins.itype = NEC850_ROTL;
|
|
uint32 r1 = PARSE_R1;
|
|
uint32 r2 = PARSE_R2;
|
|
uint32 r3 = (w & 0xF8000000 ) >> 27;
|
|
if ( subop == 0xC4 )
|
|
{
|
|
set_opimm(ins.Op1, r1);
|
|
}
|
|
else
|
|
{
|
|
set_opreg(ins.Op1, r1);
|
|
}
|
|
set_opreg(ins.Op2, r2);
|
|
set_opreg(ins.Op3, r3);
|
|
}
|
|
break;
|
|
|
|
case 0x110:
|
|
ins.itype = NEC850_HVTRAP;
|
|
set_opimm(ins.Op1, PARSE_R1, dt_byte);
|
|
break;
|
|
|
|
case 0x132:
|
|
ins.itype = NEC850_EST;
|
|
break;
|
|
|
|
case 0x134:
|
|
ins.itype = NEC850_DST;
|
|
break;
|
|
|
|
case 0x378:
|
|
{
|
|
// LDL.W [reg1], reg3
|
|
// 00000111111RRRRR wwwww01101111000
|
|
ins.itype = NEC850_LDL_W;
|
|
uint32 r3 = ( w & 0xF8000000 ) >> 27;
|
|
set_opreg(ins.Op1, PARSE_R1);
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS;
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
}
|
|
|
|
case 0x37A:
|
|
{
|
|
// STC.W reg3, [reg1]
|
|
// 00000111111RRRRR wwwww01101111010
|
|
ins.itype = NEC850_STC_W;
|
|
uint32 r3 = ( w & 0xF8000000 ) >> 27;
|
|
set_opreg(ins.Op1, r3);
|
|
set_opreg(ins.Op2, PARSE_R1);
|
|
ins.Op2.specflag1 = N850F_USEBRACKETS;
|
|
break;
|
|
}
|
|
case 0x160:
|
|
{
|
|
uint32 r1 = PARSE_R1;
|
|
uint32 r2 = PARSE_R2;
|
|
uint32 r3 = ( w & 0xF8000000 ) >> 27;
|
|
int w1 = w >> 16;
|
|
switch ( r2 )
|
|
{
|
|
case 8: // pushsp
|
|
case 0xB: // dbpush
|
|
case 0xC: // popsp
|
|
{
|
|
// PUSHSP rh-rt
|
|
// 01000111111RRRRR wwwww00101100000
|
|
// POPSP rh-rt
|
|
// 01100111111RRRRR wwwww00101100000
|
|
// RRRRR indicates rh. wwwww indicates rt.
|
|
ins.itype = r2 == 8 ? NEC850_PUSHSP
|
|
: r2 == 0xB ? NEC850_DBPUSH
|
|
: NEC850_POPSP;
|
|
ins.Op1.type = o_regrange;
|
|
ins.Op1.regrange_high = r1;
|
|
ins.Op1.regrange_low = r3;
|
|
}
|
|
break;
|
|
|
|
case 0x10:
|
|
switch ( w1 )
|
|
{
|
|
case 0x8960:
|
|
ins.itype = NEC850_TLBAI;
|
|
break;
|
|
case 0x8160:
|
|
ins.itype = NEC850_TLBVI;
|
|
break;
|
|
case 0xC160:
|
|
ins.itype = NEC850_TLBS;
|
|
break;
|
|
case 0xE960:
|
|
ins.itype = NEC850_TLBR;
|
|
break;
|
|
case 0xE160:
|
|
ins.itype = NEC850_TLBW;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0x18:
|
|
{
|
|
// JARL [reg1], reg3
|
|
// 11000111111RRRRR WWWWW00101100000
|
|
set_opreg(ins.Op1, r1);
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS;
|
|
set_opreg(ins.Op2, r3);
|
|
ins.itype = NEC850_JARL;
|
|
}
|
|
break;
|
|
|
|
case 0x19:
|
|
{
|
|
ins.itype = NEC850_DBTAG;
|
|
int v8 = (w & 0x1f) | ((w1 >> 6) & 0xe0);
|
|
set_opimm(ins.Op1, v8);
|
|
}
|
|
break;
|
|
|
|
case 0x1A:
|
|
{
|
|
ins.itype = NEC850_HVCALL;
|
|
int v8 = (w & 0x1f) | ((w1 >> 6) & 0xe0);
|
|
set_opimm(ins.Op1, v8);
|
|
}
|
|
break;
|
|
|
|
case 0x1B:
|
|
{
|
|
// PREF prefop, [reg1]
|
|
// 11011111111RRRRR PPPPP00101100000
|
|
// PPPPP indicates prefop
|
|
ins.itype = NEC850_PREF;
|
|
set_opimm(ins.Op1, r3);
|
|
set_opreg(ins.Op2, r1);
|
|
}
|
|
break;
|
|
|
|
case 0x1Cu:
|
|
case 0x1Du:
|
|
case 0x1Eu:
|
|
case 0x1Fu:
|
|
{
|
|
// CACHE cacheop, [reg1]
|
|
// 111pp111111RRRRR PPPPP00101100000
|
|
// ppPPPPP indicates cacheop
|
|
|
|
int cacheop = ( ( r2 & 3 ) << 5 ) | r3;
|
|
if ( r1 == 0x1f && cacheop == 0x7E )
|
|
{
|
|
ins.itype = NEC850_CLL;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_CACHE;
|
|
set_opimm(ins.Op1, cacheop);
|
|
set_opreg(ins.Op2, r1);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ( w == 0x1200FE0 )
|
|
ins.itype = NEC850_SNOOZE;
|
|
else if ( (w&0x10000) == 0 )
|
|
{
|
|
uint o0 = ( w >> 20 ) & 0x7F;
|
|
if ( o0 == 9 || o0 == 11 || o0 == 13 )
|
|
{
|
|
// BINS reg1, pos, width, reg2
|
|
|
|
// rrrrr111111RRRRR MMMMK 0001001 LLL0 msb >= 16, lsb >= 16
|
|
// rrrrr111111RRRRR MMMMK 0001011 LLL0 msb >= 16, lsb < 16
|
|
// rrrrr111111RRRRR MMMMK 0001101 LLL0 msb < 16, lsb < 16
|
|
// Most significant bit of field to be updated : msb = pos + width - 1
|
|
// Least significant bit of field to be updated : lsb = pos
|
|
// MMMM = lower 4 bits of msb, KLLL = lower 4 bits of lsb
|
|
uint16 whi = w >> 16;
|
|
uint lsb = ( whi >> 1 ) & 7;
|
|
lsb |= ( whi >> 8 ) & 8;
|
|
uint msb = ( whi >> 12 ) & 0xF;
|
|
if ( o0 == 9 || o0 == 11 )
|
|
msb += 16;
|
|
if ( o0 == 9 )
|
|
lsb += 16;
|
|
uint width = msb - lsb + 1;
|
|
|
|
ins.itype = NEC850_BINS;
|
|
set_opreg(ins.Op1, PARSE_R1);
|
|
set_opimm(ins.Op2, lsb);
|
|
set_opimm(ins.Op3, width);
|
|
set_opreg(ins.Op4, PARSE_R2);
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
if ( ins.itype != 0 )
|
|
break;
|
|
}
|
|
|
|
if ( ins.itype != 0 )
|
|
break;
|
|
}
|
|
if ( w == 0x14607E0 )
|
|
{
|
|
ins.itype = NEC850_DBRET;
|
|
break;
|
|
}
|
|
else if ( w == 0x14407E0 )
|
|
{
|
|
ins.itype = NEC850_CTRET;
|
|
break;
|
|
}
|
|
else if ( (w >> 16) & 0x1 )
|
|
{
|
|
int r2 = PARSE_R2;
|
|
int r1 = PARSE_R1;
|
|
if ( r2 != 0 )
|
|
{
|
|
// V850E: LD.HU disp16 [reg1], reg2
|
|
// rrrrr111111RRRRR ddddddddddddddd1
|
|
ins.itype = NEC850_LD_HU;
|
|
ins.Op1.type = o_displ;
|
|
displ_op = &ins.Op1;
|
|
ins.Op1.reg = r1;
|
|
ins.Op1.addr = uint32(( w >> 17 ) << 1);
|
|
ins.Op1.dtype = dt_word;
|
|
ins.Op1.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED;
|
|
set_opreg(ins.Op2, r2);
|
|
}
|
|
else if ( is_rh850() )
|
|
{
|
|
// RH850: Bcond disp17
|
|
// 00000111111DCCCC ddddddddddddddd1
|
|
sval_t dest = uint32(( w >> 17 ) << 1);
|
|
if ( (w & 0x10) != 0 )
|
|
dest += 0x10000; // D
|
|
SIGN_EXTEND(sval_t, dest, 17);
|
|
ins.itype = bcond_map[w & 0xF];
|
|
ins.Op1.dtype = dt_word;
|
|
ins.Op1.type = o_near;
|
|
ins.Op1.addr = ea_t(dest + ins.ip);
|
|
}
|
|
break;
|
|
}
|
|
//
|
|
// XI Group match (reg1, reg2, reg3)
|
|
//
|
|
uint32 r1 = PARSE_R1;
|
|
uint32 r2 = PARSE_R2;
|
|
uint32 r3 = ( w & 0xF8000000 ) >> 27;
|
|
|
|
op = (w & 0x7FF0000) >> 16;
|
|
if ( op == 0x220 )
|
|
ins.itype = NEC850_MUL;
|
|
else if ( op == 0x222 )
|
|
ins.itype = NEC850_MULU;
|
|
else if ( op == 0x280 )
|
|
ins.itype = NEC850_DIVH_r3;
|
|
else if ( op == 0x282 )
|
|
ins.itype = NEC850_DIVHU;
|
|
else if ( op == 0x2C0 )
|
|
ins.itype = NEC850_DIV;
|
|
else if ( op == 0x2C2 )
|
|
ins.itype = NEC850_DIVU;
|
|
else if ( is_v850e2() )
|
|
{
|
|
if ( ( op & 1 ) == 0 )
|
|
{
|
|
if ( ( op >> 5 ) == 0x1D )
|
|
{
|
|
// ADF
|
|
int cc = ( op >> 1 ) & 0xF;
|
|
if ( cc == CC_SAT )
|
|
{
|
|
ins.itype = NEC850_SATADD;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_ADF;
|
|
set_opcond(ins.Op1, cc);
|
|
set_opreg(ins.Op2, r1);
|
|
set_opreg(ins.Op3, r2);
|
|
set_opreg(ins.Op4, r3);
|
|
break;
|
|
}
|
|
}
|
|
else if ( ( op >> 5 ) == 0x1C )
|
|
{
|
|
// SBF
|
|
int cc = ( op >> 1 ) & 0xF;
|
|
if ( cc == CC_SAT )
|
|
{
|
|
ins.itype = NEC850_SATSUB;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_SBF;
|
|
set_opcond(ins.Op1, cc);
|
|
set_opreg(ins.Op2, r1);
|
|
set_opreg(ins.Op3, r2);
|
|
set_opreg(ins.Op4, r3);
|
|
break;
|
|
}
|
|
}
|
|
else if ( ( op >> 6 ) == 0xF )
|
|
{
|
|
// MAC rrrrr111111RRRRR wwww0011110mmmm0
|
|
// MACU rrrrr111111RRRRR wwww0011111mmmm0
|
|
ins.itype = ( op & 0x20 ) ? NEC850_MACU : NEC850_MAC;
|
|
int r4 = op&0x1F;
|
|
set_opreg(ins.Op1, r1);
|
|
set_opreg(ins.Op2, r2);
|
|
set_opreg(ins.Op3, r3);
|
|
set_opreg(ins.Op4, r4);
|
|
break;
|
|
}
|
|
}
|
|
switch ( op )
|
|
{
|
|
case 0x82:
|
|
ins.itype = NEC850_SHR;
|
|
break;
|
|
case 0xa2:
|
|
ins.itype = NEC850_SAR;
|
|
break;
|
|
case 0xc2:
|
|
ins.itype = NEC850_SHL;
|
|
break;
|
|
case 0xEE:
|
|
ins.itype = NEC850_CAXI;
|
|
ins.Op1.specflag1 |= N850F_USEBRACKETS;
|
|
break;
|
|
case 0x2FE:
|
|
ins.itype = NEC850_DIVQU;
|
|
break;
|
|
case 0x2FC:
|
|
ins.itype = NEC850_DIVQ;
|
|
break;
|
|
}
|
|
}
|
|
// process the match
|
|
if ( ins.itype != 0 )
|
|
{
|
|
set_opreg(ins.Op1, r1);
|
|
set_opreg(ins.Op2, r2);
|
|
set_opreg(ins.Op3, r3);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// XII/IX Group match (reg2, reg3)
|
|
//
|
|
if ( op == 0x340 )
|
|
ins.itype = NEC850_BSW;
|
|
else if ( op == 0x342 )
|
|
ins.itype = NEC850_BSH;
|
|
else if ( op == 0x344 )
|
|
ins.itype = NEC850_HSW;
|
|
else if ( is_v850e2() )
|
|
{
|
|
switch ( op )
|
|
{
|
|
case 0x346:
|
|
ins.itype = NEC850_HSH;
|
|
break;
|
|
case 0x360:
|
|
ins.itype = NEC850_SCH0R;
|
|
break;
|
|
case 0x362:
|
|
ins.itype = NEC850_SCH1R;
|
|
break;
|
|
case 0x364:
|
|
ins.itype = NEC850_SCH0L;
|
|
break;
|
|
case 0x366:
|
|
ins.itype = NEC850_SCH1L;
|
|
break;
|
|
}
|
|
}
|
|
// process the match
|
|
if ( ins.itype != 0 )
|
|
{
|
|
set_opreg(ins.Op1, r2);
|
|
set_opreg(ins.Op2, r3);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// match CMOV
|
|
//
|
|
op = w >> 16;
|
|
op = ((op & 0x7E0) >> 4) | (op & 0x1);
|
|
if ( op == 0x30 || op == 0x32 )
|
|
{
|
|
uint32 cc = (w & 0x1E0000) >> 17;
|
|
ins.itype = NEC850_CMOV;
|
|
set_opcond(ins.Op1, cc);
|
|
|
|
r1 = PARSE_R1;
|
|
r2 = PARSE_R2;
|
|
r3 = (w & 0xF8000000) >> 27;
|
|
|
|
if ( op == 0x32 ) // CMOV cc, reg1, reg2, reg3
|
|
{
|
|
set_opreg(ins.Op2, r1);
|
|
}
|
|
else
|
|
{
|
|
// CMOV cc, imm5, reg2, reg3
|
|
sval_t v = r1;
|
|
SIGN_EXTEND(sval_t, v, 5);
|
|
set_opimm(ins.Op2, v, dt_byte);
|
|
ins.Op2.specflag1 |= N850F_OUTSIGNED;
|
|
}
|
|
set_opreg(ins.Op3, r2);
|
|
set_opreg(ins.Op4, r3);
|
|
break;
|
|
}
|
|
//
|
|
// match MUL[U]_i9
|
|
//
|
|
op = w >> 16;
|
|
op = ((op & 0x7C0) >> 4) | (op & 0x3);
|
|
if ( op == 0x24 || op == 0x26 )
|
|
{
|
|
sval_t imm = (((w & 0x3C0000) >> 18) << 5) | (w & 0x1F);
|
|
if ( op == 0x24 )
|
|
{
|
|
ins.itype = NEC850_MUL;
|
|
SIGN_EXTEND(sval_t, imm, 9);
|
|
ins.Op1.specflag1 |= N850F_OUTSIGNED;
|
|
}
|
|
else
|
|
ins.itype = NEC850_MULU;
|
|
|
|
set_opimm(ins.Op1, imm);
|
|
set_opreg(ins.Op2, PARSE_R2);
|
|
set_opreg(ins.Op3, (w & 0xF8000000) >> 27);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Format IX
|
|
//
|
|
op = w >> 16; // take 2nd half-word as the opcode
|
|
uint32 reg1 = PARSE_R1;
|
|
uint32 reg2 = PARSE_R2;
|
|
// SETF
|
|
if ( op == 0 )
|
|
{
|
|
if ( ( w & 0x10 ) == 0 )
|
|
{
|
|
ins.itype = NEC850_SETF;
|
|
set_opcond(ins.Op1, w & 0xF);
|
|
set_opreg(ins.Op2, reg2);
|
|
}
|
|
else if ( is_v850e2m() )
|
|
{
|
|
ins.itype = NEC850_RIE;
|
|
uint imm5 = ( w >> 11 ) & 0x1F;
|
|
uint imm4 = w & 0xF;
|
|
set_opimm(ins.Op1, imm5);
|
|
set_opimm(ins.Op2, imm4);
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch ( op )
|
|
{
|
|
case 0x20: // LDSR
|
|
ins.itype = NEC850_LDSR;
|
|
ins.Op2.reg = rSR0; // designate system register
|
|
break;
|
|
case 0x40: // STSR
|
|
ins.itype = NEC850_STSR;
|
|
ins.Op1.reg = rSR0; // designate system register
|
|
break;
|
|
case 0x80: // SHR
|
|
ins.itype = NEC850_SHR;
|
|
break;
|
|
case 0xA0: // SAR
|
|
ins.itype = NEC850_SAR;
|
|
break;
|
|
case 0xC0: // SHL
|
|
ins.itype = NEC850_SHL;
|
|
break;
|
|
}
|
|
|
|
if ( ins.itype != 0 )
|
|
{
|
|
// Common stuff for the rest of Format 9 instructions
|
|
ins.Op1.dtype = ins.Op2.dtype = dt_dword;
|
|
ins.Op1.type = ins.Op2.type = o_reg;
|
|
ins.Op1.reg += reg1;
|
|
ins.Op2.reg += reg2;
|
|
break;
|
|
}
|
|
|
|
// -> ins.itype == 0
|
|
|
|
|
|
// No match? Try V850E
|
|
if ( is_v850e() )
|
|
{
|
|
// SASF
|
|
if ( op == 0x200 )
|
|
{
|
|
ins.itype = NEC850_SASF;
|
|
set_opcond(ins.Op1, w & 0xF);
|
|
set_opreg(ins.Op2, reg2);
|
|
break;
|
|
}
|
|
|
|
switch ( op )
|
|
{
|
|
case 0xE0: // NOT1
|
|
ins.itype = NEC850_SET1;
|
|
break;
|
|
case 0xE2: // NOT1
|
|
ins.itype = NEC850_NOT1;
|
|
break;
|
|
case 0xE4: // CLR1
|
|
ins.itype = NEC850_CLR1;
|
|
break;
|
|
case 0xE6: // TST1
|
|
ins.itype = NEC850_TST1;
|
|
break;
|
|
default:
|
|
return 0; // No match!
|
|
}
|
|
// Common
|
|
set_opreg(ins.Op1, reg2, dt_byte);
|
|
|
|
ins.Op2.dtype = dt_byte;
|
|
displ_op = &ins.Op2;
|
|
ins.Op2.type = o_displ;
|
|
ins.Op2.addr = 0;
|
|
ins.Op2.reg = reg1;
|
|
ins.Op2.specflag1 = N850F_USEBRACKETS;
|
|
}
|
|
|
|
if ( ins.itype == 0 )
|
|
return 0; // unknown instruction
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Format V
|
|
//
|
|
op = (w & 0x780) >> 6; // Take bit6->bit10
|
|
// JARL and JR
|
|
if ( op == 0x1E )
|
|
{
|
|
uint32 reg = PARSE_R2;
|
|
sval_t addr = uint32((((w & 0x3F) << 15) | ((w & 0xFFFE0000) >> 17)) << 1);
|
|
SIGN_EXTEND(sval_t, addr, 22);
|
|
|
|
ins.Op1.addr = ins.ip + addr;
|
|
ins.Op1.type = o_near;
|
|
// per the docs, if reg is zero then JARL turns to JR
|
|
if ( reg == 0 )
|
|
{
|
|
ins.itype = NEC850_JR;
|
|
}
|
|
else
|
|
{
|
|
ins.itype = NEC850_JARL;
|
|
set_opreg(ins.Op2, reg);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Format III
|
|
//
|
|
op = (w & 0x780) >> 7; // Take bit7->bit10
|
|
// assert: op in [0, 0xF]
|
|
// Bcond disp9
|
|
if ( op == 0xB )
|
|
{
|
|
sval_t dest = ( ((w & 0x70) >> 4) | ((w & 0xF800) >> 8) ) << 1;
|
|
SIGN_EXTEND(sval_t, dest, 9);
|
|
|
|
ins.itype = bcond_map[w & 0xF];
|
|
ins.Op1.dtype = dt_word;
|
|
ins.Op1.type = o_near;
|
|
ins.Op1.addr = ea_t(dest + ins.ip);
|
|
break;
|
|
}
|
|
//
|
|
// Format IV
|
|
//
|
|
else if ( op >= 6 )
|
|
{
|
|
uint32 reg2 = PARSE_R2;
|
|
uint32 addr = (w & 0x7F); // zero extended
|
|
int idx_d(-1), idx_r(-1);
|
|
char dtyp_d(-1);
|
|
|
|
// SLD.B
|
|
if ( op == 6 )
|
|
{
|
|
ins.itype = NEC850_SLD_B;
|
|
idx_d = 0;
|
|
idx_r = 1;
|
|
dtyp_d = dt_byte;
|
|
}
|
|
// SLD.H
|
|
else if ( op == 8 )
|
|
{
|
|
ins.itype = NEC850_SLD_H;
|
|
idx_d = 0;
|
|
idx_r = 1;
|
|
dtyp_d = dt_word;
|
|
addr <<= 1;
|
|
}
|
|
// SLD.W
|
|
else if ( op == 10 && ((w & 1) == 0) )
|
|
{
|
|
ins.itype = NEC850_SLD_W;
|
|
idx_d = 0;
|
|
idx_r = 1;
|
|
dtyp_d = dt_dword;
|
|
addr <<= 1;
|
|
}
|
|
// SST.B
|
|
else if ( op == 7 )
|
|
{
|
|
ins.itype = NEC850_SST_B;
|
|
idx_d = 1;
|
|
idx_r = 0;
|
|
dtyp_d = dt_byte;
|
|
}
|
|
// SST.H
|
|
else if ( op == 9 )
|
|
{
|
|
ins.itype = NEC850_SST_H;
|
|
idx_d = 1;
|
|
idx_r = 0;
|
|
dtyp_d = dt_byte;
|
|
// bit0 is already cleared, so the 7bit addr we read
|
|
// can be shifted by one to transform it to 8bit
|
|
addr <<= 1;
|
|
}
|
|
// SST.W
|
|
else if ( op == 10 && ((w & 1) == 1) )
|
|
{
|
|
ins.itype = NEC850_SST_W;
|
|
idx_d = 1;
|
|
idx_r = 0;
|
|
dtyp_d = dt_dword;
|
|
// clear lower bit because it is set, and shift by one
|
|
// bit 15 0
|
|
// rrrrr1010dddddd1
|
|
addr = (addr & ~1) << 1;
|
|
}
|
|
if ( idx_d == -1 || idx_r == -1 || dtyp_d == -1 )
|
|
return false; // could not decode
|
|
|
|
set_opreg(ins.ops[idx_r], reg2);
|
|
|
|
ins.ops[idx_d].type = o_displ;
|
|
displ_op = &ins.ops[idx_d];
|
|
ins.ops[idx_d].reg = rEP;
|
|
ins.ops[idx_d].addr = addr;
|
|
ins.ops[idx_d].dtype = dtyp_d;
|
|
ins.ops[idx_d].specflag1 = N850F_USEBRACKETS;
|
|
break;
|
|
}
|
|
// Unknown instructions
|
|
ins.itype = NEC850_NULL;
|
|
} while ( false );
|
|
|
|
// special cases when we have memory access through displacement
|
|
if ( displ_op != NULL )
|
|
{
|
|
// A displacement with GP and GP is set?
|
|
if ( displ_op->reg == rGP && g_gp_ea != BADADDR )
|
|
{
|
|
displ_op->type = o_mem;
|
|
if ( ins.itype == NEC850_SLD_BU || ins.itype == NEC850_LD_BU
|
|
|| ins.itype == NEC850_SLD_HU || ins.itype == NEC850_LD_HU )
|
|
{
|
|
displ_op->addr = short(displ_op->addr) + g_gp_ea;
|
|
}
|
|
else
|
|
{
|
|
displ_op->addr += g_gp_ea;
|
|
}
|
|
}
|
|
// register zero access?
|
|
else if ( displ_op->reg == rZERO )
|
|
{
|
|
// since r0 is always 0, we can replace the operand by the complete address
|
|
displ_op->type = o_mem;
|
|
displ_op->specflag1 &= ~N850F_OUTSIGNED;
|
|
if ( ins.itype == NEC850_LD_BU || ins.itype == NEC850_LD_HU )
|
|
displ_op->addr = short(displ_op->addr);
|
|
}
|
|
#ifdef __EA64__
|
|
if ( displ_op->type == o_mem )
|
|
{
|
|
// truncate address to 32 bits if needed
|
|
segment_t *s = getseg(displ_op->addr);
|
|
if ( s == NULL || !s->is_64bit() )
|
|
displ_op->addr = uint32(displ_op->addr);
|
|
}
|
|
#endif
|
|
}
|
|
return ins.itype != 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Analyze one instruction and fill 'insn' structure.
|
|
// insn.ea contains address of instruction to analyze.
|
|
// Return length of the instruction in bytes, 0 if instruction can't be decoded.
|
|
// This function shouldn't change the database, flags or anything else.
|
|
// All these actions should be performed only by u_emu() function.
|
|
int nec850_t::nec850_ana(insn_t *pinsn)
|
|
{
|
|
insn_t &insn = *pinsn;
|
|
if ( insn.ea & 0x1 )
|
|
return 0;
|
|
|
|
uint32 w;
|
|
fetch_instruction(&w, insn);
|
|
if ( decode_instruction(w, insn) )
|
|
return insn.size;
|
|
else
|
|
return 0;
|
|
}
|