update to ida 7.6, add builds
This commit is contained in:
942
idasdk76/module/xa/ana.cpp
Normal file
942
idasdk76/module/xa/ana.cpp
Normal file
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#include "xa.hpp"
|
||||
|
||||
static int ana_basic(insn_t &insn);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline int ua_next_word_be(insn_t &insn)
|
||||
{
|
||||
int32 result;
|
||||
result = ((uchar)insn.get_next_byte()) << 8;
|
||||
result += (uchar)insn.get_next_byte();
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void opC(op_t &op)
|
||||
{
|
||||
op.type = o_reg;
|
||||
op.reg = rC;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// register direct
|
||||
static int op_rd(op_t &x, int reg, int dtype)
|
||||
{
|
||||
x.type = o_reg;
|
||||
x.dtype = uchar(dtype);
|
||||
x.reg = uint16((dtype == dt_byte ? rR0L : rR0) + reg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// register indirect
|
||||
static int op_ph(op_t &x, uint16 phrase, int reg, int dtype)
|
||||
{
|
||||
x.type = o_phrase;
|
||||
x.dtype = uchar(dtype);
|
||||
x.phrase = phrase; // union with x.reg
|
||||
x.indreg = (uchar)reg;
|
||||
if ( (phrase != fRlistL) && (phrase != fRlistH) )
|
||||
x.indreg += rR0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// register indirect with displacement
|
||||
static int op_ds(op_t &x, uint16 phrase, int ireg, sval_t disp, int dtype)
|
||||
{
|
||||
if ( disp > 0xFD00L )
|
||||
{
|
||||
disp = disp - 0x10000L; // heuristics: treat large values from -300h as negative
|
||||
}
|
||||
x.type = o_displ;
|
||||
x.dtype = uchar(dtype);
|
||||
x.phrase = phrase;
|
||||
x.indreg = rR0 + (uchar)ireg;
|
||||
x.addr = disp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void op_mm(op_t &x, uval_t addr, int dtype)
|
||||
{
|
||||
x.type = o_mem;
|
||||
x.dtype = uchar(dtype);
|
||||
x.addr = addr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void op_rel(const insn_t &insn, op_t &x, sval_t addr)
|
||||
{
|
||||
if ( addr > 32767 )
|
||||
addr -= 0x10000L;
|
||||
x.type = o_near;
|
||||
x.dtype = dt_code;
|
||||
x.addr = (insn.ip + insn.size + 2*addr) & (~1L);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void op_near(op_t &x, uval_t addr)
|
||||
{
|
||||
x.type = o_near;
|
||||
x.dtype = dt_word;
|
||||
x.addr = addr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void op_im(op_t &x, uval_t value, int dtype)
|
||||
{
|
||||
x.type = o_imm;
|
||||
x.dtype = uchar(dtype);
|
||||
x.value = value;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void op_bit(op_t &x, int type, uval_t addr)
|
||||
{
|
||||
x.type = optype_t(type);
|
||||
x.dtype = dt_word;
|
||||
x.addr = addr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// analyze an basic instruction
|
||||
static int ana_basic(insn_t &insn)
|
||||
{
|
||||
|
||||
static const nameNum xa_basic[16] =
|
||||
{
|
||||
XA_add, XA_addc, XA_sub, XA_subb, XA_cmp, XA_and, XA_or, XA_xor,
|
||||
XA_mov, XA_null, XA_null, XA_null, XA_null, XA_null, XA_null, XA_null,
|
||||
};
|
||||
|
||||
static const nameNum xa_branches[16] =
|
||||
{
|
||||
XA_bcc, XA_bcs, XA_bne, XA_beq, XA_bnv, XA_bov, XA_bpl, XA_bmi,
|
||||
XA_bg, XA_bl, XA_bge, XA_blt, XA_bgt, XA_ble, XA_br, XA_bkpt,
|
||||
};
|
||||
|
||||
static const nameNum xa_pushpop[] =
|
||||
{
|
||||
XA_push, XA_pushu, XA_pop, XA_popu,
|
||||
};
|
||||
|
||||
static const nameNum xa_bitops[] =
|
||||
{
|
||||
XA_clr, XA_setb, XA_mov, XA_mov, XA_anl, XA_anl, XA_orl, XA_orl,
|
||||
};
|
||||
|
||||
static const nameNum xa_Jxx[] =
|
||||
{
|
||||
XA_jb, XA_jnb, XA_jbc, XA_null,
|
||||
};
|
||||
|
||||
static const nameNum xa_misc[] =
|
||||
{
|
||||
XA_da, XA_sext, XA_cpl, XA_neg,
|
||||
};
|
||||
|
||||
static const nameNum xa_shifts[] =
|
||||
{
|
||||
XA_lsr, XA_asl, XA_asr, XA_norm,
|
||||
};
|
||||
|
||||
ushort code = insn.get_next_byte();
|
||||
|
||||
ushort nibble0 = (code & 0xF);
|
||||
ushort nibble1 = (code >> 4);
|
||||
signed char off;
|
||||
int size = 0;
|
||||
ushort b1;
|
||||
|
||||
if ( nibble1 <= 0xB )
|
||||
{
|
||||
switch ( nibble0 & 0x7 )
|
||||
{
|
||||
case 0: // Specials
|
||||
case 7: // dtto
|
||||
switch ( code )
|
||||
{
|
||||
case 0x00: // 00 - NOP
|
||||
insn.itype = XA_nop;
|
||||
break;
|
||||
|
||||
case 0x07: // PUSH.B Rlist
|
||||
case 0x0F: // PUSH.W Rlist
|
||||
case 0x17: // PUSHU.B Rlist
|
||||
case 0x1F: // PUSHU.W Rlist
|
||||
case 0x27: // POP.B Rlist
|
||||
case 0x2F: // POP.W Rlist
|
||||
case 0x37: // POPU.B Rlist
|
||||
case 0x3F: // POPU.W Rlist
|
||||
case 0x47: // PUSH.B Rlist
|
||||
case 0x4F: // PUSH.W Rlist
|
||||
case 0x57: // PUSHU.B Rlist
|
||||
case 0x5F: // PUSHU.W Rlist
|
||||
case 0x67: // POP.B Rlist
|
||||
case 0x6F: // POP.W Rlist
|
||||
case 0x77: // POPU.B Rlist
|
||||
case 0x7F: // POPU.W Rlist
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
b1 = insn.get_next_byte(); // Rlist
|
||||
insn.itype = xa_pushpop[nibble1 & 3];
|
||||
if ( nibble1 & 4 ) // High
|
||||
op_ph(insn.Op1, fRlistH, b1, size);
|
||||
else
|
||||
op_ph(insn.Op1, fRlistL, b1, size);
|
||||
break;
|
||||
|
||||
case 0x08: // 08 - misc
|
||||
b1 = insn.get_next_byte();
|
||||
switch ( b1 & 0xfc )
|
||||
{
|
||||
case 0x00: // CLR
|
||||
case 0x10: // SETB
|
||||
insn.itype = xa_bitops[(b1>>4) & 7];
|
||||
op_bit(insn.Op1, o_bit, ((b1&3)<<8) + (uchar)insn.get_next_byte());
|
||||
break;
|
||||
case 0x20: // MOV C,bit
|
||||
insn.itype = xa_bitops[(b1>>4) & 7];
|
||||
opC(insn.Op1);
|
||||
op_bit(insn.Op2, o_bit, ((b1&3)<<8) + (uchar)insn.get_next_byte());
|
||||
break;
|
||||
case 0x30: // MOV bit,C
|
||||
insn.itype = xa_bitops[(b1>>4) & 7];
|
||||
op_bit(insn.Op1, o_bit, ((b1&3)<<8) + (uchar)insn.get_next_byte());
|
||||
opC(insn.Op2);
|
||||
break;
|
||||
case 0x40: // ANL C, bit
|
||||
case 0x50: // ANL C, /bit
|
||||
case 0x60: // ORL C, bit
|
||||
case 0x70: // ORL C, /bit
|
||||
insn.itype = xa_bitops[(b1>>4) & 7];
|
||||
opC(insn.Op1);
|
||||
op_bit(insn.Op2,
|
||||
(b1&0x10)?o_bitnot:o_bit, ((b1&3)<<8) + (uchar)insn.get_next_byte());
|
||||
break;
|
||||
default: // undefined
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x40: // LEA
|
||||
case 0x48: // LEA
|
||||
insn.itype = XA_lea;
|
||||
b1 = insn.get_next_byte();
|
||||
if ( b1 & 0x88 )
|
||||
return 0;
|
||||
op_rd(insn.Op1, b1>>4, dt_word);
|
||||
if ( code & 0x8 ) // 16bit offset
|
||||
op_ds(insn.Op2, fRid16, b1&0x07, (int32)ua_next_word_be(insn), dt_word);
|
||||
else
|
||||
op_ds(insn.Op2, fRid8, b1&0x07, (signed char)insn.get_next_byte(), dt_word);
|
||||
break;
|
||||
|
||||
case 0x50: // XCH.B Rd,[Rs]
|
||||
case 0x58: // XCH.W Rd,[Rs]
|
||||
case 0x60: // XCH.B Rd,Rs
|
||||
case 0x68: // XCH.W Rd,Rs
|
||||
insn.itype = XA_xch;
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
b1 = insn.get_next_byte();
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 0x5: // Rd,[Rs]
|
||||
if ( b1 & 8 )
|
||||
return 0;
|
||||
op_ds(insn.Op2, fRi, b1&7, 0, size);
|
||||
break;
|
||||
case 0x6: // Rd,Rs
|
||||
op_rd(insn.Op2, b1&0xf, size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80: // MOVC
|
||||
case 0x88: // MOVC
|
||||
b1 = insn.get_next_byte();
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
if ( b1 & 8 )
|
||||
return 0;
|
||||
insn.itype = XA_movc;
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_ph(insn.Op2, fRip, b1&7, size);
|
||||
break;
|
||||
|
||||
case 0x87: // DJNZ Rd, rel8
|
||||
case 0x8F: // POP, POPU, PUSH, PUSHU direct
|
||||
b1 = insn.get_next_byte();
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
if ( b1 & 8 ) // DJNZ
|
||||
{
|
||||
if ( b1 & 7 )
|
||||
return 0;
|
||||
insn.itype = XA_djnz;
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_rel(insn, insn.Op2, (signed char)insn.get_next_byte());
|
||||
}
|
||||
else
|
||||
{ // POP, POPU, PUSH, PUSHU
|
||||
if ( b1 & 0xc0 )
|
||||
return 0;
|
||||
insn.itype = xa_pushpop[3-((b1>>4)&3)];
|
||||
op_mm(insn.Op1, ((b1 & 7) << 8) + insn.get_next_byte(), size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x90: // CPL, DA, SEXT
|
||||
case 0x98: // CPL & MOV [Rd+], [Rs+] & MOV direct, [Rs]
|
||||
b1 = insn.get_next_byte();
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
switch ( b1 & 0x0f )
|
||||
{
|
||||
case 0x0: // MOV [Rd+], [Rs+]
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7: // MOV [Rd+], [Rs+]
|
||||
if ( b1 & 0x80 )
|
||||
return 0;
|
||||
insn.itype = XA_mov;
|
||||
op_ph(insn.Op1, fRip, (b1>>4)&7, size);
|
||||
op_ph(insn.Op2, fRip, (b1&7), size);
|
||||
break;
|
||||
|
||||
case 0x8: // DA
|
||||
case 0x9: // SEXT
|
||||
case 0xA: // CPL
|
||||
case 0xB: // NEG
|
||||
insn.itype = xa_misc[b1&3];
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
if ( (nibble0&8) != 0 && insn.itype == XA_da )
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 0xC: // MOVC A,[A+PC] 904C
|
||||
if ( (nibble0 != 0) & ((b1&0xf0) != 0xc0) )
|
||||
return 0;
|
||||
insn.itype = XA_movc;
|
||||
op_rd(insn.Op1, rA, dt_byte);
|
||||
op_ph(insn.Op2, fApc, 0, dt_byte);
|
||||
break;
|
||||
|
||||
case 0xE: // MOVC A,[A+DPTR] 904E
|
||||
if ( (nibble0 != 0) & ((b1&0xf0) != 0xc0) )
|
||||
return 0;
|
||||
insn.itype = XA_movc;
|
||||
op_rd(insn.Op1, rA, dt_byte);
|
||||
op_ph(insn.Op2, fAdptr, 0, dt_byte);
|
||||
break;
|
||||
|
||||
case 0xF: // MOV Rd,USP & MOV USP, Rs
|
||||
insn.itype = XA_mov;
|
||||
if ( nibble0&8 ) // USP,Rs
|
||||
{
|
||||
op_rd(insn.Op1, rUSP-rR0, dt_word);
|
||||
op_rd(insn.Op2, b1>>4, dt_word);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, dt_word);
|
||||
op_rd(insn.Op2, rUSP-rR0, dt_word);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x97: // {JB,JBC,JNB} bit, rel8 & MOV direct, direct
|
||||
case 0x9F: // {JB,JBC,JNB} bit, rel8 & MOV direct, direct
|
||||
b1 = insn.get_next_byte();
|
||||
if ( (b1 & 0x88) == 0x00 ) // MOV direct, direct
|
||||
{
|
||||
insn.itype = XA_mov;
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
op_mm(insn.Op1, ((b1 & 0x70) << 4) + (uchar)insn.get_next_byte(), size);
|
||||
op_mm(insn.Op2, ((b1 & 0x7) << 8) + (uchar)insn.get_next_byte(), size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( nibble0 & 8 )
|
||||
return 0;
|
||||
switch ( b1 & 0xfc )
|
||||
{
|
||||
case 0x80: // JB
|
||||
case 0xA0: // JNB
|
||||
case 0xC0: // JBC
|
||||
insn.itype = xa_Jxx[(b1>>5)&3];
|
||||
op_bit(insn.Op1, o_bit, ((b1&3)<<8) + (uchar)insn.get_next_byte());
|
||||
op_rel(insn, insn.Op2, (signed char)insn.get_next_byte());
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA0: // MOV.B direct, [Rs] & [Rd], direct & XCH
|
||||
case 0xA8: // MOV.W direct, [Rs] & [Rd], direct & XCH
|
||||
b1 = insn.get_next_byte();
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
if ( b1 & 8 ) // XCH
|
||||
{
|
||||
insn.itype = XA_xch;
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_mm(insn.Op2, ((b1 & 7) << 8) + (uchar)insn.get_next_byte(), size);
|
||||
}
|
||||
else
|
||||
{ // MOV
|
||||
insn.itype = XA_mov;
|
||||
if ( b1 & 0x80 ) // direct, [Rs]
|
||||
{
|
||||
op_mm(insn.Op1, ((b1 & 7) << 8) + (uchar)insn.get_next_byte(), size);
|
||||
op_ds(insn.Op2, fRi, (b1>>4)&7, 0, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_ds(insn.Op1, fRi, (b1>>4)&7, 0, size);
|
||||
op_mm(insn.Op2, ((b1 & 7) << 8) + (uchar)insn.get_next_byte(), size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA7: // MOVX
|
||||
case 0xAF: // MOVX
|
||||
insn.itype = XA_movx;
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
b1 = insn.get_next_byte();
|
||||
if ( b1 & 8 ) // [Rd],Rs
|
||||
{
|
||||
op_ds(insn.Op1, fRi, b1&0x7, 0, size);
|
||||
op_rd(insn.Op2, b1>>4, size);
|
||||
}
|
||||
else
|
||||
{ // Rd,[Rs]
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_ds(insn.Op2, fRi, b1&0x7, 0, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB0: // RR
|
||||
case 0xB7: // RRC
|
||||
case 0xB8: // RR
|
||||
case 0xBF: // RRC
|
||||
insn.itype = (nibble0 & 7) ? XA_rrc : XA_rr;
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
b1 = insn.get_next_byte();
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, b1&0xf, size);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 0: // ADD
|
||||
case 1: // ADDC
|
||||
case 2: // SUB
|
||||
case 3: // SUBB
|
||||
case 4: // CMP
|
||||
case 5: // AND
|
||||
case 6: // OR
|
||||
case 7: // XOR
|
||||
case 8: // MOV
|
||||
insn.itype = xa_basic[nibble1];
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
b1 = insn.get_next_byte();
|
||||
switch ( nibble0 & 0x7 )
|
||||
{
|
||||
case 0x1: // OP Rd,Rs
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_rd(insn.Op2, b1&0xF, size);
|
||||
break;
|
||||
|
||||
case 0x2: // OP Rd,[Rs]
|
||||
if ( b1 & 8 ) // [Rd], Rs
|
||||
{
|
||||
op_ds(insn.Op1, fRi, b1&7, 0, size);
|
||||
op_rd(insn.Op2, b1>>4, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_ds(insn.Op2, fRi, b1&7, 0, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3: // OP Rd,[Rs+]
|
||||
if ( b1 & 8 ) // [Rd], Rs
|
||||
{
|
||||
op_ph(insn.Op1, fRip, (b1&7), size);
|
||||
op_rd(insn.Op2, b1>>4, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_ph(insn.Op2, fRip, (b1&7), size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x4: // OP Rd,[Rs+o8]
|
||||
if ( b1 & 8 ) // [Rd], Rs
|
||||
{
|
||||
op_ds(insn.Op1, fRid8, (b1&7), (signed char)insn.get_next_byte(), size);
|
||||
op_rd(insn.Op2, b1>>4, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_ds(insn.Op2, fRid8, (b1&7), (signed char)insn.get_next_byte(), size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5: // OP Rd,[Rs+o16]
|
||||
if ( b1 & 8 ) // [Rd], Rs
|
||||
{
|
||||
op_ds(insn.Op1, fRid16, (b1&7), (int)ua_next_word_be(insn), size);
|
||||
op_rd(insn.Op2, b1>>4, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_ds(insn.Op2, fRid16, (b1&7), (int)ua_next_word_be(insn), size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6: // OP Rd,direct
|
||||
if ( b1 & 8 ) // direct, Rs
|
||||
{
|
||||
op_mm(insn.Op1, ((b1 & 7) << 8) + insn.get_next_byte(), size);
|
||||
op_rd(insn.Op2, b1>>4, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_mm(insn.Op2, ((b1 & 7) << 8) + insn.get_next_byte(), size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: // Immediate operations
|
||||
b1 = insn.get_next_byte();
|
||||
insn.itype = xa_basic[b1 & 0x0f];
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
switch ( nibble0 & 0x7 )
|
||||
{
|
||||
case 0x1:
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, (size == dt_byte) ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
op_ds(insn.Op1, fRi, (b1>>4) & 0x7, 0, size);
|
||||
op_im(insn.Op2, (size == dt_byte) ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
op_ph(insn.Op1, fRip, (b1>>4) & 0x7, size);
|
||||
op_im(insn.Op2, (size == dt_byte) ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
op_ds(insn.Op1, fRid8, (b1>>4) & 0x7, (signed char)insn.get_next_byte(), size);
|
||||
op_im(insn.Op2, (size == dt_byte) ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
break;
|
||||
|
||||
case 0x5:
|
||||
op_ds(insn.Op1, fRid16, (b1>>4) & 0x7, (int)ua_next_word_be(insn), size);
|
||||
op_im(insn.Op2, (size == dt_byte) ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
op_mm(insn.Op1, (((b1>>4) & 0x7) << 8) + insn.get_next_byte(), size);
|
||||
op_im(insn.Op2, (size == dt_byte) ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA: // ADDS
|
||||
case 0xB: // MOVS
|
||||
b1 = insn.get_next_byte();
|
||||
insn.itype = (nibble1 == 0x0A) ? XA_adds : XA_movs;
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
off = b1 & 0xf;
|
||||
if ( off > 7 )
|
||||
off -= 16;
|
||||
op_im(insn.Op2, (int32)off, size);
|
||||
switch ( nibble0 & 0x7 )
|
||||
{
|
||||
case 0x1:
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
op_ds(insn.Op1, fRi, (b1>>4) & 0x7, 0, size);
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
op_ph(insn.Op1, fRip, (b1>>4) & 0x7, size);
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
op_ds(insn.Op1, fRid8, (b1>>4) & 0x7, (signed char)insn.get_next_byte(), size);
|
||||
break;
|
||||
|
||||
case 0x5:
|
||||
op_ds(insn.Op1, fRid16, (b1>>4) & 0x7, (int)ua_next_word_be(insn), size);
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
op_mm(insn.Op1, (((b1>>4) & 0x7) << 8) + (uchar)insn.get_next_byte(), size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // nibble1 > B
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 0xC: // Shifts, CALL, FCALL
|
||||
switch ( nibble0 & 0xc )
|
||||
{
|
||||
case 0x0:
|
||||
size = dt_byte;
|
||||
break;
|
||||
case 0x8:
|
||||
size = dt_word;
|
||||
break;
|
||||
case 0xC:
|
||||
size = dt_dword;
|
||||
break;
|
||||
case 0x4: // Special instructions
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 4: // FCALL addr24
|
||||
insn.itype = XA_fcall;
|
||||
insn.Op1.type = o_far;
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.addr = (ushort)ua_next_word_be(insn);
|
||||
insn.Op1.specval = (uchar)insn.get_next_byte();
|
||||
break;
|
||||
case 5: // CALL rel16
|
||||
insn.itype = XA_call;
|
||||
op_rel(insn, insn.Op1, (int)ua_next_word_be(insn));
|
||||
break;
|
||||
case 6: // CALL [Rs]
|
||||
b1 = insn.get_next_byte();
|
||||
if ( b1 & 0xf8 )
|
||||
return 0;
|
||||
insn.itype = XA_call;
|
||||
op_ds(insn.Op1, fRi, b1&7, 0, dt_word);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( insn.itype == XA_null )
|
||||
{
|
||||
insn.itype = xa_shifts[nibble0 & 3];
|
||||
b1 = insn.get_next_byte();
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_rd(insn.Op2, b1&0xf, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD: // JMP, FJMP, rotations & shifts with #d4/#d5
|
||||
switch ( nibble0 & 0xC )
|
||||
{
|
||||
case 0x4: // Special instructions
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 7: // rotate
|
||||
break;
|
||||
case 4: // FJMP addr24
|
||||
insn.itype = XA_fjmp;
|
||||
insn.Op1.type = o_far;
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.addr = (ushort)ua_next_word_be(insn);
|
||||
insn.Op1.specval = (uchar)insn.get_next_byte();
|
||||
break;
|
||||
case 5: // JMP rel16
|
||||
insn.itype = XA_jmp;
|
||||
op_rel(insn, insn.Op1, (int)ua_next_word_be(insn));
|
||||
break;
|
||||
case 6: // specials
|
||||
insn.itype = XA_jmp;
|
||||
b1 = insn.get_next_byte();
|
||||
switch ( b1 & 0xf8 )
|
||||
{
|
||||
case 0x10: // RESET
|
||||
if ( b1 & 7 )
|
||||
return 0;
|
||||
insn.itype = XA_reset;
|
||||
break;
|
||||
case 0x30: // TRAP
|
||||
case 0x38: // TRAP
|
||||
insn.itype = XA_trap;
|
||||
op_im(insn.Op1, b1 & 0xf, dt_byte);
|
||||
break;
|
||||
case 0x40: // JMP [A+DPTR]
|
||||
if ( (b1&7) != 6 )
|
||||
return 0;
|
||||
op_ph(insn.Op1, fAdptr, 0, dt_word);
|
||||
break;
|
||||
case 0x60: // JMP [[Rs+]]
|
||||
op_ph(insn.Op1, fRipi, b1&7, dt_word);
|
||||
break;
|
||||
case 0x70: // JMP [Rs]
|
||||
op_ph(insn.Op1, fRi, b1&7, dt_word);
|
||||
break;
|
||||
case 0x80: // RET
|
||||
if ( b1 & 7 )
|
||||
return 0;
|
||||
insn.itype = XA_ret;
|
||||
break;
|
||||
case 0x90: // RETI
|
||||
if ( b1 & 7 )
|
||||
return 0;
|
||||
insn.itype = XA_reti;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0:
|
||||
size = dt_byte;
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
size = dt_word;
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
size = dt_dword;
|
||||
break;
|
||||
}
|
||||
if ( insn.itype == XA_null )
|
||||
{
|
||||
insn.itype = xa_shifts[nibble0 & 3];
|
||||
if ( insn.itype == XA_norm )
|
||||
{ // rotations
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
insn.itype = (nibble0 & 4) ? XA_rlc : XA_rl;
|
||||
b1 = insn.get_next_byte();
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, b1&0xf, size);
|
||||
}
|
||||
else
|
||||
{ // shifts
|
||||
b1 = insn.get_next_byte();
|
||||
if ( size == dt_dword )
|
||||
{
|
||||
op_rd(insn.Op1, (b1>>4)&0x0e, size); // Only even registers allowed
|
||||
op_im(insn.Op2, b1&0x1f, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, b1&0xf, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE: // DIV & MUL & cjne & jz/jnz
|
||||
b1 = insn.get_next_byte();
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 0x0: // MULU.B Rd,Rs
|
||||
insn.itype = XA_mulu;
|
||||
op_rd(insn.Op1, b1>>4, dt_byte);
|
||||
op_rd(insn.Op2, b1&0xf, dt_byte);
|
||||
break;
|
||||
case 0x1: // DIVU.B Rd,Rs
|
||||
insn.itype = XA_divu;
|
||||
op_rd(insn.Op1, b1>>4, dt_byte);
|
||||
op_rd(insn.Op2, b1&0xf, dt_byte);
|
||||
break;
|
||||
case 0x4: // MULU.W Rd,Rs
|
||||
insn.itype = XA_mulu;
|
||||
op_rd(insn.Op1, b1>>4, dt_word);
|
||||
op_rd(insn.Op2, b1&0xf, dt_word);
|
||||
break;
|
||||
case 0x5: // DIVU.W Rd,Rs
|
||||
insn.itype = XA_divu;
|
||||
op_rd(insn.Op1, b1>>4, dt_word);
|
||||
op_rd(insn.Op2, b1&0xf, dt_word);
|
||||
break;
|
||||
case 0x6: // MUL.W Rd,Rs
|
||||
insn.itype = XA_mul;
|
||||
op_rd(insn.Op1, b1>>4, dt_word);
|
||||
op_rd(insn.Op2, b1&0xf, dt_word);
|
||||
break;
|
||||
case 0x7: // DIV.W Rd, Rs
|
||||
insn.itype = XA_div;
|
||||
op_rd(insn.Op1, b1>>4, dt_word);
|
||||
op_rd(insn.Op2, b1&0xf, dt_word);
|
||||
break;
|
||||
case 0x8: // MUL & DIV Rd,#8
|
||||
switch ( b1 & 0xf )
|
||||
{
|
||||
case 0x0: // MULU.B Rd,#d8
|
||||
insn.itype = XA_mulu;
|
||||
size = dt_byte;
|
||||
break;
|
||||
case 0x1: // DIVU.B Rd,#d8
|
||||
insn.itype = XA_divu;
|
||||
size = dt_byte;
|
||||
break;
|
||||
case 0x3: // DIVU.W Rd,#d8
|
||||
insn.itype = XA_divu;
|
||||
size = dt_word;
|
||||
break;
|
||||
case 0xB: // DIV.W Rd,#d8
|
||||
insn.itype = XA_div;
|
||||
size = dt_word;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, insn.get_next_byte(), dt_word);
|
||||
break;
|
||||
case 0x9: // MUL & DIV Rd,#16
|
||||
switch ( b1 & 0xf )
|
||||
{
|
||||
case 0x0: // MULU.W Rd,#d16
|
||||
insn.itype = XA_mulu;
|
||||
size = dt_word;
|
||||
break;
|
||||
case 0x1: // DIVU.D Rd,#d16
|
||||
if ( b1&0x10 )
|
||||
return 0;
|
||||
insn.itype = XA_divu;
|
||||
size = dt_dword;
|
||||
break;
|
||||
case 0x8: // MUL.W Rd,#d16
|
||||
insn.itype = XA_mul;
|
||||
size = dt_word;
|
||||
break;
|
||||
case 0x9: // DIV.D Rd,#d16
|
||||
if ( b1&0x10 )
|
||||
return 0;
|
||||
insn.itype = XA_div;
|
||||
size = dt_dword;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, ua_next_word_be(insn), dt_byte);
|
||||
break;
|
||||
case 0xD: // DIVU.D Rd,Rs
|
||||
if ( b1&0x10 )
|
||||
return 0;
|
||||
insn.itype = XA_divu;
|
||||
op_rd(insn.Op1, b1>>4, dt_dword);
|
||||
op_rd(insn.Op2, b1&0xf, dt_dword);
|
||||
break;
|
||||
case 0xF: // DIV.D Rd, Rs
|
||||
if ( b1&0x10 )
|
||||
return 0;
|
||||
insn.itype = XA_div;
|
||||
op_rd(insn.Op1, b1>>4, dt_dword);
|
||||
op_rd(insn.Op2, b1&0xf, dt_dword);
|
||||
break;
|
||||
case 0x2: // cjne direct & [Rd] & DJNZ direct
|
||||
case 0xA: // cjne direct & [Rd] & DJNZ direct
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
if ( b1 & 8 )
|
||||
{ // DJNZ direct, rel8
|
||||
insn.itype = XA_djnz;
|
||||
op_mm(insn.Op1, ((b1&7)<<8)+(uchar)insn.get_next_byte(), size);
|
||||
op_rel(insn, insn.Op2, (signed char)insn.get_next_byte());
|
||||
}
|
||||
else
|
||||
{ // CJNE.s Rd, direct, rel8
|
||||
insn.itype = XA_cjne;
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_mm(insn.Op2, ((b1&7)<<8)+(uchar)insn.get_next_byte(), size);
|
||||
op_rel(insn, insn.Op3, (signed char)insn.get_next_byte());
|
||||
}
|
||||
break;
|
||||
case 0x3: // cjne #,rel
|
||||
case 0xB: // cjne #,rel
|
||||
if ( b1 & 7 )
|
||||
return 0;
|
||||
insn.itype = XA_cjne;
|
||||
size = (nibble0 < 8) ? dt_byte : dt_word;
|
||||
off = insn.get_next_byte();
|
||||
if ( b1 & 0x8 )
|
||||
op_ds(insn.Op1, fRi, b1>>4, 0, size);
|
||||
else
|
||||
op_rd(insn.Op1, b1>>4, size);
|
||||
op_im(insn.Op2, size == dt_byte ? insn.get_next_byte() : ua_next_word_be(insn), size);
|
||||
op_rel(insn, insn.Op3, off);
|
||||
break;
|
||||
case 0xC: // JZ rel8
|
||||
insn.itype = XA_jz;
|
||||
op_rel(insn, insn.Op1, (signed char)b1);
|
||||
break;
|
||||
case 0xE: // JNZ rel8
|
||||
insn.itype = XA_jnz;
|
||||
op_rel(insn, insn.Op1, (signed char)b1);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF: // Bxx
|
||||
insn.itype = xa_branches[nibble0];
|
||||
if ( nibble0 != 0xF )
|
||||
{
|
||||
op_rel(insn, insn.Op1, (signed char)insn.get_next_byte());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// analyze an instruction
|
||||
int xa_t::ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
insn.itype = XA_null;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op2.dtype = dt_byte;
|
||||
insn.Op3.dtype = dt_byte;
|
||||
|
||||
switch ( ptype ) //-V785 Constant expression in switch statement
|
||||
{
|
||||
case prc_xaG3:
|
||||
return ana_basic(insn);
|
||||
}
|
||||
return 0; //lint !e527 statement is unreachable
|
||||
}
|
||||
1017
idasdk76/module/xa/emu.cpp
Normal file
1017
idasdk76/module/xa/emu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
83
idasdk76/module/xa/ins.cpp
Normal file
83
idasdk76/module/xa/ins.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#include "xa.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc
|
||||
{ "addc", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc with carry
|
||||
{ "adds", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND (op1 &= op2)
|
||||
{ "anl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND Carry and Bit
|
||||
{ "asl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical shift left
|
||||
{ "asr", CF_USE1|CF_USE2|CF_CHG1 }, // Arithmetic shift left
|
||||
{ "bcc", CF_USE1 }, // Branch if Carry clear
|
||||
{ "bcs", CF_USE1 }, // Branch if Carry set
|
||||
{ "beq", CF_USE1 }, // Branch if Zero
|
||||
{ "bg", CF_USE1 }, // Branch if Greater than (unsigned)
|
||||
{ "bge", CF_USE1 }, // Branch if Greater than or equal to (signed)
|
||||
{ "bgt", CF_USE1 }, // Branch if Greater than (signed)
|
||||
{ "bkpt", 0 }, // Breakpoint
|
||||
{ "bl", CF_USE1 }, // Branch if Less than or equal to (unsigned)
|
||||
{ "ble", CF_USE1 }, // Branch if less than or equal to (signed)
|
||||
{ "blt", CF_USE1 }, // Branch if less than (signed)
|
||||
{ "bmi", CF_USE1 }, // Branch if negative
|
||||
{ "bne", CF_USE1 }, // Branch if not equal
|
||||
{ "bnv", CF_USE1 }, // Branch if no overflow
|
||||
{ "bov", CF_USE1 }, // Branch if overflow flag
|
||||
{ "bpl", CF_USE1 }, // Branch if positive
|
||||
{ "br", CF_USE1|CF_STOP|CF_JUMP }, // Branch always
|
||||
{ "call", CF_USE1|CF_CALL }, // Call Subroutine
|
||||
{ "cjne", CF_USE1|CF_USE2|CF_USE3 }, // Compare Operands and JNE
|
||||
{ "clr", CF_CHG1 }, // Clear Operand (0)
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // Compare destination and source registers
|
||||
{ "cpl", CF_USE1|CF_CHG1 }, // Complement Operand
|
||||
{ "da", CF_USE1|CF_CHG1 }, // Decimal Adjust Accumulator
|
||||
{ "div", CF_USE1|CF_CHG1|CF_USE2 }, // Divide
|
||||
{ "divu", CF_USE1|CF_CHG1|CF_USE2 }, // Divide
|
||||
{ "djnz", CF_USE1|CF_CHG1|CF_USE2 }, // Decrement Operand and JNZ
|
||||
{ "fcall", CF_USE1|CF_CALL }, // Far Call
|
||||
{ "fjmp", CF_USE1|CF_STOP|CF_JUMP }, // Far Jump
|
||||
{ "jb", CF_USE1|CF_USE2 }, // Jump if Bit is set
|
||||
{ "jbc", CF_USE1|CF_USE2 }, // Jump if Bit is set & clear Bit
|
||||
{ "jmp", CF_USE1|CF_STOP|CF_JUMP }, // Jump indirect relative to Data Pointer
|
||||
{ "jnb", CF_USE1|CF_USE2 }, // Jump if Bit is clear
|
||||
{ "jnz", CF_USE1 }, // Jump if Acc is not zero
|
||||
{ "jz", CF_USE1 }, // Jump if Acc is zero
|
||||
{ "lea", CF_CHG1|CF_USE2 }, // Load effective address
|
||||
{ "lsr", CF_USE1|CF_CHG1|CF_USE2 }, // Logical shift right
|
||||
{ "mov", CF_CHG1|CF_USE2 }, // Move (Op1 <- Op2)
|
||||
{ "movc", CF_CHG1|CF_USE2 }, // Move code byte relative to second op to Acc
|
||||
{ "movs", CF_CHG1|CF_USE2 }, // Move short
|
||||
{ "movx", CF_CHG1|CF_USE2 }, // Move from/to external RAM
|
||||
{ "mul", CF_USE1|CF_CHG1|CF_USE2 }, // Multiply
|
||||
{ "mulu", CF_USE1|CF_CHG1|CF_USE2 }, // Multiply unsigned
|
||||
{ "neg", CF_USE1|CF_CHG1 }, // Negate
|
||||
{ "nop", 0 }, // No operation
|
||||
{ "norm", CF_USE1|CF_CHG1|CF_CHG2 }, // Normalize
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR (op1 |= op2)
|
||||
{ "orl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR Carry
|
||||
{ "pop", CF_CHG1 }, // Pop from Stack and put in Direct RAM
|
||||
{ "popu", CF_CHG1 }, // Pop from Stack and put in Direct RAM
|
||||
{ "push", CF_USE1 }, // Push from Direct RAM to Stack
|
||||
{ "pushu", CF_USE1 }, // Push from Direct RAM to Stack
|
||||
{ "reset", 0 }, // Software reset
|
||||
{ "ret", CF_STOP }, // Return from subroutine
|
||||
{ "reti", CF_STOP }, // Return from Interrupt
|
||||
{ "rl", CF_USE1|CF_CHG1|CF_USE2 }, // Rotate Acc left
|
||||
{ "rlc", CF_USE1|CF_CHG1|CF_USE2 }, // Rotate Acc left through Carry
|
||||
{ "rr", CF_USE1|CF_CHG1|CF_USE2 }, // Rotate Acc right
|
||||
{ "rrc", CF_USE1|CF_CHG1|CF_USE2 }, // Rotate Acc right through Carry
|
||||
{ "setb", CF_CHG1 }, // Set Direct Bit
|
||||
{ "sext", CF_CHG1 }, // Sign extend
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Second Operand from Acc with Borrow
|
||||
{ "subb", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Second Operand from Acc with Borrow
|
||||
{ "trap", CF_USE1 }, // Software TRAP
|
||||
{ "xch", CF_USE1|CF_CHG1|CF_USE2|CF_CHG2 }, // Exchange Operands
|
||||
{ "xor", CF_USE1|CF_USE2|CF_CHG1 }, // Exclusive OR (op1 ^= op2)
|
||||
};
|
||||
|
||||
CASSERT(sizeof(Instructions)/sizeof(Instructions[0]) == XA_last);
|
||||
90
idasdk76/module/xa/ins.hpp
Normal file
90
idasdk76/module/xa/ins.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
XA_null = 0, // Unknown Operation
|
||||
|
||||
XA_add, // Add Second Operand to Acc
|
||||
XA_addc, // Add Second Operand to Acc with carry
|
||||
XA_adds, // Add Second Operand to Acc
|
||||
XA_and, // Logical AND (op1 &= op2)
|
||||
XA_anl, // Logical AND Carry and Bit
|
||||
XA_asl, // Logical shift left
|
||||
XA_asr, // Arithmetic shift left
|
||||
XA_bcc, // Branch if Carry clear
|
||||
XA_bcs, // Branch if Carry set
|
||||
XA_beq, // Branch if Zero
|
||||
XA_bg, // Branch if Greater than (unsigned)
|
||||
XA_bge, // Branch if Greater than or equal to (signed)
|
||||
XA_bgt, // Branch if Greater than (signed)
|
||||
XA_bkpt, // Breakpoint
|
||||
XA_bl, // Branch if Less than or equal to (unsigned)
|
||||
XA_ble, // Branch if less than or equal to (signed)
|
||||
XA_blt, // Branch if less than (signed)
|
||||
XA_bmi, // Branch if negative
|
||||
XA_bne, // Branch if not equal
|
||||
XA_bnv, // Branch if no overflow
|
||||
XA_bov, // Branch if overflow flag
|
||||
XA_bpl, // Branch if positive
|
||||
XA_br, // Branch always
|
||||
XA_call, // Call Subroutine
|
||||
XA_cjne, // Compare Operands and JNE
|
||||
XA_clr, // Clear Operand (0)
|
||||
XA_cmp, // Compare destination and source registers
|
||||
XA_cpl, // Complement Operand
|
||||
XA_da, // Decimal Adjust Accumulator
|
||||
XA_div, // Divide
|
||||
XA_divu, // Divide
|
||||
XA_djnz, // Decrement Operand and JNZ
|
||||
XA_fcall, // Far Call
|
||||
XA_fjmp, // Far Jump
|
||||
XA_jb, // Jump if Bit is set
|
||||
XA_jbc, // Jump if Bit is set & clear Bit
|
||||
XA_jmp, // Jump indirect relative to Data Pointer
|
||||
XA_jnb, // Jump if Bit is clear
|
||||
XA_jnz, // Jump if Acc is not zero
|
||||
XA_jz, // Jump if Acc is zero
|
||||
XA_lea, // Load effective address
|
||||
XA_lsr, // Logical shift right
|
||||
XA_mov, // Move (Op1 <- Op2)
|
||||
XA_movc, // Move code byte relative to second op to Acc
|
||||
XA_movs, // Move short
|
||||
XA_movx, // Move from/to external RAM
|
||||
XA_mul, // Multiply
|
||||
XA_mulu, // Multiply unsigned
|
||||
XA_neg, // Negate
|
||||
XA_nop, // No operation
|
||||
XA_norm, // Normalize
|
||||
XA_or, // Logical OR (op1 |= op2)
|
||||
XA_orl, // Logical OR Carry
|
||||
XA_pop, // Pop from Stack and put in Direct RAM
|
||||
XA_popu, // Pop from Stack and put in Direct RAM
|
||||
XA_push, // Push from Direct RAM to Stack
|
||||
XA_pushu, // Push from Direct RAM to Stack
|
||||
XA_reset, // Software reset
|
||||
XA_ret, // Return from subroutine
|
||||
XA_reti, // Return from Interrupt
|
||||
XA_rl, // Rotate Acc left
|
||||
XA_rlc, // Rotate Acc left through Carry
|
||||
XA_rr, // Rotate Acc right
|
||||
XA_rrc, // Rotate Acc right through Carry
|
||||
XA_setb, // Set Direct Bit
|
||||
XA_sext, // Sign extend
|
||||
XA_sub, // Subtract Second Operand from Acc with Borrow
|
||||
XA_subb, // Subtract Second Operand from Acc with Borrow
|
||||
XA_trap, // Software TRAP
|
||||
XA_xch, // Exchange Operands
|
||||
XA_xor, // Exclusive OR (op1 ^= op2)
|
||||
|
||||
XA_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
50
idasdk76/module/xa/makefile
Normal file
50
idasdk76/module/xa/makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
PROC=xa
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.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 ana.cpp ins.hpp \
|
||||
xa.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.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)struct.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
emu.cpp ins.hpp xa.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.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 ins.cpp ins.hpp \
|
||||
xa.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.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 ins.hpp out.cpp \
|
||||
xa.hpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.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 \
|
||||
ins.hpp reg.cpp xa.hpp
|
||||
487
idasdk76/module/xa/out.cpp
Normal file
487
idasdk76/module/xa/out.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#include "xa.hpp"
|
||||
#include <fpro.h>
|
||||
#include <diskio.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_xa_t : public outctx_t
|
||||
{
|
||||
out_xa_t(void) = delete; // not used
|
||||
public:
|
||||
void OutReg(int rgnum)
|
||||
{
|
||||
out_register(ph.reg_names[rgnum]);
|
||||
}
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
|
||||
void do_out_equ(const char *name, uchar off);
|
||||
int out_equ(void);
|
||||
};
|
||||
CASSERT(sizeof(out_xa_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_xa_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
AS_PRINTF(1, 0) static void vlog(const char *format, va_list va)
|
||||
{
|
||||
static FILE *fp = NULL;
|
||||
if ( fp == NULL )
|
||||
fp = fopenWT("debug_log");
|
||||
qvfprintf(fp, format, va);
|
||||
qflush(fp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
AS_PRINTF(1, 2) inline void log(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vlog(format, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
#define AT COLSTR("@", SCOLOR_SYMBOL)
|
||||
#define PLUS COLSTR("+", SCOLOR_SYMBOL)
|
||||
|
||||
static const char *const phrases[] =
|
||||
{
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("DPTR", SCOLOR_REG),
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("PC", SCOLOR_REG)
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate the text representation of an operand
|
||||
|
||||
bool out_xa_t::out_operand(const op_t &x)
|
||||
{
|
||||
uval_t v = 0;
|
||||
int dir, bit;
|
||||
qstring qbuf;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
OutReg(x.reg);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case fAdptr:
|
||||
case fApc:
|
||||
out_colored_register_line(phrases[x.phrase]);
|
||||
break;
|
||||
case fRi:
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRip:
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol('+');
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRii:
|
||||
out_symbol('[');
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol(']');
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRipi:
|
||||
out_symbol('[');
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol('+');
|
||||
out_symbol(']');
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRlistL:
|
||||
case fRlistH:
|
||||
v = x.indreg;
|
||||
dir = (x.dtype == dt_byte) ? rR0L : rR0;
|
||||
if ( x.phrase == fRlistH )
|
||||
dir += 8;
|
||||
for ( bit = 0; bit < 8; bit++,dir++,v >>= 1 )
|
||||
{
|
||||
if ( v&1 )
|
||||
{
|
||||
OutReg(dir);
|
||||
if ( v & 0xfe )
|
||||
out_symbol(',');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
if ( insn.itype != XA_lea )
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
if ( x.indreg == rR7 || x.phrase != fRi )
|
||||
out_value(x, OOF_ADDR | OOFS_NEEDSIGN | OOF_SIGNED | OOFW_16);
|
||||
if ( insn.itype != XA_lea )
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, OOFS_IFSIGN | /* OOF_SIGNED | */ OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
case o_near:
|
||||
case o_far:
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_mem:
|
||||
v = map_addr(x.addr);
|
||||
break;
|
||||
case o_near:
|
||||
v = to_ea(insn.cs, x.addr);
|
||||
break;
|
||||
case o_far:
|
||||
v = x.addr + (x.specval<<16);
|
||||
break;
|
||||
}
|
||||
if ( get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, x.addr & 0xFFFF) <= 0 )
|
||||
{
|
||||
if ( x.type == o_far )
|
||||
{
|
||||
// print the segment part
|
||||
out_long(x.specval, 16);
|
||||
out_symbol(':');
|
||||
}
|
||||
// now print the offset
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
break;
|
||||
}
|
||||
|
||||
// we want to output SFR register names always in COLOR_REG,
|
||||
// so remove the color tags and output it manually:
|
||||
|
||||
if ( x.type == o_mem && x.addr >= 0x400 )
|
||||
{
|
||||
tag_remove(&qbuf);
|
||||
out_register(qbuf.begin());
|
||||
break;
|
||||
}
|
||||
out_line(qbuf.begin());
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_bitnot:
|
||||
out_symbol('/');
|
||||
// fallthrough
|
||||
case o_bit:
|
||||
dir = int(x.addr >> 3);
|
||||
bit = x.addr & 7;
|
||||
if ( dir & 0x40 ) // SFR
|
||||
{
|
||||
dir += 0x3c0;
|
||||
}
|
||||
else if ( (dir & 0x20) == 0 ) // Register file
|
||||
{
|
||||
dir = int(x.addr >> 4);
|
||||
bit = x.addr & 15;
|
||||
OutReg(rR0+dir);
|
||||
out_symbol(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
if ( bit > 9 )
|
||||
{
|
||||
out_symbol('1');
|
||||
bit -= 10;
|
||||
}
|
||||
out_symbol(char('0'+bit));
|
||||
break;
|
||||
}
|
||||
if ( ash.uflag & UAS_PBIT )
|
||||
{
|
||||
xa_t &pm = *static_cast<xa_t *>(procmod);
|
||||
const predefined_t *predef = pm.GetPredefinedBits(dir, bit);
|
||||
if ( predef != NULL )
|
||||
{
|
||||
out_line(predef->name, COLOR_REG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
v = map_addr(dir);
|
||||
bool ok = get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, dir) > 0;
|
||||
if ( ok && strchr(qbuf.begin(), '+') == NULL )
|
||||
{
|
||||
|
||||
// we want to output the bit names always in COLOR_REG,
|
||||
// so remove the color tags and output it manually:
|
||||
|
||||
if ( dir < 0x80 )
|
||||
{
|
||||
out_line(qbuf.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
tag_remove(&qbuf);
|
||||
out_register(qbuf.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_long(dir, 16);
|
||||
}
|
||||
out_symbol(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
out_symbol(char('0'+bit));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_xa_t::out_proc_mnem(void)
|
||||
{
|
||||
if ( insn.Op1.type != o_void )
|
||||
{
|
||||
switch ( insn.Op1.dtype )
|
||||
{
|
||||
case dt_byte:
|
||||
out_mnem(8,".b");
|
||||
break;
|
||||
case dt_word:
|
||||
out_mnem(8,".w");
|
||||
break;
|
||||
case dt_dword:
|
||||
out_mnem(8,".d");
|
||||
break;
|
||||
default:
|
||||
out_mnem();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_mnem(); // output instruction mnemonics
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate a text representation of an instruction
|
||||
// the information about the instruction is in the insn structure
|
||||
|
||||
void out_xa_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
out_one_operand(0); // output the first operand
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1); // output the second operand
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2); // output the third operand
|
||||
}
|
||||
|
||||
|
||||
// output a character representation of the immediate values
|
||||
// embedded in the instruction as comments
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of the disassembly
|
||||
|
||||
void xa_t::xa_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of a segment
|
||||
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void xa_t::xa_segstart(outctx_t &ctx, segment_t *Sarea)
|
||||
{
|
||||
qstring sname;
|
||||
get_visible_segm_name(&sname, Sarea);
|
||||
|
||||
if ( ash.uflag & UAS_SECT )
|
||||
{
|
||||
if ( Sarea->type == SEG_IMEM )
|
||||
ctx.flush_buf(".RSECT", DEFAULT_INDENT);
|
||||
else
|
||||
ctx.gen_printf(0, COLSTR("%s: .section", SCOLOR_ASMDIR), sname.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ash.uflag & UAS_NOSEG )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s.segment %s", SCOLOR_AUTOCMT),
|
||||
ash.cmnt, sname.c_str());
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("segment %s",SCOLOR_ASMDIR), sname.c_str());
|
||||
if ( ash.uflag & UAS_SELSG )
|
||||
ctx.flush_buf(sname.c_str(), DEFAULT_INDENT);
|
||||
if ( ash.uflag & UAS_CDSEG )
|
||||
ctx.flush_buf(Sarea->type == SEG_IMEM
|
||||
? COLSTR("DSEG", SCOLOR_ASMDIR)
|
||||
: COLSTR("CSEG", SCOLOR_ASMDIR),
|
||||
DEFAULT_INDENT);
|
||||
// XSEG - eXternal memory
|
||||
}
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
adiff_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_cmt_line("%s %s", ash.origin, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate end of the disassembly
|
||||
|
||||
void xa_t::xa_footer(outctx_t &ctx)
|
||||
{
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
ctx.out_line(ash.end, COLOR_ASMDIR);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
ctx.out_char(' ');
|
||||
if ( ash.uflag & UAS_NOENS )
|
||||
ctx.out_line(ash.cmnt);
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// output one "equ" directive
|
||||
|
||||
void out_xa_t::do_out_equ(const char *name, uchar off)
|
||||
{
|
||||
if ( (ash.uflag & UAS_PSAM) != 0 )
|
||||
{
|
||||
out_line(ash.a_equ, COLOR_KEYWORD);
|
||||
out_char(' ');
|
||||
out_line(name);
|
||||
out_symbol(',');
|
||||
}
|
||||
else
|
||||
{
|
||||
out_line(name);
|
||||
if ( ash.uflag & UAS_EQCLN )
|
||||
out_symbol(':');
|
||||
out_char(' ');
|
||||
out_line(ash.a_equ, COLOR_KEYWORD);
|
||||
out_char(' ');
|
||||
}
|
||||
out_long(off, 16);
|
||||
clr_gen_label();
|
||||
out_tagoff(COLOR_SYMBOL);
|
||||
flush_outbuf(0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// output "equ" directive(s) if necessary
|
||||
int out_xa_t::out_equ(void)
|
||||
{
|
||||
ea_t ea = insn.ea;
|
||||
segment_t *s = getseg(ea);
|
||||
if ( s != NULL && s->type == SEG_IMEM && ash.a_equ != NULL )
|
||||
{
|
||||
qstring name;
|
||||
if ( get_visible_name(&name, ea) > 0
|
||||
&& ((ash.uflag & UAS_PBYTNODEF) == 0 || !xa_t::IsPredefined(name.begin())) )
|
||||
{
|
||||
get_colored_name(&name, ea);
|
||||
uchar off = uchar(ea - get_segm_base(s));
|
||||
do_out_equ(name.begin(), off);
|
||||
if ( (ash.uflag & UAS_AUBIT) == 0 && (off & 0xF8) == off )
|
||||
{
|
||||
qstring tmp;
|
||||
out_tagon(COLOR_SYMBOL);
|
||||
out_char(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
tmp.swap(outbuf);
|
||||
for ( int i=0; i < 8; i++,off++ )
|
||||
{
|
||||
qstring full = tmp;
|
||||
full.append('0' + i);
|
||||
do_out_equ(full.begin(), off);
|
||||
}
|
||||
gen_empty_line();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clr_gen_label();
|
||||
flush_buf("");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if ( (ash.uflag & UAS_NODS) != 0 )
|
||||
{
|
||||
if ( !is_loaded(ea) && s->type == SEG_CODE )
|
||||
{
|
||||
adiff_t org = ea - get_segm_base(s) + get_item_size(ea);
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate a data representation
|
||||
// usually all the job is handled by the kernel's standard procedure,
|
||||
// out_data()
|
||||
// But 8051 has its own quirks (namely, "equ" directives) and out_data()
|
||||
// can't handle them. So we output "equ" ourselves and pass everything
|
||||
// else to out_data()
|
||||
// Again, let's repeat: usually the data items are output by the kernel
|
||||
// function out_data(). You have to override it only if the processor
|
||||
// has special features and the data itesm should be displayed in a
|
||||
// special way.
|
||||
|
||||
void xa_t::xa_data(outctx_t &ctx, bool analyze_only)
|
||||
{
|
||||
// the kernel's standard routine which outputs the data knows nothing
|
||||
// about "equ" directives. So we do the following:
|
||||
// - try to output an "equ" directive
|
||||
// - if we succeed, then ok
|
||||
// - otherwise let the standard data output routine, out_data()
|
||||
// do all the job
|
||||
|
||||
out_xa_t *p = (out_xa_t *)&ctx;
|
||||
if ( !p->out_equ() )
|
||||
ctx.out_data(analyze_only);
|
||||
}
|
||||
651
idasdk76/module/xa/reg.cpp
Normal file
651
idasdk76/module/xa/reg.cpp
Normal file
@@ -0,0 +1,651 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#include "xa.hpp"
|
||||
#include <entry.hpp>
|
||||
#include <segregs.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"R0L", "R0H", "R1L", "R1H", "R2L", "R2H", "R3L", "R3H",
|
||||
"R4L", "R4H", "R5L", "R5H", "R6L", "R6H", "R7L", "R7H",
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
|
||||
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
|
||||
"A", "DPTR", "C", "PC", "USP",
|
||||
"CS","DS", "ES",
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
const predefined_t iregs[] =
|
||||
{
|
||||
{ prc_xaG3, 0x6A, 0, "BCR", "Bus configuration register" },
|
||||
{ prc_xaG3, 0x69, 0, "BTRH", "Bus timing register high byte" },
|
||||
{ prc_xaG3, 0x68, 0, "BTRL", "Bus timing register low byte" },
|
||||
{ prc_xaG3, 0x43, 0, "CS", "Code segment" },
|
||||
{ prc_xaG3, 0x41, 0, "DS", "Data segment" },
|
||||
{ prc_xaG3, 0x42, 0, "ES", "Extra segment" },
|
||||
{ prc_xaG3, 0x27, 0, "IEH", "Interrupt enable high byte" },
|
||||
{ prc_xaG3, 0x26, 0, "IEL", "Interrupt enable low byte" },
|
||||
{ prc_xaG3, 0xa0, 0, "IPA0", "Interrupt priority 0" },
|
||||
{ prc_xaG3, 0xa1, 0, "IPA1", "Interrupt priority 1" },
|
||||
{ prc_xaG3, 0xa2, 0, "IPA2", "Interrupt priority 2" },
|
||||
{ prc_xaG3, 0xa3, 0, "IPA3", "Interrupt priority 3" },
|
||||
{ prc_xaG3, 0xa4, 0, "IPA4", "Interrupt priority 4" },
|
||||
{ prc_xaG3, 0xa5, 0, "IPA5", "Interrupt priority 5" },
|
||||
{ prc_xaG3, 0x30, 0, "P0", "Port 0" },
|
||||
{ prc_xaG3, 0x31, 0, "P1", "Port 1" },
|
||||
{ prc_xaG3, 0x32, 0, "P2", "Port 2" },
|
||||
{ prc_xaG3, 0x33, 0, "P3", "Port 3" },
|
||||
{ prc_xaG3, 0x70, 0, "P0CFGA", "Port 0 configuration A" },
|
||||
{ prc_xaG3, 0x71, 0, "P1CFGA", "Port 1 configuration A" },
|
||||
{ prc_xaG3, 0x72, 0, "P2CFGA", "Port 2 configuration A" },
|
||||
{ prc_xaG3, 0x73, 0, "P3CFGA", "Port 3 configuration A" },
|
||||
{ prc_xaG3, 0xF0, 0, "P0CFGB", "Port 0 configuration B" },
|
||||
{ prc_xaG3, 0xF1, 0, "P1CFGB", "Port 1 configuration B" },
|
||||
{ prc_xaG3, 0xF2, 0, "P2CFGB", "Port 2 configuration B" },
|
||||
{ prc_xaG3, 0xF3, 0, "P3CFGB", "Port 3 configuration B" },
|
||||
{ prc_xaG3, 0x04, 0, "PCON", "Power control register" },
|
||||
{ prc_xaG3, 0x01, 0, "PSWH", "Program status word high byte" },
|
||||
{ prc_xaG3, 0x00, 0, "PSWL", "Program status word low byte" },
|
||||
{ prc_xaG3, 0x02, 0, "PSW51", "8051 compatible PSW" },
|
||||
{ prc_xaG3, 0x55, 0, "RTH0", "Timer 0 extender reload high byte" },
|
||||
{ prc_xaG3, 0x57, 0, "RTH1", "Timer 1 extender reload high byte" },
|
||||
{ prc_xaG3, 0x54, 0, "RTL0", "Timer 0 extender reload low byte" },
|
||||
{ prc_xaG3, 0x56, 0, "RTL1", "Timer 1 extender reload low byte" },
|
||||
{ prc_xaG3, 0x20, 0, "S0CON", "Serial port 0 control register" },
|
||||
{ prc_xaG3, 0x21, 0, "S0STAT", "Serial port 0 extended status" },
|
||||
{ prc_xaG3, 0x60, 0, "S0BUF", "Serial port 0 buffer register" },
|
||||
{ prc_xaG3, 0x61, 0, "S0ADDR", "Serial port 0 address register" },
|
||||
{ prc_xaG3, 0x62, 0, "S0ADEN", "Serial port 0 address enable" },
|
||||
{ prc_xaG3, 0x24, 0, "S1CON", "Serial port 1 control register" },
|
||||
{ prc_xaG3, 0x25, 0, "S1STAT", "Serial port 1 extended status" },
|
||||
{ prc_xaG3, 0x64, 0, "S1BUF", "Serial port 1 buffer register" },
|
||||
{ prc_xaG3, 0x65, 0, "S1ADDR", "Serial port 1 address register" },
|
||||
{ prc_xaG3, 0x66, 0, "S1ADEN", "Serial port 1 address enable" },
|
||||
{ prc_xaG3, 0x40, 0, "SCR", "System configuration register" },
|
||||
{ prc_xaG3, 0x03, 0, "SSEL", "Segment selection register" },
|
||||
{ prc_xaG3, 0x7A, 0, "SWE", "Software interrupt enable" },
|
||||
{ prc_xaG3, 0x2A, 0, "SWR", "Software interrupt reguest" },
|
||||
{ prc_xaG3, 0x18, 0, "T2CON", "Timer 2 control register" },
|
||||
{ prc_xaG3, 0x19, 0, "T2MOD", "Timer 2 mode control" },
|
||||
{ prc_xaG3, 0x59, 0, "TH2", "Timer 2 high byte" },
|
||||
{ prc_xaG3, 0x58, 0, "TL2", "Timer 2 low byte" },
|
||||
{ prc_xaG3, 0x5B, 0, "T2CAPH", "Timer 2 capture register high byte" },
|
||||
{ prc_xaG3, 0x5A, 0, "T2CAPL", "Timer 2 capture register low byte" },
|
||||
{ prc_xaG3, 0x10, 0, "TCON", "Timer 0 and 1 control register" },
|
||||
{ prc_xaG3, 0x51, 0, "TH0", "Timer 0 high byte" },
|
||||
{ prc_xaG3, 0x53, 0, "TH1", "Timer 1 high byte" },
|
||||
{ prc_xaG3, 0x50, 0, "TL0", "Timer 0 low byte" },
|
||||
{ prc_xaG3, 0x52, 0, "TL1", "Timer 1 low byte" },
|
||||
{ prc_xaG3, 0x5C, 0, "TMOD", "Timer 0 and 1 mode control" },
|
||||
{ prc_xaG3, 0x11, 0, "TSTAT", "Timer 0 and 1 extended status" },
|
||||
{ prc_xaG3, 0x1F, 0, "WDCON", "Watchdog control register" },
|
||||
{ prc_xaG3, 0x5F, 0, "WDL", "Watchdog timer reload" },
|
||||
{ prc_xaG3, 0x5D, 0, "WFEED1", "Watchdog feed 1" },
|
||||
{ prc_xaG3, 0x5E, 0, "WFEED2", "Watchdog feed 2" },
|
||||
{ prc_xaG3, 0x00, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
const predefined_t ibits[] =
|
||||
{
|
||||
{ prc_xaG3, 0x427, 0, "ERI0", "IEH.0 - " },
|
||||
{ prc_xaG3, 0x427, 1, "ETI0", "IEH.1 - " },
|
||||
{ prc_xaG3, 0x427, 2, "ERI1", "IEH.2 - " },
|
||||
{ prc_xaG3, 0x427, 3, "ETI1", "IEH.3 - " },
|
||||
{ prc_xaG3, 0x426, 0, "EX0", "IEL.0 - " },
|
||||
{ prc_xaG3, 0x426, 1, "ET0", "IEL.1 - " },
|
||||
{ prc_xaG3, 0x426, 2, "EX1", "IEL.2 - " },
|
||||
{ prc_xaG3, 0x426, 3, "ET1", "IEL.3 - " },
|
||||
{ prc_xaG3, 0x426, 4, "ET2", "IEL.4 - " },
|
||||
{ prc_xaG3, 0x426, 7, "EA", "IEL.7 - " },
|
||||
{ prc_xaG3, 0x426, 7, "EA", "IEL.7 - " },
|
||||
{ prc_xaG3, 0x404, 0, "IDL", "PCON.0 - Idle Mode Bit" },
|
||||
{ prc_xaG3, 0x404, 1, "PD", "PCON.1 - Power Down Mode Bit" },
|
||||
{ prc_xaG3, 0x401, 0, "IM0", "PSWH.0 - Interrupt mask 0" },
|
||||
{ prc_xaG3, 0x401, 1, "IM1", "PSWH.1 - Interrupt mask 1" },
|
||||
{ prc_xaG3, 0x401, 2, "IM2", "PSWH.2 - Interrupt mask 2" },
|
||||
{ prc_xaG3, 0x401, 3, "IM3", "PSWH.3 - Interrupt mask 3" },
|
||||
{ prc_xaG3, 0x401, 4, "RS0", "PSWH.4 - Register select 0" },
|
||||
{ prc_xaG3, 0x401, 5, "RS1", "PSWH.5 - Register select 1" },
|
||||
{ prc_xaG3, 0x401, 6, "TM", "PSWH.6 - Trace mode" },
|
||||
{ prc_xaG3, 0x401, 7, "SM", "PSWH.7 - System mode" },
|
||||
{ prc_xaG3, 0x400, 0, "Z", "PSWL.0 - Zero flag" },
|
||||
{ prc_xaG3, 0x400, 1, "N", "PSWL.1 - Negative flag" },
|
||||
{ prc_xaG3, 0x400, 2, "V", "PSWL.2 - Overflow flag" },
|
||||
{ prc_xaG3, 0x400, 6, "AC", "PSWL.6 - Auxiliary carry flag" },
|
||||
{ prc_xaG3, 0x400, 7, "CY", "PSWL.7 - Carry flag" },
|
||||
{ prc_xaG3, 0x420, 0, "RI_0", "S0CON.0 -" },
|
||||
{ prc_xaG3, 0x420, 1, "TI_0", "S0CON.1 -" },
|
||||
{ prc_xaG3, 0x420, 2, "RB8_0", "S0CON.2 -" },
|
||||
{ prc_xaG3, 0x420, 3, "TB8_0", "S0CON.3 -" },
|
||||
{ prc_xaG3, 0x420, 4, "REN_0", "S0CON.4 -" },
|
||||
{ prc_xaG3, 0x420, 5, "SM2_0", "S0CON.5 -" },
|
||||
{ prc_xaG3, 0x420, 6, "SM1_0", "S0CON.6 -" },
|
||||
{ prc_xaG3, 0x420, 7, "SM0_0", "S0CON.7 -" },
|
||||
{ prc_xaG3, 0x421, 0, "STINT0", "S0STAT.0 -" },
|
||||
{ prc_xaG3, 0x421, 1, "OE0", "S0STAT.1 -" },
|
||||
{ prc_xaG3, 0x421, 2, "BR0", "S0STAT.2 -" },
|
||||
{ prc_xaG3, 0x421, 3, "FE0", "S0STAT.3 -" },
|
||||
{ prc_xaG3, 0x424, 0, "RI_1", "S1CON.0 -" },
|
||||
{ prc_xaG3, 0x424, 1, "TI_1", "S1CON.1 -" },
|
||||
{ prc_xaG3, 0x424, 2, "RB8_1", "S1CON.2 -" },
|
||||
{ prc_xaG3, 0x424, 3, "TB8_1", "S1CON.3 -" },
|
||||
{ prc_xaG3, 0x424, 4, "REN_1", "S1CON.4 -" },
|
||||
{ prc_xaG3, 0x424, 5, "SM2_1", "S1CON.5 -" },
|
||||
{ prc_xaG3, 0x424, 6, "SM1_1", "S1CON.6 -" },
|
||||
{ prc_xaG3, 0x424, 7, "SM0_1", "S1CON.7 -" },
|
||||
{ prc_xaG3, 0x425, 0, "STINT1", "S1STAT.0 -" },
|
||||
{ prc_xaG3, 0x425, 1, "OE1", "S1STAT.1 -" },
|
||||
{ prc_xaG3, 0x425, 2, "BR1", "S1STAT.2 -" },
|
||||
{ prc_xaG3, 0x425, 3, "FE1", "S1STAT.3 -" },
|
||||
{ prc_xaG3, 0x403, 0, "R0SEG", "SSEL.0 -" },
|
||||
{ prc_xaG3, 0x403, 1, "R1SEG", "SSEL.1 -" },
|
||||
{ prc_xaG3, 0x403, 2, "R2SEG", "SSEL.2 -" },
|
||||
{ prc_xaG3, 0x403, 3, "R3SEG", "SSEL.3 -" },
|
||||
{ prc_xaG3, 0x403, 4, "R4SEG", "SSEL.4 -" },
|
||||
{ prc_xaG3, 0x403, 5, "R5SEG", "SSEL.5 -" },
|
||||
{ prc_xaG3, 0x403, 6, "R6SEG", "SSEL.6 -" },
|
||||
{ prc_xaG3, 0x403, 7, "ESWEN", "SSEL.7 -" },
|
||||
{ prc_xaG3, 0x42A, 0, "SWR1", "SWR.0 -" },
|
||||
{ prc_xaG3, 0x42A, 1, "SWR2", "SWR.1 -" },
|
||||
{ prc_xaG3, 0x42A, 2, "SWR3", "SWR.2 -" },
|
||||
{ prc_xaG3, 0x42A, 3, "SWR4", "SWR.3 -" },
|
||||
{ prc_xaG3, 0x42A, 4, "SWR5", "SWR.4 -" },
|
||||
{ prc_xaG3, 0x42A, 5, "SWR6", "SWR.5 -" },
|
||||
{ prc_xaG3, 0x42A, 6, "SWR7", "SWR.6 -" },
|
||||
{ prc_xaG3, 0x418, 0, "CPRL2", "T2CON.0 -" },
|
||||
{ prc_xaG3, 0x418, 1, "CT2", "T2CON.1 -" },
|
||||
{ prc_xaG3, 0x418, 2, "TR2", "T2CON.2 -" },
|
||||
{ prc_xaG3, 0x418, 3, "EXEN2", "T2CON.3 -" },
|
||||
{ prc_xaG3, 0x418, 4, "TCLK0", "T2CON.4 -" },
|
||||
{ prc_xaG3, 0x418, 5, "RCLK0", "T2CON.5 -" },
|
||||
{ prc_xaG3, 0x418, 6, "EXF2", "T2CON.6 -" },
|
||||
{ prc_xaG3, 0x418, 7, "TF2", "T2CON.7 -" },
|
||||
{ prc_xaG3, 0x419, 0, "DCEN", "T2MOD.0 -" },
|
||||
{ prc_xaG3, 0x419, 1, "T2OE", "T2MOD.1 -" },
|
||||
{ prc_xaG3, 0x419, 2, "T2RD", "T2MOD.2 -" },
|
||||
{ prc_xaG3, 0x419, 4, "TCLK1", "T2MOD.4 -" },
|
||||
{ prc_xaG3, 0x419, 5, "RCLK1", "T2MOD.5 -" },
|
||||
{ prc_xaG3, 0x410, 0, "IT0", "TCON.0 -" },
|
||||
{ prc_xaG3, 0x410, 1, "IE0", "TCON.1 -" },
|
||||
{ prc_xaG3, 0x410, 2, "IT1", "TCON.2 -" },
|
||||
{ prc_xaG3, 0x410, 3, "IE1", "TCON.3 -" },
|
||||
{ prc_xaG3, 0x410, 4, "TR0", "TCON.4 -" },
|
||||
{ prc_xaG3, 0x410, 6, "TF0", "TCON.5 -" },
|
||||
{ prc_xaG3, 0x410, 6, "TR1", "TCON.6 -" },
|
||||
{ prc_xaG3, 0x410, 7, "TF1", "TCON.7 -" },
|
||||
{ prc_xaG3, 0x411, 0, "T0OE", "TSTAT.0 -" },
|
||||
{ prc_xaG3, 0x411, 1, "T0RD", "TSTAT.1 -" },
|
||||
{ prc_xaG3, 0x411, 2, "T1OE", "TSTAT.2 -" },
|
||||
{ prc_xaG3, 0x411, 3, "T1RD", "TSTAT.3 -" },
|
||||
{ prc_xaG3, 0x41f, 1, "WDTOF", "WDCON.1 -" },
|
||||
{ prc_xaG3, 0x41f, 2, "WDRUN", "WDCON.2 -" },
|
||||
{ prc_xaG3, 0x41f, 5, "PRE0", "WDCON.5 -" },
|
||||
{ prc_xaG3, 0x41f, 6, "PRE1", "WDCON.6 -" },
|
||||
{ prc_xaG3, 0x41f, 7, "PRE2", "WDCON.7 -" },
|
||||
{ prc_xaG3, 0x000, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int xa_t::IsPredefined(const char *name)
|
||||
{
|
||||
const predefined_t *ptr;
|
||||
|
||||
for ( ptr = ibits; ptr->name != NULL; ptr++ )
|
||||
if ( strcmp(ptr->name, name) == 0 )
|
||||
return 1;
|
||||
|
||||
for ( ptr = iregs; ptr->name != NULL; ptr++ )
|
||||
if ( strcmp(ptr->name, name) == 0 )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
const predefined_t *xa_t::GetPredefined(const predefined_t *ptr,int addr,int bit) const
|
||||
{
|
||||
for ( ; ptr->name != NULL; ptr++ )
|
||||
{
|
||||
if ( ptr->proc != ptype )
|
||||
continue;
|
||||
if ( addr == ptr->addr && bit == ptr->bit )
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
const predefined_t *xa_t::GetPredefinedBits(int addr, int bit) const
|
||||
{
|
||||
return GetPredefined(ibits, addr, bit);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void xa_t::attach_bit_comment(const insn_t &insn, int addr, int bit) const
|
||||
{
|
||||
const predefined_t *predef = GetPredefined(ibits, addr, bit);
|
||||
if ( predef != NULL && get_cmt(NULL, insn.ea, false) <= 0 )
|
||||
set_cmt(insn.ea,predef->cmt,0);
|
||||
}
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
uint32 off;
|
||||
char proc;
|
||||
};
|
||||
|
||||
static entry_t const entries[] =
|
||||
{
|
||||
#define ENTRY(proc, off, name, cmt) { name, cmt, off, proc }
|
||||
ENTRY(prc_xaG3, 0x00, "Reset", "Reset (h/w, watchdog, s/w)"),
|
||||
ENTRY(prc_xaG3, 0x04, "Breakpoint", "Breakpoint instruction (h/w trap 1)"),
|
||||
ENTRY(prc_xaG3, 0x08, "Trace", "Trace (h/w trap 2)"),
|
||||
ENTRY(prc_xaG3, 0x0C, "StackOverflow", "Stack Overflow (h/w trap 3)"),
|
||||
ENTRY(prc_xaG3, 0x10, "DivBy0", "Divide by 0 (h/w trap 4)"),
|
||||
ENTRY(prc_xaG3, 0x14, "UserRETI", "User RETI (h/w trap 5)"),
|
||||
ENTRY(prc_xaG3, 0x40, "Trap0", "Software TRAP 0"),
|
||||
ENTRY(prc_xaG3, 0x44, "Trap1", "Software TRAP 1"),
|
||||
ENTRY(prc_xaG3, 0x48, "Trap2", "Software TRAP 2"),
|
||||
ENTRY(prc_xaG3, 0x4C, "Trap3", "Software TRAP 3"),
|
||||
ENTRY(prc_xaG3, 0x50, "Trap4", "Software TRAP 4"),
|
||||
ENTRY(prc_xaG3, 0x54, "Trap5", "Software TRAP 5"),
|
||||
ENTRY(prc_xaG3, 0x58, "Trap6", "Software TRAP 6"),
|
||||
ENTRY(prc_xaG3, 0x5C, "Trap7", "Software TRAP 7"),
|
||||
ENTRY(prc_xaG3, 0x60, "Trap8", "Software TRAP 8"),
|
||||
ENTRY(prc_xaG3, 0x64, "Trap9", "Software TRAP 9"),
|
||||
ENTRY(prc_xaG3, 0x68, "Trap10", "Software TRAP 10"),
|
||||
ENTRY(prc_xaG3, 0x6C, "Trap11", "Software TRAP 11"),
|
||||
ENTRY(prc_xaG3, 0x70, "Trap12", "Software TRAP 12"),
|
||||
ENTRY(prc_xaG3, 0x74, "Trap13", "Software TRAP 13"),
|
||||
ENTRY(prc_xaG3, 0x78, "Trap14", "Software TRAP 14"),
|
||||
ENTRY(prc_xaG3, 0x7C, "Trap15", "Software TRAP 15"),
|
||||
ENTRY(prc_xaG3, 0x80, "ExtInt0", "External Interrupt 0"),
|
||||
ENTRY(prc_xaG3, 0x84, "TimerInt0", "Timer 0 Interrupt"),
|
||||
ENTRY(prc_xaG3, 0x88, "ExtInt1", "External Interrupt 1"),
|
||||
ENTRY(prc_xaG3, 0x8C, "TimerInt1", "Timer 1 Interrupt"),
|
||||
ENTRY(prc_xaG3, 0x90, "TimerInt2", "Timer 2 Interrupt"),
|
||||
ENTRY(prc_xaG3, 0xA0, "SerIntRx0", "Serial port 0 Rx"),
|
||||
ENTRY(prc_xaG3, 0xA4, "SerIntTx0", "Serial port 0 Tx"),
|
||||
ENTRY(prc_xaG3, 0xA8, "SerIntRx1", "Serial port 1 Rx"),
|
||||
ENTRY(prc_xaG3, 0xAC, "SerIntTx1", "Serial port 1 Tx"),
|
||||
ENTRY(prc_xaG3, 0x100, "SWI1", "Software Interrupt 1"),
|
||||
ENTRY(prc_xaG3, 0x104, "SWI2", "Software Interrupt 2"),
|
||||
ENTRY(prc_xaG3, 0x108, "SWI3", "Software Interrupt 3"),
|
||||
ENTRY(prc_xaG3, 0x10C, "SWI4", "Software Interrupt 4"),
|
||||
ENTRY(prc_xaG3, 0x110, "SWI5", "Software Interrupt 5"),
|
||||
ENTRY(prc_xaG3, 0x114, "SWI6", "Software Interrupt 6"),
|
||||
ENTRY(prc_xaG3, 0x118, "SWI7", "Software Interrupt 7"),
|
||||
#undef ENTRY
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(new xa_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// The kernel event notifications
|
||||
// Here you may take desired actions upon some kernel events
|
||||
ssize_t idaapi xa_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_be(false); // Set a little endian mode of the IDA kernel
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
segment_t *sptr = get_first_seg();
|
||||
if ( sptr != NULL )
|
||||
{
|
||||
if ( sptr->start_ea-get_segm_base(sptr) == 0 )
|
||||
{
|
||||
inf_set_start_ea(sptr->start_ea);
|
||||
inf_set_start_ip(BADADDR);
|
||||
if ( sptr->size() > 0x10000 )
|
||||
{
|
||||
ea_t end_ea = sptr->end_ea;
|
||||
ea_t start_ea = sptr->start_ea;
|
||||
|
||||
if ( end_ea & 0xFFFF )
|
||||
{
|
||||
ea_t start = end_ea & 0xFFFF0000;
|
||||
add_segm(start >> 4, start, end_ea, "ROMxx", "CODE");
|
||||
end_ea = start;
|
||||
}
|
||||
for ( ea_t start = end_ea - 0x10000;
|
||||
start > start_ea;
|
||||
end_ea -= 0x10000, start -= 0x10000 )
|
||||
{
|
||||
char sname[32];
|
||||
qsnprintf(sname, sizeof(sname), "RAM%02x", int((start&0xFF0000L)>>16));
|
||||
|
||||
add_segm(start>>4, start, start+0x10000, sname, "CODE");
|
||||
}
|
||||
sptr = getseg(start_ea);
|
||||
set_segm_name(sptr, "ROM00");
|
||||
set_segm_class(sptr, "CODE");
|
||||
}
|
||||
for ( int i=0; i < qnumber(entries); i++ )
|
||||
{
|
||||
if ( entries[i].proc > ptype )
|
||||
continue;
|
||||
ea_t ea = inf_get_start_ea()+entries[i].off;
|
||||
if ( is_mapped(ea) && get_byte(ea) == 0 )
|
||||
{
|
||||
add_entry(ea, ea, entries[i].name, 0);
|
||||
create_word(ea, 2);
|
||||
create_word(ea+2, 2);
|
||||
op_offset(ea+2, 0, REF_OFF16, get_word(ea+2));
|
||||
add_cref(ea+2, get_word(ea+2), fl_CN);
|
||||
set_cmt(ea, entries[i].cmt, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_segm(INTMEMBASE>>4, INTMEMBASE, INTMEMBASE+0x400, "INTMEM", "DATA");
|
||||
add_segm(INTMEMBASE>>4, SFRBASE, SFRBASE+0x400, "SFR", "DATA");
|
||||
|
||||
// the default data segment will be INTMEM
|
||||
set_default_dataseg(getseg(INTMEMBASE)->sel);
|
||||
|
||||
const predefined_t *ptr;
|
||||
for ( ptr=iregs; ptr->name != NULL; ptr++ )
|
||||
{
|
||||
ea_t ea = SFRBASE + ptr->addr;
|
||||
ea_t oldea = get_name_ea(BADADDR, ptr->name);
|
||||
if ( oldea != ea )
|
||||
{
|
||||
if ( oldea != BADADDR )
|
||||
del_global_name(oldea);
|
||||
create_byte(ea, 1);
|
||||
set_name(ea, ptr->name, SN_NOCHECK|SN_NODUMMY);
|
||||
}
|
||||
if ( ptr->cmt != NULL )
|
||||
set_cmt(ea, ptr->cmt, 0);
|
||||
}
|
||||
|
||||
// Perform the final pass of analysis even for the binary files
|
||||
if ( inf_get_filetype() == f_BIN )
|
||||
inf_set_af(inf_get_af() | AF_FINAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_oldfile:
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
// make the default DS point to INTMEM
|
||||
{
|
||||
segment_t *newseg = va_arg(va, segment_t *);
|
||||
segment_t *intseg = getseg(INTMEMBASE);
|
||||
if ( intseg != NULL )
|
||||
newseg->defsr[rDS-ph.reg_first_sreg] = intseg->sel;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
{
|
||||
processor_subtype_t prcnum = processor_subtype_t(va_arg(va, int));
|
||||
// bool keep_cfg = va_argi(va, bool);
|
||||
ptype = prcnum;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_mnem(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
xa_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
xa_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 *);
|
||||
xa_segstart(*ctx, seg);
|
||||
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_out_data:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
bool analyze_only = va_argi(va, bool);
|
||||
xa_data(*ctx, analyze_only);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_switch:
|
||||
{
|
||||
switch_info_t *si = va_arg(va, switch_info_t *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return xa_is_switch(si, *insn) ? 1 : 0;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
xa_create_func(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 = xa_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);
|
||||
xa_stkvar_def(*ctx, mptr, v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_align_insn:
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
return xa_align_insn(ea);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
// Definitions of the target assemblers
|
||||
// 8051 has unusually many of them.
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// XA Assembler by Macraigor Systems
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t xaasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0,
|
||||
UAS_PBIT | UAS_SECT,
|
||||
"XA Macro Assembler dummy entry",
|
||||
0,
|
||||
NULL, // no headers
|
||||
"org",
|
||||
"end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
"db", // ascii string directive
|
||||
"db", // byte directive
|
||||
"dw", // word directive
|
||||
"long", // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
"#d dup(#v)", // arrays (#h,#d,#v,#s(...)
|
||||
"ds %s", // uninited arrays
|
||||
"reg", // equ
|
||||
NULL, // seg prefix
|
||||
"$",
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
"align", // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"not", // not
|
||||
"shl", // shl
|
||||
"shr", // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &xaasm, NULL };
|
||||
//-----------------------------------------------------------------------
|
||||
// The short and long names of the supported processors
|
||||
#define FAMILY "Philips 51XA Series:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"51XA-G3",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Philips 51XA G3",
|
||||
NULL
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Opcodes of "return" instructions. This information will be used in 2 ways:
|
||||
// - if an instruction has the "return" opcode, its autogenerated label
|
||||
// will be "locret" rather than "loc".
|
||||
// - IDA will use the first "return" opcode to create empty subroutines.
|
||||
|
||||
static const uchar retcode_1[] = { 0xd6, 0x80 };
|
||||
static const uchar retcode_2[] = { 0xd6, 0x90 };
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
#define PLFM_XA 0x8051
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_XA, // id
|
||||
// flag
|
||||
PR_SEGS
|
||||
| PR_RNAMESOK // can use register names for byte names
|
||||
| PR_BINMEM, // The module creates RAM/ROM segments for binary files
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // array of short processor names
|
||||
// the short names are used to specify the processor
|
||||
// with the -p command line switch)
|
||||
lnames, // array of long processor names
|
||||
// the long names are used to build the processor type
|
||||
// selection menu
|
||||
|
||||
asms, // array of target assemblers
|
||||
|
||||
notify, // the kernel event notification callback
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rCS,rES,
|
||||
1, // size of a segment register
|
||||
rCS,rDS,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0,XA_last,
|
||||
Instructions, // instruc
|
||||
0, // tbyte_size
|
||||
{0,0,0,0}, // real_width
|
||||
XA_ret, // icode_return
|
||||
NULL // DEPREECATED: is_align_insn
|
||||
|
||||
,};
|
||||
127
idasdk76/module/xa/xa.hpp
Normal file
127
idasdk76/module/xa/xa.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#ifndef _XA_HPP
|
||||
#define _XA_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// customization of the insn_t structure:
|
||||
|
||||
// XA bit references:
|
||||
|
||||
#define o_bit o_idpspec0
|
||||
#define o_bitnot o_idpspec1
|
||||
|
||||
// fRi and other indirect register number (for o_phrase):
|
||||
#define indreg specflag1
|
||||
|
||||
// ash.uflag bit meanings:
|
||||
|
||||
#define UAS_PSAM 0x0001 // PseudoSam: use funny form of
|
||||
// equ for intmem
|
||||
#define UAS_SECT 0x0002 // Segments are named .SECTION
|
||||
#define UAS_NOSEG 0x0004 // No 'segment' directives
|
||||
#define UAS_NOBIT 0x0008 // No bit.# names, use bit_#
|
||||
#define UAS_SELSG 0x0010 // Segment should be selected by its name
|
||||
#define UAS_EQCLN 0x0020 // ':' in EQU directives
|
||||
#define UAS_AUBIT 0x0040 // Don't use BIT directives -
|
||||
// assembler generates bit names itself
|
||||
#define UAS_CDSEG 0x0080 // Only DSEG,CSEG,XSEG
|
||||
#define UAS_NODS 0x0100 // No .DS directives in Code segment
|
||||
#define UAS_NOENS 0x0200 // don't specify start addr in the .end directive
|
||||
#define UAS_PBIT 0x0400 // assembler knows about predefined bits
|
||||
#define UAS_PBYTNODEF 0x0800 // do not define predefined byte names
|
||||
|
||||
enum processor_subtype_t
|
||||
{
|
||||
// odd types are binary mode
|
||||
// even types are source modes
|
||||
prc_xaG3 = 0, // XAG3
|
||||
};
|
||||
|
||||
struct predefined_t;
|
||||
struct xa_t : public procmod_t
|
||||
{
|
||||
processor_subtype_t ptype;
|
||||
bool flow = false; // does the current instruction pass
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void attach_bit_comment(const insn_t &insn, int addr, int bit) const;
|
||||
const predefined_t *GetPredefined(const predefined_t *ptr, int addr, int bit) const;
|
||||
const predefined_t *GetPredefinedBits(int addr, int bit) const;
|
||||
static int IsPredefined(const char *name);
|
||||
|
||||
void xa_header(outctx_t &ctx);
|
||||
void xa_footer(outctx_t &ctx);
|
||||
void xa_segstart(outctx_t &ctx, segment_t *seg);
|
||||
|
||||
int ana(insn_t *insn);
|
||||
|
||||
int emu(const insn_t &insn);
|
||||
void handle_operand(insn_t &insn, const op_t &x, bool loading);
|
||||
|
||||
void xa_data(outctx_t &ctx, bool analyze_only);
|
||||
static bool xa_create_func(func_t *pfn);
|
||||
static bool xa_is_switch(switch_info_t *si, const insn_t &insn);
|
||||
static int xa_frame_retsize(const func_t *pfn);
|
||||
static void xa_stkvar_def(outctx_t &ctx, const member_t *mptr, sval_t v);
|
||||
static int xa_align_insn(ea_t ea);
|
||||
};
|
||||
|
||||
#define INTMEMBASE (2L << 24)
|
||||
#define SFRBASE (INTMEMBASE + 0x400)
|
||||
#define EXTRAMBASE (1L << 24)
|
||||
|
||||
inline ea_t map_addr(ea_t off)
|
||||
{
|
||||
return ((off >= 0x800) ? EXTRAMBASE : INTMEMBASE) + off;
|
||||
}
|
||||
|
||||
#define DS 0x441
|
||||
#define ES 0x442
|
||||
#define CS 0x443
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Registers
|
||||
enum xa_registers
|
||||
{
|
||||
rR0L, rR0H, rR1L, rR1H, rR2L, rR2H, rR3L, rR3H, rR4L, rR4H,
|
||||
rR5L, rR5H, rR6L, rR6H, rR7L, rR7H,
|
||||
rR0, rR1, rR2, rR3, rR4, rR5, rR6, rR7,
|
||||
rR8, rR9, rR10, rR11, rR12, rR13, rR14, rR15,
|
||||
rA, rDPTR, rC, rPC, rUSP,
|
||||
rCS, rDS, rES
|
||||
};
|
||||
|
||||
// Indirect addressing modes without a displacement:
|
||||
enum xa_phrases
|
||||
{
|
||||
fAdptr, // [A+DPTR]
|
||||
fApc, // [A+PC]
|
||||
fRi, // [Ri], reg number in indreg
|
||||
fRii, // [[Ri]], reg number in indreg
|
||||
fRip, // [Ri+], reg number in indreg
|
||||
fRipi, // [[Ri+]], reg number in indreg
|
||||
fRid8, // [Ri+d8], reg number in indreg
|
||||
fRid16, // [Ri+d16], reg number in indreg
|
||||
fRlistL, // PUSH/POP list of registers lower half
|
||||
fRlistH, // PUSH/POP upper half of registers
|
||||
};
|
||||
|
||||
|
||||
// The predefined locations
|
||||
struct predefined_t
|
||||
{
|
||||
uchar proc;
|
||||
uint16 addr;
|
||||
uchar bit;
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user