741 lines
24 KiB
C++
741 lines
24 KiB
C++
/*
|
|
* Interactive disassembler (IDA).
|
|
* Copyright (c) 1990-2001 by Ilfak Guilfanov.
|
|
* ALL RIGHTS RESERVED.
|
|
* E-mail: ig@datarescue.com
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include "i960.hpp"
|
|
|
|
struct sparse_tabent_t
|
|
{
|
|
ushort code;
|
|
ushort itype;
|
|
char opnum;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void opimm(op_t &x, uval_t value, char dtype)
|
|
{
|
|
x.type = o_imm;
|
|
x.dtype = dtype;
|
|
x.value = value;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void opreg(op_t &x, int reg)
|
|
{
|
|
x.type = o_reg;
|
|
x.dtype = dt_dword;
|
|
x.reg = (uchar)reg;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void opmem(op_t &x, uval_t addr, char dtype)
|
|
{
|
|
x.type = o_mem;
|
|
x.dtype = dtype;
|
|
x.addr = addr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void opdsp(op_t &x, int base, int idx, int scale, uval_t disp, char dtype)
|
|
{
|
|
x.type = o_displ;
|
|
x.dtype = dtype;
|
|
x.addr = disp;
|
|
x.reg = (uint16)base;
|
|
x.index = (uchar)idx;
|
|
x.scale = (uchar)scale;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void opphr(op_t &x, int base, int idx, int scale, char dtype)
|
|
{
|
|
x.type = o_phrase;
|
|
x.dtype = dtype;
|
|
x.reg = (uint16)base;
|
|
x.index = (uchar)idx;
|
|
x.scale = (uchar)scale;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void opnear(op_t &x, uval_t addr)
|
|
{
|
|
x.type = o_near;
|
|
x.dtype = dt_code;
|
|
x.addr = addr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool i960_t::ctrl(insn_t &insn, uint32 code)
|
|
{
|
|
static const ushort itypes[] =
|
|
{
|
|
I960_null, /* 0x00 */
|
|
I960_null, /* 0x01 */
|
|
I960_null, /* 0x02 */
|
|
I960_null, /* 0x03 */
|
|
I960_null, /* 0x04 */
|
|
I960_null, /* 0x05 */
|
|
I960_null, /* 0x06 */
|
|
I960_null, /* 0x07 */
|
|
I960_b, /* 0x08 */
|
|
I960_call, /* 0x09 */
|
|
I960_ret, /* 0x0a */
|
|
I960_bal, /* 0x0b */
|
|
I960_null, /* 0x0c */
|
|
I960_null, /* 0x0d */
|
|
I960_null, /* 0x0e */
|
|
I960_null, /* 0x0f */
|
|
I960_bno, /* 0x10 */
|
|
I960_bg, /* 0x11 */
|
|
I960_be, /* 0x12 */
|
|
I960_bge, /* 0x13 */
|
|
I960_bl, /* 0x14 */
|
|
I960_bne, /* 0x15 */
|
|
I960_ble, /* 0x16 */
|
|
I960_bo, /* 0x17 */
|
|
I960_faultno, /* 0x18 */
|
|
I960_faultg, /* 0x19 */
|
|
I960_faulte, /* 0x1a */
|
|
I960_faultge, /* 0x1b */
|
|
I960_faultl, /* 0x1c */
|
|
I960_faultne, /* 0x1d */
|
|
I960_faultle, /* 0x1e */
|
|
I960_faulto, /* 0x1f */
|
|
};
|
|
int opcode = code >> 24;
|
|
if ( opcode >= qnumber(itypes) )
|
|
return false;
|
|
if ( is_strict() && (code & 1) != 0 )
|
|
return false;
|
|
insn.itype = itypes[opcode];
|
|
if ( opcode >= 0x10 ) // .t or .f are allowed
|
|
{
|
|
insn.auxpref |= (code & 2) ? aux_f : aux_t;
|
|
}
|
|
// has operand?
|
|
if ( Instructions[insn.itype].feature & CF_USE1 )
|
|
{
|
|
sval_t disp = code & 0xFFFFFC;
|
|
if ( disp & 0x800000 )
|
|
disp |= ~uval_t(0xFFFFFF); // sign extend
|
|
opnear(insn.Op1, insn.ip+disp);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static bool cobr(insn_t &insn, uint32 code)
|
|
{
|
|
static const ushort itypes[] =
|
|
{
|
|
I960_testno, /* 0x20 */
|
|
I960_testg, /* 0x21 */
|
|
I960_teste, /* 0x22 */
|
|
I960_testge, /* 0x23 */
|
|
I960_testl, /* 0x24 */
|
|
I960_testne, /* 0x25 */
|
|
I960_testle, /* 0x26 */
|
|
I960_testo, /* 0x27 */
|
|
I960_null, /* 0x28 */
|
|
I960_null, /* 0x29 */
|
|
I960_null, /* 0x2a */
|
|
I960_null, /* 0x2b */
|
|
I960_null, /* 0x2c */
|
|
I960_null, /* 0x2d */
|
|
I960_null, /* 0x2e */
|
|
I960_null, /* 0x2f */
|
|
I960_bbc, /* 0x30 */
|
|
I960_cmpobg, /* 0x31 */
|
|
I960_cmpobe, /* 0x32 */
|
|
I960_cmpobge, /* 0x33 */
|
|
I960_cmpobl, /* 0x34 */
|
|
I960_cmpobne, /* 0x35 */
|
|
I960_cmpoble, /* 0x36 */
|
|
I960_bbs, /* 0x37 */
|
|
I960_cmpibno, /* 0x38 */
|
|
I960_cmpibg, /* 0x39 */
|
|
I960_cmpibe, /* 0x3a */
|
|
I960_cmpibge, /* 0x3b */
|
|
I960_cmpibl, /* 0x3c */
|
|
I960_cmpibne, /* 0x3d */
|
|
I960_cmpible, /* 0x3e */
|
|
I960_cmpibo, /* 0x3f */
|
|
};
|
|
uint32 opcode = (code >> 24) - 0x20;
|
|
if ( opcode >= qnumber(itypes) )
|
|
return false;
|
|
insn.itype = itypes[opcode];
|
|
insn.auxpref |= (code & 2) ? aux_f : aux_t;
|
|
|
|
int src1 = (code >> 19) & 0x1F;
|
|
int src2 = (code >> 14) & 0x1F;
|
|
|
|
// operand 1
|
|
if ( code & 0x2000 ) // M1
|
|
{
|
|
opimm(insn.Op1, src1, dt_byte);
|
|
if ( opcode < 8 )
|
|
return false; // test instructions can't have imm
|
|
}
|
|
else
|
|
{
|
|
opreg(insn.Op1, src1);
|
|
}
|
|
|
|
if ( Instructions[insn.itype].feature & (CF_USE2|CF_CHG2) )
|
|
{
|
|
// instruction has at least 3 operands
|
|
if ( code & 1 )
|
|
src2 += SF0; // S2
|
|
opreg(insn.Op2, src2);
|
|
sval_t disp = code & 0x1FFC;
|
|
if ( disp & 0x1000 )
|
|
disp |= ~uval_t(0x1FFF); // sign extend
|
|
opnear(insn.Op3, insn.ip+disp);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool i960_t::opmemory(insn_t &insn, op_t &x, uint32 code, char dtype)
|
|
{
|
|
int reg2 = (code >> 14) & 0x1F;
|
|
int mode = (code >> 10) & 0xF;
|
|
if ( mode & 4 ) /* MEMB FORMAT */
|
|
{
|
|
unsigned scale = (code >> 7) & 0x07;
|
|
if ( (scale > 4) )
|
|
return false;
|
|
bool badscale = ((code >> 5) & 0x03) != 0;
|
|
static const int scale_tab[] = { 1, 2, 4, 8, 16 };
|
|
scale = scale_tab[scale];
|
|
|
|
int reg3 = code & 0x1F;
|
|
uval_t disp;
|
|
switch ( mode )
|
|
{
|
|
case 4: /* (reg) */
|
|
opphr(x, reg2, -1, 1, dtype);
|
|
break;
|
|
case 5: /* displ+8(ip) */
|
|
x.offb = (uchar)insn.size;
|
|
disp = insn.get_next_dword();
|
|
opdsp(x, IP, -1, 1, disp, dtype);
|
|
// opmem(x, insn.ip+8+disp, dtype);
|
|
// insn.auxpref |= aux_ip;
|
|
break;
|
|
case 7: /* (reg)[index*scale] */
|
|
if ( is_strict() && badscale )
|
|
return false;
|
|
opphr(x, reg2, reg3, scale, dtype);
|
|
break;
|
|
case 12: /* displacement */
|
|
x.offb = (uchar)insn.size;
|
|
disp = insn.get_next_dword();
|
|
opmem(x, disp, dtype);
|
|
break;
|
|
case 13: /* displ(reg) */
|
|
x.offb = (uchar)insn.size;
|
|
disp = insn.get_next_dword();
|
|
opdsp(x, reg2, -1, 1, disp, dtype);
|
|
break;
|
|
case 14: /* displ[index*scale] */
|
|
if ( is_strict() && badscale )
|
|
return false;
|
|
x.offb = (uchar)insn.size;
|
|
disp = insn.get_next_dword();
|
|
opdsp(x, -1, reg3, scale, disp, dtype);
|
|
break;
|
|
case 15: /* displ(reg)[index*scale] */
|
|
if ( is_strict() && badscale )
|
|
return false;
|
|
x.offb = (uchar)insn.size;
|
|
disp = insn.get_next_dword();
|
|
opdsp(x, reg2, reg3, scale, disp, dtype);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
else /* MEMA FORMAT */
|
|
{
|
|
int offset = code & 0xFFF;
|
|
if ( mode & 8 )
|
|
opdsp(x, reg2, -1, 1, offset, dtype);
|
|
else
|
|
opmem(x, offset, dtype);
|
|
}
|
|
if ( x.type == o_mem && dtype == dt_code )
|
|
x.type = o_near;
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool i960_t::mem(insn_t &insn, uint32 code)
|
|
{
|
|
static const tabent_t itypes[] =
|
|
{
|
|
{ /* 0x80 */ I960_ldob, 2, dt_byte },
|
|
{ /* 0x81 */ I960_null, 0, 0 },
|
|
{ /* 0x82 */ I960_stob, -2, dt_byte },
|
|
{ /* 0x83 */ I960_null, 0, 0 },
|
|
{ /* 0x84 */ I960_bx, 1, dt_code },
|
|
{ /* 0x85 */ I960_balx, 2, dt_code },
|
|
{ /* 0x86 */ I960_callx, 1, dt_code },
|
|
{ /* 0x87 */ I960_null, 0, 0 },
|
|
{ /* 0x88 */ I960_ldos, 2, dt_word },
|
|
{ /* 0x89 */ I960_null, 0, 0 },
|
|
{ /* 0x8a */ I960_stos, -2, dt_word },
|
|
{ /* 0x8b */ I960_null, 0, 0 },
|
|
{ /* 0x8c */ I960_lda, 2, dt_byte },
|
|
{ /* 0x8d */ I960_null, 0, 0 },
|
|
{ /* 0x8e */ I960_null, 0, 0 },
|
|
{ /* 0x8f */ I960_null, 0, 0 },
|
|
{ /* 0x90 */ I960_ld, 2, dt_dword },
|
|
{ /* 0x91 */ I960_null, 0, 0 },
|
|
{ /* 0x92 */ I960_st, -2, dt_dword },
|
|
{ /* 0x93 */ I960_null, 0, 0 },
|
|
{ /* 0x94 */ I960_null, 0, 0 },
|
|
{ /* 0x95 */ I960_null, 0, 0 },
|
|
{ /* 0x96 */ I960_null, 0, 0 },
|
|
{ /* 0x97 */ I960_null, 0, 0 },
|
|
{ /* 0x98 */ I960_ldl, 2, dt_qword },
|
|
{ /* 0x99 */ I960_null, 0, 0 },
|
|
{ /* 0x9a */ I960_stl, -2, dt_qword },
|
|
{ /* 0x9b */ I960_null, 0, 0 },
|
|
{ /* 0x9c */ I960_null, 0, 0 },
|
|
{ /* 0x9d */ I960_null, 0, 0 },
|
|
{ /* 0x9e */ I960_null, 0, 0 },
|
|
{ /* 0x9f */ I960_null, 0, 0 },
|
|
{ /* 0xa0 */ I960_ldt, 2, dt_fword },
|
|
{ /* 0xa1 */ I960_null, 0, 0 },
|
|
{ /* 0xa2 */ I960_stt, -2, dt_fword },
|
|
{ /* 0xa3 */ I960_null, 0, 0 },
|
|
{ /* 0xa4 */ I960_null, 0, 0 },
|
|
{ /* 0xa5 */ I960_null, 0, 0 },
|
|
{ /* 0xa6 */ I960_null, 0, 0 },
|
|
{ /* 0xa7 */ I960_null, 0, 0 },
|
|
{ /* 0xa8 */ I960_null, 0, 0 },
|
|
{ /* 0xa9 */ I960_null, 0, 0 },
|
|
{ /* 0xaa */ I960_null, 0, 0 },
|
|
{ /* 0xab */ I960_null, 0, 0 },
|
|
{ /* 0xac */ I960_dcinva, 1, dt_byte },
|
|
{ /* 0xad */ I960_null, 0, 0 },
|
|
{ /* 0xae */ I960_null, 0, 0 },
|
|
{ /* 0xaf */ I960_null, 0, 0 },
|
|
{ /* 0xb0 */ I960_ldq, 2, dt_byte16 },
|
|
{ /* 0xb1 */ I960_null, 0, 0 },
|
|
{ /* 0xb2 */ I960_stq, -2, dt_byte16 },
|
|
{ /* 0xb3 */ I960_null, 0, 0 },
|
|
{ /* 0xb4 */ I960_null, 0, 0 },
|
|
{ /* 0xb5 */ I960_null, 0, 0 },
|
|
{ /* 0xb6 */ I960_null, 0, 0 },
|
|
{ /* 0xb7 */ I960_null, 0, 0 },
|
|
{ /* 0xb8 */ I960_null, 0, 0 },
|
|
{ /* 0xb9 */ I960_null, 0, 0 },
|
|
{ /* 0xba */ I960_null, 0, 0 },
|
|
{ /* 0xbb */ I960_null, 0, 0 },
|
|
{ /* 0xbc */ I960_null, 0, 0 },
|
|
{ /* 0xbd */ I960_null, 0, 0 },
|
|
{ /* 0xbe */ I960_null, 0, 0 },
|
|
{ /* 0xbf */ I960_null, 0, 0 },
|
|
{ /* 0xc0 */ I960_ldib, 2, dt_byte },
|
|
{ /* 0xc1 */ I960_null, 0, 0 },
|
|
{ /* 0xc2 */ I960_stib, -2, dt_byte },
|
|
{ /* 0xc3 */ I960_null, 0, 0 },
|
|
{ /* 0xc4 */ I960_null, 0, 0 },
|
|
{ /* 0xc5 */ I960_null, 0, 0 },
|
|
{ /* 0xc6 */ I960_null, 0, 0 },
|
|
{ /* 0xc7 */ I960_null, 0, 0 },
|
|
{ /* 0xc8 */ I960_ldis, 2, dt_word },
|
|
{ /* 0xc9 */ I960_null, 0, 0 },
|
|
{ /* 0xca */ I960_stis, -2, dt_word },
|
|
};
|
|
|
|
uint32 opcode = (code >> 24) - 0x80;
|
|
if ( opcode >= qnumber(itypes) )
|
|
return false;
|
|
insn.itype = itypes[opcode].itype;
|
|
|
|
int reg1 = (code >> 19) & 0x1F;
|
|
switch ( itypes[opcode].opnum )
|
|
{
|
|
case -2: /* STORE INSTRUCTION */
|
|
opreg(insn.Op1, reg1);
|
|
if ( !opmemory(insn, insn.Op2, code, itypes[opcode].dtype) )
|
|
return false;
|
|
break;
|
|
|
|
case 2: /* LOAD INSTRUCTION */
|
|
opreg(insn.Op2, reg1);
|
|
// no break
|
|
|
|
case 1: /* BX/CALLX INSTRUCTION */
|
|
if ( !opmemory(insn, insn.Op1, code, itypes[opcode].dtype) )
|
|
return false;
|
|
break;
|
|
}
|
|
if ( insn.itype == I960_lda && insn.Op1.type == o_mem )
|
|
opimm(insn.Op1, insn.Op1.addr, dt_dword);
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static void regop(op_t &x, bool mode, bool spec, int reg, bool fp)
|
|
{
|
|
if ( fp ) /* FLOATING POINT INSTRUCTION */
|
|
{
|
|
if ( mode ) /* FP operand */
|
|
{
|
|
switch ( reg )
|
|
{
|
|
case 0:
|
|
opreg(x, FP0);
|
|
break;
|
|
case 1:
|
|
opreg(x, FP1);
|
|
break;
|
|
case 2:
|
|
opreg(x, FP2);
|
|
break;
|
|
case 3:
|
|
opreg(x, FP3);
|
|
break;
|
|
/* case 16: "0f0.0"
|
|
break;
|
|
case 22: "0f1.0"
|
|
break;
|
|
default: "?"
|
|
break;*/
|
|
}
|
|
}
|
|
else
|
|
{ /* Non-FP register */
|
|
opreg(x, reg);
|
|
}
|
|
}
|
|
else
|
|
{ /* NOT FLOATING POINT */
|
|
if ( mode ) /* Literal */
|
|
{
|
|
opimm(x, reg, dt_dword);
|
|
}
|
|
else
|
|
{ /* Register */
|
|
if ( spec )
|
|
reg += SF0;
|
|
opreg(x, reg);
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Register Instruction Destination Operand
|
|
static void dstop(op_t &x, bool mode, int reg, bool fp)
|
|
{
|
|
// 'dst' operand can't be a literal. On non-FP instructions, register
|
|
// mode is assumed and "m3" acts as if were "s3"; on FP-instructions,
|
|
// sf registers are not allowed so m3 acts normally.
|
|
if ( fp )
|
|
regop(x, mode, false, reg, fp);
|
|
else
|
|
regop(x, false, mode, reg, fp);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool i960_t::reg(insn_t &insn, uint32 code)
|
|
{
|
|
static const sparse_tabent_t reg_init[] =
|
|
{
|
|
{ 0x580, I960_notbit, 3 },
|
|
{ 0x581, I960_and, 3 },
|
|
{ 0x582, I960_andnot, 3 },
|
|
{ 0x583, I960_setbit, 3 },
|
|
{ 0x584, I960_notand, 3 },
|
|
{ 0x586, I960_xor, 3 },
|
|
{ 0x587, I960_or, 3 },
|
|
{ 0x588, I960_nor, 3 },
|
|
{ 0x589, I960_xnor, 3 },
|
|
{ 0x58a, I960_not, -2 },
|
|
{ 0x58b, I960_ornot, 3 },
|
|
{ 0x58c, I960_clrbit, 3 },
|
|
{ 0x58d, I960_notor, 3 },
|
|
{ 0x58e, I960_nand, 3 },
|
|
{ 0x58f, I960_alterbit, 3 },
|
|
{ 0x590, I960_addo, 3 },
|
|
{ 0x591, I960_addi, 3 },
|
|
{ 0x592, I960_subo, 3 },
|
|
{ 0x593, I960_subi, 3 },
|
|
{ 0x594, I960_cmpob, 2 },
|
|
{ 0x595, I960_cmpib, 2 },
|
|
{ 0x596, I960_cmpos, 2 },
|
|
{ 0x597, I960_cmpis, 2 },
|
|
{ 0x598, I960_shro, 3 },
|
|
{ 0x59a, I960_shrdi, 3 },
|
|
{ 0x59b, I960_shri, 3 },
|
|
{ 0x59c, I960_shlo, 3 },
|
|
{ 0x59d, I960_rotate, 3 },
|
|
{ 0x59e, I960_shli, 3 },
|
|
{ 0x5a0, I960_cmpo, 2 },
|
|
{ 0x5a1, I960_cmpi, 2 },
|
|
{ 0x5a2, I960_concmpo, 2 },
|
|
{ 0x5a3, I960_concmpi, 2 },
|
|
{ 0x5a4, I960_cmpinco, 3 },
|
|
{ 0x5a5, I960_cmpinci, 3 },
|
|
{ 0x5a6, I960_cmpdeco, 3 },
|
|
{ 0x5a7, I960_cmpdeci, 3 },
|
|
{ 0x5ac, I960_scanbyte, 2 },
|
|
{ 0x5ad, I960_bswap, -2 },
|
|
{ 0x5ae, I960_chkbit, 2 },
|
|
{ 0x5b0, I960_addc, 3 },
|
|
{ 0x5b2, I960_subc, 3 },
|
|
{ 0x5b4, I960_intdis, 0 },
|
|
{ 0x5b5, I960_inten, 0 },
|
|
{ 0x5cc, I960_mov, -2 },
|
|
{ 0x5d8, I960_eshro, 3 },
|
|
{ 0x5dc, I960_movl, -2 },
|
|
{ 0x5ec, I960_movt, -2 },
|
|
{ 0x5fc, I960_movq, -2 },
|
|
{ 0x600, I960_synmov, 2 },
|
|
{ 0x601, I960_synmovl, 2 },
|
|
{ 0x602, I960_synmovq, 2 },
|
|
{ 0x603, I960_cmpstr, 3 },
|
|
{ 0x604, I960_movqstr, 3 },
|
|
{ 0x605, I960_movstr, 3 },
|
|
{ 0x610, I960_atmod, 3 },
|
|
{ 0x612, I960_atadd, 3 },
|
|
{ 0x613, I960_inspacc, -2 },
|
|
{ 0x614, I960_ldphy, -2 },
|
|
{ 0x615, I960_synld, -2 },
|
|
{ 0x617, I960_fill, 3 },
|
|
{ 0x630, I960_sdma, 3 },
|
|
{ 0x631, I960_udma, 0 },
|
|
{ 0x640, I960_spanbit, -2 },
|
|
{ 0x641, I960_scanbit, -2 },
|
|
{ 0x642, I960_daddc, 3 },
|
|
{ 0x643, I960_dsubc, 3 },
|
|
{ 0x644, I960_dmovt, -2 },
|
|
{ 0x645, I960_modac, 3 },
|
|
{ 0x646, I960_condrec, -2 },
|
|
{ 0x650, I960_modify, 3 },
|
|
{ 0x651, I960_extract, 3 },
|
|
{ 0x654, I960_modtc, 3 },
|
|
{ 0x655, I960_modpc, 3 },
|
|
{ 0x656, I960_receive, -2 },
|
|
{ 0x658, I960_intctl, -2 },
|
|
{ 0x659, I960_sysctl, 3 },
|
|
{ 0x65b, I960_icctl, 3 },
|
|
{ 0x65c, I960_dcctl, 3 },
|
|
{ 0x65d, I960_halt, 1 },
|
|
{ 0x660, I960_calls, 1 },
|
|
{ 0x662, I960_send, 3 },
|
|
{ 0x663, I960_sendserv, 1 },
|
|
{ 0x664, I960_resumprcs, 1 },
|
|
{ 0x665, I960_schedprcs, 1 },
|
|
{ 0x666, I960_saveprcs, 0 },
|
|
{ 0x668, I960_condwait, 1 },
|
|
{ 0x669, I960_wait, 1 },
|
|
{ 0x66a, I960_signal, 1 },
|
|
{ 0x66b, I960_mark, 0 },
|
|
{ 0x66c, I960_fmark, 0 },
|
|
{ 0x66d, I960_flushreg, 0 },
|
|
{ 0x66f, I960_syncf, 0 },
|
|
{ 0x670, I960_emul, 3 },
|
|
{ 0x671, I960_ediv, 3 },
|
|
{ 0x673, I960_ldtime, -1 },
|
|
{ 0x674, I960_fcvtir, -2 },
|
|
{ 0x675, I960_fcvtilr, -2 },
|
|
{ 0x676, I960_fscalerl, 3 },
|
|
{ 0x677, I960_fscaler, 3 },
|
|
{ 0x680, I960_fatanr, 3 },
|
|
{ 0x681, I960_flogepr, 3 },
|
|
{ 0x682, I960_flogr, 3 },
|
|
{ 0x683, I960_fremr, 3 },
|
|
{ 0x684, I960_fcmpor, 2 },
|
|
{ 0x685, I960_fcmpr, 2 },
|
|
{ 0x688, I960_fsqrtr, -2 },
|
|
{ 0x689, I960_fexpr, -2 },
|
|
{ 0x68a, I960_flogbnr, -2 },
|
|
{ 0x68b, I960_froundr, -2 },
|
|
{ 0x68c, I960_fsinr, -2 },
|
|
{ 0x68d, I960_fcosr, -2 },
|
|
{ 0x68e, I960_ftanr, -2 },
|
|
{ 0x68f, I960_fclassr, 1 },
|
|
{ 0x690, I960_fatanrl, 3 },
|
|
{ 0x691, I960_flogeprl, 3 },
|
|
{ 0x692, I960_flogrl, 3 },
|
|
{ 0x693, I960_fremrl, 3 },
|
|
{ 0x694, I960_fcmporl, 2 },
|
|
{ 0x695, I960_fcmprl, 2 },
|
|
{ 0x698, I960_fsqrtrl, -2 },
|
|
{ 0x699, I960_fexprl, -2 },
|
|
{ 0x69a, I960_flogbnrl, -2 },
|
|
{ 0x69b, I960_froundrl, -2 },
|
|
{ 0x69c, I960_fsinrl, -2 },
|
|
{ 0x69d, I960_fcosrl, -2 },
|
|
{ 0x69e, I960_ftanrl, -2 },
|
|
{ 0x69f, I960_fclassrl, 1 },
|
|
{ 0x6c0, I960_fcvtri, -2 },
|
|
{ 0x6c1, I960_fcvtril, -2 },
|
|
{ 0x6c2, I960_fcvtzri, -2 },
|
|
{ 0x6c3, I960_fcvtzril, -2 },
|
|
{ 0x6c9, I960_fmovr, -2 },
|
|
{ 0x6d9, I960_fmovrl, -2 },
|
|
{ 0x6e1, I960_fmovre, -2 },
|
|
{ 0x6e2, I960_fcpysre, 3 },
|
|
{ 0x6e3, I960_fcpyrsre, 3 },
|
|
{ 0x701, I960_mulo, 3 },
|
|
{ 0x708, I960_remo, 3 },
|
|
{ 0x70b, I960_divo, 3 },
|
|
{ 0x741, I960_muli, 3 },
|
|
{ 0x748, I960_remi, 3 },
|
|
{ 0x749, I960_modi, 3 },
|
|
{ 0x74b, I960_divi, 3 },
|
|
{ 0x780, I960_addono, 3 },
|
|
{ 0x781, I960_addino, 3 },
|
|
{ 0x782, I960_subono, 3 },
|
|
{ 0x783, I960_subino, 3 },
|
|
{ 0x784, I960_selno, 3 },
|
|
{ 0x78b, I960_fdivr, 3 },
|
|
{ 0x78c, I960_fmulr, 3 },
|
|
{ 0x78d, I960_fsubr, 3 },
|
|
{ 0x78f, I960_faddr, 3 },
|
|
{ 0x790, I960_addog, 3 },
|
|
{ 0x791, I960_addig, 3 },
|
|
{ 0x792, I960_subog, 3 },
|
|
{ 0x793, I960_subig, 3 },
|
|
{ 0x794, I960_selg, 3 },
|
|
{ 0x79b, I960_fdivrl, 3 },
|
|
{ 0x79c, I960_fmulrl, 3 },
|
|
{ 0x79d, I960_fsubrl, 3 },
|
|
{ 0x79f, I960_faddrl, 3 },
|
|
{ 0x7a0, I960_addoe, 3 },
|
|
{ 0x7a1, I960_addie, 3 },
|
|
{ 0x7a2, I960_suboe, 3 },
|
|
{ 0x7a3, I960_subie, 3 },
|
|
{ 0x7a4, I960_sele, 3 },
|
|
{ 0x7b0, I960_addoge, 3 },
|
|
{ 0x7b1, I960_addige, 3 },
|
|
{ 0x7b2, I960_suboge, 3 },
|
|
{ 0x7b3, I960_subige, 3 },
|
|
{ 0x7b4, I960_selge, 3 },
|
|
{ 0x7c0, I960_addol, 3 },
|
|
{ 0x7c1, I960_addil, 3 },
|
|
{ 0x7c2, I960_subol, 3 },
|
|
{ 0x7c3, I960_subil, 3 },
|
|
{ 0x7c4, I960_sell, 3 },
|
|
{ 0x7d0, I960_addone, 3 },
|
|
{ 0x7d1, I960_addine, 3 },
|
|
{ 0x7d2, I960_subone, 3 },
|
|
{ 0x7d3, I960_subine, 3 },
|
|
{ 0x7d4, I960_selne, 3 },
|
|
{ 0x7e0, I960_addole, 3 },
|
|
{ 0x7e1, I960_addile, 3 },
|
|
{ 0x7e2, I960_subole, 3 },
|
|
{ 0x7e3, I960_subile, 3 },
|
|
{ 0x7e4, I960_selle, 3 },
|
|
{ 0x7f0, I960_addoo, 3 },
|
|
{ 0x7f1, I960_addio, 3 },
|
|
{ 0x7f2, I960_suboo, 3 },
|
|
{ 0x7f3, I960_subio, 3 },
|
|
{ 0x7f4, I960_selo, 3 },
|
|
};
|
|
if ( reg_tab == NULL )
|
|
{
|
|
reg_tab = reg_tab_buf;
|
|
for ( int i = 0; i < qnumber(reg_init); i++ )
|
|
{
|
|
int j = reg_init[i].code - REG_MIN;
|
|
QASSERT(10086, j >= 0 && j < qnumber(reg_tab_buf));
|
|
reg_tab[j].itype = reg_init[i].itype;
|
|
reg_tab[j].opnum = reg_init[i].opnum;
|
|
}
|
|
}
|
|
|
|
int opcode = ((code >> 20) & 0xff0) | ((code >> 7) & 0xf);
|
|
if ( opcode < REG_MIN || opcode > REG_MAX )
|
|
return false;
|
|
|
|
int i = opcode - REG_MIN;
|
|
insn.itype = reg_tab[i].itype;
|
|
bool fp = insn.itype >= I960_fp_first && insn.itype <= I960_fp_last;
|
|
|
|
bool s1 = ((code >> 5) & 1) != 0;
|
|
bool s2 = ((code >> 6) & 1) != 0;
|
|
bool m1 = ((code >> 11) & 1) != 0;
|
|
bool m2 = ((code >> 12) & 1) != 0;
|
|
bool m3 = ((code >> 13) & 1) != 0;
|
|
int src = code & 0x1f;
|
|
int src2 = (code >> 14) & 0x1f;
|
|
int dst = (code >> 19) & 0x1f;
|
|
|
|
switch ( reg_tab[i].opnum )
|
|
{
|
|
case 1:
|
|
regop(insn.Op1, m1, s1, src, fp);
|
|
break;
|
|
case -1:
|
|
dstop(insn.Op1, m3, dst, fp);
|
|
break;
|
|
case 2:
|
|
regop(insn.Op1, m1, s1, src, fp);
|
|
regop(insn.Op2, m2, s2, src2, fp);
|
|
break;
|
|
case -2:
|
|
regop(insn.Op1, m1, s1, src, fp);
|
|
dstop(insn.Op2, m3, dst, fp);
|
|
break;
|
|
case 3:
|
|
regop(insn.Op1, m1, s1, src, fp);
|
|
regop(insn.Op2, m2, s2, src2, fp);
|
|
dstop(insn.Op3, m3, dst, fp);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
int i960_t::i960_ana(insn_t *_insn)
|
|
{
|
|
insn_t &insn = *_insn;
|
|
if ( insn.ip & 3 )
|
|
return 0; // alignment error
|
|
uint32 code = insn.get_next_dword();
|
|
switch ( code >> 28 )
|
|
{
|
|
case 0x0:
|
|
case 0x1:
|
|
if ( !ctrl(insn, code) )
|
|
return 0;
|
|
break;
|
|
case 0x2:
|
|
case 0x3:
|
|
if ( !cobr(insn, code) )
|
|
return 0;
|
|
break;
|
|
case 0x5:
|
|
case 0x6:
|
|
case 0x7:
|
|
if ( !reg(insn, code) )
|
|
return 0;
|
|
break;
|
|
case 0x8:
|
|
case 0x9:
|
|
case 0xA:
|
|
case 0xB:
|
|
case 0xC:
|
|
if ( !mem(insn, code) )
|
|
return 0;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return insn.itype == I960_null ? 0 : insn.size;
|
|
}
|
|
|