update
This commit is contained in:
597
idasdk75/module/80196/ana.cpp
Normal file
597
idasdk75/module/80196/ana.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct wsr_mapping_t
|
||||
{
|
||||
ushort base;
|
||||
uchar wsr;
|
||||
uchar wsrbase;
|
||||
uchar wsr1base;
|
||||
};
|
||||
|
||||
static const wsr_mapping_t mappings[] =
|
||||
{
|
||||
{ 0x0000, 0x10, 0x80, 0xFF }, // 0080-00FF
|
||||
{ 0x0080, 0x11, 0x80, 0xFF },
|
||||
{ 0x0100, 0x12, 0x80, 0xFF },
|
||||
{ 0x0180, 0x13, 0x80, 0xFF },
|
||||
{ 0x0200, 0x14, 0x80, 0xFF },
|
||||
{ 0x0280, 0x15, 0x80, 0xFF },
|
||||
{ 0x0300, 0x16, 0x80, 0xFF },
|
||||
{ 0x0380, 0x17, 0x80, 0xFF },
|
||||
{ 0x1F00, 0x1E, 0x80, 0xFF },
|
||||
{ 0x1F80, 0x1F, 0x80, 0xFF },
|
||||
{ 0x0000, 0x20, 0xC0, 0x40 }, // 00C0-00FF or 0040-007F
|
||||
{ 0x0040, 0x21, 0xC0, 0x40 },
|
||||
{ 0x0080, 0x22, 0xC0, 0x40 },
|
||||
{ 0x00C0, 0x23, 0xC0, 0x40 },
|
||||
{ 0x0100, 0x24, 0xC0, 0x40 },
|
||||
{ 0x0140, 0x25, 0xC0, 0x40 },
|
||||
{ 0x0180, 0x26, 0xC0, 0x40 },
|
||||
{ 0x01C0, 0x27, 0xC0, 0x40 },
|
||||
{ 0x0200, 0x28, 0xC0, 0x40 },
|
||||
{ 0x0240, 0x29, 0xC0, 0x40 },
|
||||
{ 0x0280, 0x2A, 0xC0, 0x40 },
|
||||
{ 0x02C0, 0x2B, 0xC0, 0x40 },
|
||||
{ 0x0300, 0x2C, 0xC0, 0x40 },
|
||||
{ 0x0340, 0x2D, 0xC0, 0x40 },
|
||||
{ 0x0380, 0x2E, 0xC0, 0x40 },
|
||||
{ 0x03C0, 0x2F, 0xC0, 0x40 },
|
||||
{ 0x1F00, 0x3C, 0xC0, 0x40 },
|
||||
{ 0x1F40, 0x3D, 0xC0, 0x40 },
|
||||
{ 0x1F80, 0x3E, 0xC0, 0x40 },
|
||||
{ 0x1FC0, 0x3F, 0xC0, 0x40 },
|
||||
{ 0x0000, 0x40, 0xE0, 0x60 }, // 00E0-00FF or 0060-007F
|
||||
{ 0x0020, 0x41, 0xE0, 0x60 },
|
||||
{ 0x0040, 0x42, 0xE0, 0x60 },
|
||||
{ 0x0060, 0x43, 0xE0, 0x60 },
|
||||
{ 0x0080, 0x44, 0xE0, 0x60 },
|
||||
{ 0x00A0, 0x45, 0xE0, 0x60 },
|
||||
{ 0x00C0, 0x46, 0xE0, 0x60 },
|
||||
{ 0x00E0, 0x47, 0xE0, 0x60 },
|
||||
{ 0x0100, 0x48, 0xE0, 0x60 },
|
||||
{ 0x0120, 0x49, 0xE0, 0x60 },
|
||||
{ 0x0140, 0x4A, 0xE0, 0x60 },
|
||||
{ 0x0160, 0x4B, 0xE0, 0x60 },
|
||||
{ 0x0180, 0x4C, 0xE0, 0x60 },
|
||||
{ 0x01A0, 0x4D, 0xE0, 0x60 },
|
||||
{ 0x01C0, 0x4E, 0xE0, 0x60 },
|
||||
{ 0x01E0, 0x4F, 0xE0, 0x60 },
|
||||
{ 0x0200, 0x50, 0xE0, 0x60 },
|
||||
{ 0x0220, 0x51, 0xE0, 0x60 },
|
||||
{ 0x0240, 0x52, 0xE0, 0x60 },
|
||||
{ 0x0260, 0x53, 0xE0, 0x60 },
|
||||
{ 0x0280, 0x54, 0xE0, 0x60 },
|
||||
{ 0x02A0, 0x55, 0xE0, 0x60 },
|
||||
{ 0x02C0, 0x56, 0xE0, 0x60 },
|
||||
{ 0x02E0, 0x57, 0xE0, 0x60 },
|
||||
{ 0x0300, 0x58, 0xE0, 0x60 },
|
||||
{ 0x0320, 0x59, 0xE0, 0x60 },
|
||||
{ 0x0340, 0x5A, 0xE0, 0x60 },
|
||||
{ 0x0360, 0x5B, 0xE0, 0x60 },
|
||||
{ 0x0380, 0x5C, 0xE0, 0x60 },
|
||||
{ 0x03A0, 0x5D, 0xE0, 0x60 },
|
||||
{ 0x03C0, 0x5E, 0xE0, 0x60 },
|
||||
{ 0x03E0, 0x5F, 0xE0, 0x60 },
|
||||
{ 0x1F00, 0x78, 0xE0, 0x60 },
|
||||
{ 0x1F20, 0x79, 0xE0, 0x60 },
|
||||
{ 0x1F40, 0x7A, 0xE0, 0x60 },
|
||||
{ 0x1F60, 0x7B, 0xE0, 0x60 },
|
||||
{ 0x1F80, 0x7C, 0xE0, 0x60 },
|
||||
{ 0x1FA0, 0x7D, 0xE0, 0x60 },
|
||||
{ 0x1FC0, 0x7E, 0xE0, 0x60 },
|
||||
{ 0x1FE0, 0x7F, 0xE0, 0x60 },
|
||||
};
|
||||
|
||||
static int NT_CDECL cmp(const void *x, const void *y)
|
||||
{
|
||||
const wsr_mapping_t *a = (const wsr_mapping_t *)x;
|
||||
const wsr_mapping_t *b = (const wsr_mapping_t *)y;
|
||||
return a->wsr - b->wsr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// perform WSR/WSR1 mapping
|
||||
ea_t i196_t::map(ea_t iea, ea_t v) const
|
||||
{
|
||||
if ( !extended )
|
||||
return v;
|
||||
if ( v < 0x40 )
|
||||
return v;
|
||||
sel_t wsr = get_sreg(iea, v < 0x80 ? WSR1 : WSR) & 0x7F;
|
||||
if ( wsr < 0x10 )
|
||||
return v;
|
||||
|
||||
wsr_mapping_t key;
|
||||
key.wsr = (char)wsr;
|
||||
wsr_mapping_t *p = (wsr_mapping_t *)
|
||||
bsearch(&key, mappings, qnumber(mappings), sizeof(key), cmp);
|
||||
if ( p == NULL )
|
||||
return v;
|
||||
|
||||
int delta = v < 0x80 ? p->wsr1base : p->wsrbase;
|
||||
if ( v < delta )
|
||||
return v;
|
||||
return v - delta + p->base;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void i196_t::aop(insn_t &insn, uint code, op_t &op)
|
||||
{
|
||||
switch ( code & 3 )
|
||||
{
|
||||
case 0: // direct
|
||||
op.type = o_mem;
|
||||
op.addr = map(insn.ea, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
case 1: // immediate
|
||||
op.type = o_imm;
|
||||
if ( (code & 0x10) == 0 && (code & 0xFC) != 0xAC ) // ldbze always baop
|
||||
{
|
||||
op.dtype = dt_word;
|
||||
op.value = insn.get_next_word();
|
||||
}
|
||||
else
|
||||
{
|
||||
op.value = insn.get_next_byte();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // indirect
|
||||
op.dtype = dt_word;
|
||||
op.addr = insn.get_next_byte();
|
||||
op.type = (op.addr & 1) ? o_indirect_inc : o_indirect;
|
||||
op.addr = map(insn.ea, op.addr & ~1);
|
||||
break;
|
||||
|
||||
case 3: // indexed
|
||||
op.dtype = dt_word;
|
||||
op.type = o_indexed;
|
||||
op.value = insn.get_next_byte(); // short (reg file)
|
||||
op.addr = (op.value & 1) ? insn.get_next_word() : insn.get_next_byte();
|
||||
op.value = map(insn.ea, op.value & ~1);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int i196_t::ld_st(insn_t &insn, ushort itype, char dtype, bool indirect, op_t ®, op_t &mem)
|
||||
{
|
||||
if ( !extended )
|
||||
return 0;
|
||||
insn.itype = itype;
|
||||
reg.dtype = dtype;
|
||||
mem.dtype = dtype;
|
||||
mem.addr = insn.get_next_byte();
|
||||
if ( indirect ) // indirect
|
||||
{
|
||||
mem.type = (mem.addr & 1) ? o_indirect_inc : o_indirect;
|
||||
mem.addr = map(insn.ea, mem.addr & ~1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mem.type = o_indexed;
|
||||
mem.value = map(insn.ea, mem.addr);
|
||||
mem.addr = insn.get_next_word();
|
||||
mem.addr |= insn.get_next_byte() << 16;
|
||||
}
|
||||
reg.type = o_mem;
|
||||
reg.addr = map(insn.ea, insn.get_next_byte());
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int i196_t::ana(insn_t *_insn)
|
||||
{
|
||||
if ( _insn == NULL )
|
||||
return 0;
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op2.dtype = dt_byte;
|
||||
insn.Op3.dtype = dt_byte;
|
||||
|
||||
uint code = insn.get_next_byte();
|
||||
|
||||
uint nibble0 = (code & 0xF);
|
||||
uint nibble1 = (code >> 4);
|
||||
|
||||
char offc;
|
||||
int32 off;
|
||||
uint tmp;
|
||||
|
||||
if ( nibble1 < 2 ) // 0,1
|
||||
{
|
||||
static const char cmd01[] =
|
||||
{
|
||||
I196_skip, I196_clr, I196_not, I196_neg,
|
||||
I196_xch, I196_dec, I196_ext, I196_inc,
|
||||
I196_shr, I196_shl, I196_shra, I196_xch,
|
||||
I196_shrl, I196_shll, I196_shral, I196_norml,
|
||||
I196_null, I196_clrb, I196_notb, I196_negb,
|
||||
I196_xchb, I196_decb, I196_extb, I196_incb,
|
||||
I196_shrb, I196_shlb, I196_shrab, I196_xchb,
|
||||
I196_est, I196_est, I196_estb, I196_estb
|
||||
};
|
||||
|
||||
insn.itype = cmd01[code & 0x1F];
|
||||
|
||||
if ( insn.itype == I196_null )
|
||||
return 0; // unknown instruction
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0x4: case 0x14: //xch reg,aop direct
|
||||
case 0xB: case 0x1B: //xch reg,aop indexed
|
||||
if ( (code & 0x10) == 0 )
|
||||
insn.Op2.dtype = dt_word;
|
||||
aop(insn, code, insn.Op2);
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
case 0xF: //norml lreg,breg
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
case 0x1C: // est.indirect
|
||||
case 0x1D: // est.indexed
|
||||
return ld_st(insn, I196_est, dt_word, code == 0x1C, insn.Op1, insn.Op2);
|
||||
|
||||
case 0x1E: // estb.indirect
|
||||
case 0x1F: // estb.indexed
|
||||
return ld_st(insn, I196_estb, dt_byte, code == 0x1E, insn.Op1, insn.Op2);
|
||||
|
||||
default: // shifts
|
||||
tmp = insn.get_next_byte();
|
||||
if ( tmp < 16 )
|
||||
{
|
||||
insn.Op2.value = tmp;
|
||||
insn.Op2.type = o_imm;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op2.addr = map(insn.ea, tmp);
|
||||
insn.Op2.type = o_mem;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case 0x0: case 0x1: case 0x2: case 0x3:
|
||||
case 0x5: case 0x6: case 0x7: case 0x11:
|
||||
case 0x12: case 0x13: case 0x15: case 0x16: case 0x17:
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
}
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0x1: case 0x2: case 0x3: case 0x4: case 0x5:
|
||||
case 0x7: case 0x8: case 0x9: case 0xA: case 0xB: case 0x16:
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
|
||||
case 0x6: case 0xC: case 0xD: case 0xE: case 0xF:
|
||||
insn.Op1.dtype = dt_dword;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( nibble1 < 4 ) // 2,3
|
||||
{
|
||||
static const char cmd23[] = { I196_sjmp, I196_scall, I196_jbc, I196_jbs };
|
||||
|
||||
insn.itype = cmd23[ ((code - 0x20) >> 3) & 3 ];
|
||||
|
||||
if ( nibble1 == 2 ) // sjmp/scall
|
||||
{
|
||||
insn.Op1.type = o_near;
|
||||
off = insn.get_next_byte() + ((code & 7) << 8);
|
||||
if ( off & 0x400 )
|
||||
off |= ~0x7FF;
|
||||
else
|
||||
off &= 0x7FF; // make signed
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off); // signed addition
|
||||
// insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else // jbc/jbs
|
||||
{
|
||||
insn.Op2.type = o_bit;
|
||||
insn.Op2.reg = code & 7;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op3.type = o_near;
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op3.addr = truncate(insn.ip + insn.size + offc); // signed addition
|
||||
// insn.Op3.dtype = dt_word;
|
||||
}
|
||||
}
|
||||
else if ( nibble1 < 6 ) // 4,5
|
||||
{
|
||||
static const char cmd45[] =
|
||||
{
|
||||
I196_and3, I196_add3, I196_sub3, I196_mulu3,
|
||||
I196_andb3, I196_addb3, I196_subb3, I196_mulub3
|
||||
};
|
||||
|
||||
insn.itype = cmd45[ ((code - 0x40) >> 2) & 7 ];
|
||||
|
||||
if ( (code & 0x10) == 0 )
|
||||
insn.Op1.dtype = insn.Op2.dtype = insn.Op3.dtype = dt_word;
|
||||
|
||||
if ( (code & 0xc) == 0xc ) // mulu/mulub
|
||||
insn.Op1.dtype++; // word->dword/byte->word
|
||||
|
||||
aop(insn, code, insn.Op3);
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
}
|
||||
else if ( nibble1 < 0xD ) // 6,7,8,9,A,B,C
|
||||
{
|
||||
static const char cmd6c[] =
|
||||
{
|
||||
I196_and2, I196_add2, I196_sub2, I196_mulu2,
|
||||
I196_andb2, I196_addb2, I196_subb2, I196_mulub2,
|
||||
I196_or, I196_xor, I196_cmp, I196_divu,
|
||||
I196_orb, I196_xorb, I196_cmpb, I196_divub,
|
||||
I196_ld, I196_addc, I196_subc, I196_ldbze,
|
||||
I196_ldb, I196_addcb, I196_subcb, I196_ldbse,
|
||||
I196_st, I196_stb, I196_push, I196_pop,
|
||||
I196_null, I196_null, I196_null, I196_null,
|
||||
};
|
||||
|
||||
insn.itype = cmd6c[ ((code - 0x60) >> 2) & 31 ];
|
||||
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 6: // and/add/sub/mulu
|
||||
case 8: // or/xor/cmp/duvu
|
||||
insn.Op1.dtype = insn.Op2.dtype = dt_word;
|
||||
if ( (nibble0 & 0xC) == 0xC )
|
||||
insn.Op1.dtype++; //mulu/divu
|
||||
break;
|
||||
|
||||
case 0xA: // ld/addc/subc/ldbze
|
||||
insn.Op1.dtype = insn.Op2.dtype = dt_word;
|
||||
if ( (nibble0 & 0xC) == 0xC )
|
||||
insn.Op2.dtype = dt_byte; //ldbze
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( code & 0xFC )
|
||||
{
|
||||
case 0xC0: // st
|
||||
insn.Op2.dtype = dt_word;
|
||||
|
||||
case 0x7C: case 0x9C: case 0xBC: case 0xC8: case 0xCC:
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0xC1:
|
||||
insn.itype = I196_bmov;
|
||||
goto cont1;
|
||||
|
||||
case 0xC5:
|
||||
insn.itype = I196_cmpl;
|
||||
insn.Op2.dtype = dt_dword;
|
||||
goto cont2;
|
||||
|
||||
case 0xCD:
|
||||
insn.itype = I196_bmovi;
|
||||
cont1:
|
||||
insn.Op2.dtype = dt_word;
|
||||
cont2:
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.dtype = dt_dword;
|
||||
// insn.Op1.addr = insn.get_next_byte();
|
||||
// insn.Op1.type = o_mem;
|
||||
goto cont3;
|
||||
|
||||
default:
|
||||
if ( code > 0xC7 )
|
||||
{
|
||||
aop(insn, code, insn.Op1);
|
||||
}
|
||||
else
|
||||
{
|
||||
aop(insn, code, insn.Op2);
|
||||
cont3:
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( nibble1 == 0xD ) // jcc
|
||||
{
|
||||
static const char cmdd[] =
|
||||
{
|
||||
I196_jnst, I196_jnh, I196_jgt, I196_jnc,
|
||||
I196_jnvt, I196_jnv, I196_jge, I196_jne,
|
||||
I196_jst, I196_jh, I196_jle, I196_jc,
|
||||
I196_jvt, I196_jv, I196_jlt, I196_je
|
||||
};
|
||||
|
||||
insn.itype = cmdd[nibble0];
|
||||
|
||||
insn.Op1.type = o_near;
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + offc); // signed addition
|
||||
// insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else if ( nibble1 == 0xE ) // Ex
|
||||
{
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 0x0: case 0x1: // djnz, djnzw
|
||||
if ( nibble0 & 1 )
|
||||
{
|
||||
insn.itype = I196_djnzw;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = I196_djnz;
|
||||
}
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op2.type = o_near;
|
||||
insn.Op2.addr = truncate(insn.ip + insn.size + offc); // signed addition
|
||||
break;
|
||||
|
||||
case 0x2: // tijmp
|
||||
insn.itype = I196_tijmp;
|
||||
insn.Op1.dtype = insn.Op2.dtype = dt_word;
|
||||
insn.Op2.type = o_indirect;
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op3.type = o_imm;
|
||||
insn.Op3.value = insn.get_next_byte();
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
case 0x3: // br
|
||||
insn.itype = extended ? I196_ebr : I196_br;
|
||||
aop(insn, 2, insn.Op1);
|
||||
break;
|
||||
|
||||
case 0x4: // ebmovi
|
||||
if ( !extended )
|
||||
return 0;
|
||||
insn.itype = I196_ebmovi;
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
case 0x6: // ejmp
|
||||
if ( !extended )
|
||||
return 0;
|
||||
insn.itype = I196_ejmp;
|
||||
insn.Op1.type = o_near;
|
||||
off = insn.get_next_word();
|
||||
off |= int32(insn.get_next_byte()) << 16;
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off); // signed addition
|
||||
break;
|
||||
|
||||
case 0x8: // eld.indirect
|
||||
case 0x9: // eld.indexed
|
||||
return ld_st(insn, I196_eld, dt_word, nibble0 == 0x8, insn.Op1, insn.Op2);
|
||||
|
||||
case 0xA: // eldb.indirect
|
||||
case 0xB: // eldb.indexed
|
||||
return ld_st(insn, I196_eldb, dt_byte, nibble0 == 0xA, insn.Op1, insn.Op2);
|
||||
|
||||
case 0xC: // dpts
|
||||
insn.itype = I196_dpts;
|
||||
break;
|
||||
|
||||
case 0xD: // epts
|
||||
insn.itype = I196_epts;
|
||||
break;
|
||||
|
||||
case 0x7: case 0xF: // ljmp, lcall
|
||||
insn.itype = (nibble0 & 8) ? I196_lcall : I196_ljmp;
|
||||
insn.Op1.type = o_near;
|
||||
off = short(insn.get_next_word());
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off); // signed addition
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char cmdf[] =
|
||||
{
|
||||
I196_ret, I196_ecall,I196_pushf, I196_popf,
|
||||
I196_pusha, I196_popa, I196_idlpd, I196_trap,
|
||||
I196_clrc, I196_setc, I196_di, I196_ei,
|
||||
I196_clrvt, I196_nop, I196_null, I196_rst
|
||||
};
|
||||
|
||||
insn.itype = cmdf[nibble0];
|
||||
if ( nibble0 == 1 ) // ecall
|
||||
{
|
||||
if ( !extended )
|
||||
return 0;
|
||||
off = insn.get_next_word();
|
||||
off |= int32(insn.get_next_byte()) << 16;
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off);
|
||||
}
|
||||
else if ( nibble0 == 6 ) // idlpd
|
||||
{
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
}
|
||||
else if ( nibble0 == 0xE ) // prefix
|
||||
{
|
||||
code = insn.get_next_byte();
|
||||
|
||||
switch ( code & 0xFC )
|
||||
{
|
||||
case 0x4C: case 0x5C:
|
||||
if ( code & 0x10 )
|
||||
{
|
||||
insn.itype = I196_mulb3;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = I196_mul3;
|
||||
insn.Op3.dtype = insn.Op2.dtype = dt_word;
|
||||
insn.Op1.dtype = dt_dword;
|
||||
}
|
||||
|
||||
aop(insn, code, insn.Op3);
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
case 0x6C: case 0x7C: case 0x8C: case 0x9C:
|
||||
insn.itype = (code & 0x80)
|
||||
? (code & 0x10) ? I196_divb : I196_div
|
||||
: (code & 0x10) ? I196_mulb2 : I196_mul2;
|
||||
|
||||
if ( code & 0x10 )
|
||||
{
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = dt_dword;
|
||||
insn.Op2.dtype = dt_word;
|
||||
}
|
||||
|
||||
aop(insn, code, insn.Op2);
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return insn.size;
|
||||
}
|
||||
92
idasdk75/module/80196/emu.cpp
Normal file
92
idasdk75/module/80196/emu.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void i196_t::handle_operand(const insn_t &insn, const op_t &x, int isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
set_immd(insn.ea);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, OOF_SIGNED);
|
||||
break;
|
||||
case o_indexed: // addr[value]
|
||||
set_immd(insn.ea);
|
||||
if ( x.value == 0 && !is_defarg(get_flags(insn.ea), x.n) )
|
||||
op_plain_offset(insn.ea, x.n, to_ea(insn.cs, 0));
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) ) // xref to addr
|
||||
{
|
||||
insn_t tmp = insn;
|
||||
tmp.ops[x.n].value = x.addr;
|
||||
tmp.add_off_drefs(tmp.ops[x.n], x.value ? dr_O : isload ? dr_R : dr_W, OOF_SIGNED|OOF_ADDR);
|
||||
}
|
||||
if ( x.value != 0 ) // xref to value
|
||||
{ // no references to ZERO_REG
|
||||
ea_t ea = to_ea(insn.cs, x.value);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_indirect:
|
||||
case o_indirect_inc:
|
||||
case o_mem:
|
||||
{
|
||||
ea_t dea = to_ea(insn.cs, x.addr);
|
||||
insn.create_op_data(dea, x);
|
||||
insn.add_dref(dea, x.offb, isload ? dr_R : dr_W);
|
||||
if ( !isload && (x.addr == 0x14 || x.addr == 0x15) )
|
||||
{
|
||||
sel_t wsrval = BADSEL;
|
||||
if ( insn.Op2.type == o_imm )
|
||||
wsrval = sel_t(insn.Op2.value);
|
||||
split_sreg_range(insn.ea, x.addr == 0x14 ? WSR : WSR1, wsrval, SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
int iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
|
||||
if ( flow && iscall )
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int i196_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, 1);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, 1);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, 1);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, 0);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, 0);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, 0);
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I196_popa:
|
||||
split_sreg_range(insn.ea, WSR, BADSEL, SR_auto);
|
||||
split_sreg_range(insn.ea, WSR1, BADSEL, SR_auto);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
63
idasdk75/module/80196/i196.hpp
Normal file
63
idasdk75/module/80196/i196.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I196_HPP
|
||||
#define _I196_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <segregs.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// customization of cmd structure:
|
||||
|
||||
#define o_indirect o_idpspec0 // [addr]
|
||||
#define o_indirect_inc o_idpspec1 // [addr]+
|
||||
#define o_indexed o_idpspec2 // addr[value]
|
||||
#define o_bit o_idpspec3
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
enum i196_registers { rVcs, rVds, WSR, WSR1 };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uchar addr;
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
} predefined_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void idaapi i196_header(outctx_t &ctx);
|
||||
void idaapi i196_footer(outctx_t &ctx);
|
||||
|
||||
void idaapi i196_segend(outctx_t &ctx, segment_t *seg);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct i196_t : public procmod_t
|
||||
{
|
||||
int extended = 0;
|
||||
int flow = false;
|
||||
|
||||
inline uint32 truncate(ea_t x)
|
||||
{
|
||||
return x & (extended ? 0xFFFFF : 0xFFFF);
|
||||
}
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
ea_t map(ea_t iea, ea_t v) const;
|
||||
void aop(insn_t &insn, uint code, op_t &op);
|
||||
int ld_st(insn_t &insn, ushort itype, char dtype, bool indirect, op_t ®, op_t &mem);
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &x, int isload);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void i196_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
180
idasdk75/module/80196/ins.cpp
Normal file
180
idasdk75/module/80196/ins.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
{ "add", CF_USE2|CF_USE1|CF_CHG1 }, // Add words (2 operands)
|
||||
{ "add", CF_USE3|CF_USE2|CF_CHG1 }, // Add words (3 operands)
|
||||
{ "addb", CF_USE2|CF_USE1|CF_CHG1 }, // Add bytes (2 operands)
|
||||
{ "addb", CF_USE3|CF_USE2|CF_CHG1 }, // Add bytes (3 operands)
|
||||
|
||||
{ "addc", CF_USE2|CF_USE1|CF_CHG1 }, // Add words with carry
|
||||
{ "addcb", CF_USE2|CF_USE1|CF_CHG1 }, // Add bytes with carry
|
||||
|
||||
{ "and", CF_USE2|CF_USE1|CF_CHG1 }, // Logical AND words (2 operands)
|
||||
{ "and", CF_USE3|CF_USE2|CF_CHG1 }, // Logical AND words (3 operands)
|
||||
{ "andb", CF_USE2|CF_USE1|CF_CHG1 }, // Logical AND bytes (2 operands)
|
||||
{ "andb", CF_USE3|CF_USE2|CF_CHG1 }, // Logical AND bytes (3 operands)
|
||||
|
||||
{ "bmov", CF_USE2|CF_USE1 }, // Block move
|
||||
{ "bmovi", CF_USE2|CF_USE1 }, // Interruptable block move
|
||||
|
||||
{ "br", CF_JUMP|CF_USE1|CF_STOP }, // Branch indirect
|
||||
|
||||
{ "clr", CF_CHG1 }, // Clear word
|
||||
{ "clrb", CF_CHG1 }, // Clear byte
|
||||
{ "clrc", 0 }, // Clear carry flag
|
||||
{ "clrvt", 0 }, // Clear overflow-trap flag
|
||||
|
||||
{ "cmp", CF_USE2|CF_USE1 }, // Compare words
|
||||
{ "cmpb", CF_USE2|CF_USE1 }, // Compare bytes
|
||||
{ "cmpl", CF_USE2|CF_USE1 }, // Compare long
|
||||
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // Decrement word
|
||||
{ "decb", CF_USE1|CF_CHG1 }, // Decrement byte
|
||||
|
||||
{ "di", 0 }, // Disable interrupts
|
||||
|
||||
{ "div", CF_USE2|CF_USE1|CF_CHG1 }, // Divide integers
|
||||
{ "divb", CF_USE2|CF_USE1|CF_CHG1 }, // Divide short-integers
|
||||
{ "divu", CF_USE2|CF_USE1|CF_CHG1 }, // Divide words, unsigned
|
||||
{ "divub", CF_USE2|CF_USE1|CF_CHG1 }, // Divide bytes, unsigned
|
||||
|
||||
{ "djnz", CF_USE2|CF_USE1|CF_CHG1 }, // Decrement and jump if not zero
|
||||
{ "djnzw", CF_USE2|CF_USE1|CF_CHG1 }, // Decrement and jump if not zero word
|
||||
|
||||
{ "dpts", 0 }, // Disable peripheral transaction server
|
||||
|
||||
{ "ei", 0 }, // Enable interrupts
|
||||
|
||||
{ "epts", 0 }, // Enable peripheral transaction server
|
||||
|
||||
{ "ext", CF_USE1|CF_CHG1 }, // Sign-extend integer into long-integer
|
||||
{ "extb", CF_USE1|CF_CHG1 }, // Sign-extend short-integer into integer
|
||||
|
||||
{ "idlpd", CF_USE1 }, // Idle/powerdown
|
||||
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // Increment word
|
||||
{ "incb", CF_USE1|CF_CHG1 }, // Increment byte
|
||||
|
||||
{ "jbc", CF_USE3|CF_USE2|CF_USE1 }, // Jump if bit is clear
|
||||
{ "jbs", CF_USE3|CF_USE2|CF_USE1 }, // Jump if bit is set
|
||||
{ "jc", CF_USE1 }, // Jump if carry flag is set
|
||||
{ "je", CF_USE1 }, // Jump if equal
|
||||
{ "jge", CF_USE1 }, // Jump if signed greater than or equal
|
||||
{ "jgt", CF_USE1 }, // Jump if signed greater than
|
||||
{ "jh", CF_USE1 }, // Jump if higher (unsigned)
|
||||
{ "jle", CF_USE1 }, // Jump if signed less than or equal
|
||||
{ "jlt", CF_USE1 }, // Jump if signed less than
|
||||
{ "jnc", CF_USE1 }, // Jump if carry flag is clear
|
||||
{ "jne", CF_USE1 }, // Jump if not equal
|
||||
{ "jnh", CF_USE1 }, // Jump if not higher (unsigned)
|
||||
{ "jnst", CF_USE1 }, // Jump if sticky bit flag is clear
|
||||
{ "jnv", CF_USE1 }, // Jump if overflow flag is clear
|
||||
{ "jnvt", CF_USE1 }, // Jump if overflow-trap flag is clear
|
||||
{ "jst", CF_USE1 }, // Jump if sticky bit flag is set
|
||||
{ "jv", CF_USE1 }, // Jump if overflow flag is set
|
||||
{ "jvt", CF_USE1 }, // Jump if overflow-trap flag is set
|
||||
|
||||
{ "lcall", CF_USE1|CF_CALL }, // Long call
|
||||
|
||||
{ "ld", CF_USE2|CF_CHG1 }, // Load word
|
||||
{ "ldb", CF_USE2|CF_CHG1 }, // Load byte
|
||||
{ "ldbse", CF_USE2|CF_CHG1 }, // Load byte sign-extended
|
||||
{ "ldbze", CF_USE2|CF_CHG1 }, // Load byte zero-extended
|
||||
|
||||
{ "ljmp", CF_USE1|CF_STOP }, // Long jump
|
||||
|
||||
{ "mul", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply integers (2 operands)
|
||||
{ "mul", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply integers (3 operands)
|
||||
{ "mulb", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply short-integers (2 operands)
|
||||
{ "mulb", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply short-integers (3 operands)
|
||||
{ "mulu", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply words, unsigned (2 operands)
|
||||
{ "mulu", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply words, unsigned (3 operands)
|
||||
{ "mulub", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply bytes, unsigned (2 operands)
|
||||
{ "mulub", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply bytes, unsigned (3 operands)
|
||||
|
||||
{ "neg", CF_USE1|CF_CHG1 }, // Negate integer
|
||||
{ "negb", CF_USE1|CF_CHG1 }, // Negate short-integer
|
||||
|
||||
{ "nop", 0 }, // No operation
|
||||
|
||||
{ "norml", CF_USE1|CF_CHG2|CF_CHG1 }, // Normalize long-integer
|
||||
|
||||
{ "not", CF_USE1|CF_CHG1 }, // Complement word
|
||||
{ "notb", CF_USE1|CF_CHG1 }, // Complement byte
|
||||
|
||||
{ "or", CF_USE2|CF_USE1|CF_CHG1 }, // Logical OR words
|
||||
{ "orb", CF_USE2|CF_USE1|CF_CHG1 }, // Logical OR bytes
|
||||
|
||||
{ "pop", CF_CHG1 }, // Pop word
|
||||
{ "popa", 0 }, // Pop all
|
||||
{ "popf", 0 }, // Pop flags
|
||||
{ "push", CF_USE1 }, // Push word
|
||||
{ "pusha", 0 }, // Push all
|
||||
{ "pushf", 0 }, // Push flags
|
||||
|
||||
{ "ret", CF_STOP }, // Return from subroutine
|
||||
|
||||
{ "rst", CF_STOP }, // Reset system
|
||||
|
||||
{ "scall", CF_USE1|CF_CALL }, // Short call
|
||||
|
||||
{ "setc", 0 }, // Set carry flag
|
||||
|
||||
{ "shl", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Shift word left
|
||||
{ "shlb", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Shift byte left
|
||||
{ "shll", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Shift double-word left
|
||||
{ "shr", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Logical right shift word
|
||||
{ "shra", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Arithmetic right shift word
|
||||
{ "shrab", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Arithmetic right shift byte
|
||||
{ "shral", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Arithmetic right shift double-word
|
||||
{ "shrb", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Logical right shift byte
|
||||
{ "shrl", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Logical right shift double-word
|
||||
|
||||
{ "sjmp", CF_USE1|CF_STOP }, // Short jump
|
||||
|
||||
{ "skip", CF_USE1 }, // Two byte no-operation
|
||||
|
||||
{ "st", CF_USE1|CF_CHG2 }, // Store word
|
||||
{ "stb", CF_USE1|CF_CHG2 }, // Store byte
|
||||
|
||||
{ "sub", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract words (2 operands)
|
||||
{ "sub", CF_USE3|CF_USE2|CF_CHG1 }, // Subtract words (3 operands)
|
||||
{ "subb", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract bytes (2 operands)
|
||||
{ "subb", CF_USE3|CF_USE2|CF_CHG1 }, // subtract bytes (3 operands)
|
||||
|
||||
{ "subc", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract words with borrow
|
||||
{ "subcb", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract bytes with borrow
|
||||
|
||||
{ "tijmp", CF_JUMP|CF_USE3|CF_USE2|CF_USE1|CF_STOP }, // Table indirect jump
|
||||
|
||||
{ "trap", 0 }, // Software trap
|
||||
|
||||
{ "xch", CF_USE2|CF_USE1|CF_CHG2|CF_CHG1 }, // Exchange word
|
||||
{ "xchb", CF_USE2|CF_USE1|CF_CHG2|CF_CHG1 }, // Exchange byte
|
||||
|
||||
{ "xor", CF_USE2|CF_USE1|CF_CHG1 }, // Logical exclusive-or words
|
||||
{ "xorb", CF_USE2|CF_USE1|CF_CHG1 }, // Logical exclusive-or bytes
|
||||
|
||||
// 8x196NU, NP instructions
|
||||
|
||||
{ "ebmovi", CF_USE1|CF_USE2 }, // Extended interruptable block move
|
||||
{ "ebr", CF_USE1|CF_STOP }, // Extended branch indirect
|
||||
{ "ecall", CF_USE1|CF_CALL }, // Extended call
|
||||
{ "ejmp", CF_USE1|CF_STOP }, // Extended jump
|
||||
{ "eld", CF_CHG1|CF_USE2 }, // Extended load word
|
||||
{ "eldb", CF_CHG1|CF_USE2 }, // Extended load byte
|
||||
{ "est", CF_USE1|CF_CHG2 }, // Extended store word
|
||||
{ "estb", CF_USE1|CF_CHG2 }, // Extended store byte
|
||||
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == I196_last);
|
||||
184
idasdk75/module/80196/ins.hpp
Normal file
184
idasdk75/module/80196/ins.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
I196_null = 0, // Unknown Operation
|
||||
|
||||
I196_add2, // Add words (2 operands)
|
||||
I196_add3, // Add words (3 operands)
|
||||
I196_addb2, // Add bytes (2 operands)
|
||||
I196_addb3, // Add bytes (3 operands)
|
||||
|
||||
I196_addc, // Add words with carry
|
||||
I196_addcb, // Add bytes with carry
|
||||
|
||||
I196_and2, // Logical AND words (2 operands)
|
||||
I196_and3, // Logical AND words (3 operands)
|
||||
I196_andb2, // Logical AND bytes (2 operands)
|
||||
I196_andb3, // Logical AND bytes (3 operands)
|
||||
|
||||
I196_bmov, // Block move
|
||||
I196_bmovi, // Interruptable block move
|
||||
|
||||
I196_br, // Branch indirect
|
||||
|
||||
I196_clr, // Clear word
|
||||
I196_clrb, // Clear byte
|
||||
I196_clrc, // Clear carry flag
|
||||
I196_clrvt, // Clear overflow-trap flag
|
||||
|
||||
I196_cmp, // Compare words
|
||||
I196_cmpb, // Compare bytes
|
||||
I196_cmpl, // Compare long
|
||||
|
||||
I196_dec, // Decrement word
|
||||
I196_decb, // Decrement byte
|
||||
|
||||
I196_di, // Disable interrupts
|
||||
|
||||
I196_div, // Divide integers
|
||||
I196_divb, // Divide short-integers
|
||||
I196_divu, // Divide words, unsigned
|
||||
I196_divub, // Divide bytes, unsigned
|
||||
|
||||
I196_djnz, // Decrement and jump if not zero
|
||||
I196_djnzw, // Decrement and jump if not zero word
|
||||
|
||||
I196_dpts, // Disable peripheral transaction server
|
||||
|
||||
I196_ei, // Enable interrupts
|
||||
|
||||
I196_epts, // Enable peripheral transaction server
|
||||
|
||||
I196_ext, // Sign-extend integer into long-integer
|
||||
I196_extb, // Sign-extend short-integer into integer
|
||||
|
||||
I196_idlpd, // Idle/powerdown
|
||||
|
||||
I196_inc, // Increment word
|
||||
I196_incb, // Increment byte
|
||||
|
||||
I196_jbc, // Jump if bit is clear
|
||||
I196_jbs, // Jump if bit is set
|
||||
I196_jc, // Jump if carry flag is set
|
||||
I196_je, // Jump if equal
|
||||
I196_jge, // Jump if signed greater than or equal
|
||||
I196_jgt, // Jump if signed greater than
|
||||
I196_jh, // Jump if higher (unsigned)
|
||||
I196_jle, // Jump if signed less than or equal
|
||||
I196_jlt, // Jump if signed less than
|
||||
I196_jnc, // Jump if carry flag is clear
|
||||
I196_jne, // Jump if not equal
|
||||
I196_jnh, // Jump if not higher (unsigned)
|
||||
I196_jnst, // Jump if sticky bit flag is clear
|
||||
I196_jnv, // Jump if overflow flag is clear
|
||||
I196_jnvt, // Jump if overflow-trap flag is clear
|
||||
I196_jst, // Jump if sticky bit flag is set
|
||||
I196_jv, // Jump if overflow flag is set
|
||||
I196_jvt, // Jump if overflow-trap flag is set
|
||||
|
||||
I196_lcall, // Long call
|
||||
|
||||
I196_ld, // Load word
|
||||
I196_ldb, // Load byte
|
||||
I196_ldbse, // Load byte sign-extended
|
||||
I196_ldbze, // Load byte zero-extended
|
||||
|
||||
I196_ljmp, // Long jump
|
||||
|
||||
I196_mul2, // Multiply integers (2 operands)
|
||||
I196_mul3, // Multiply integers (3 operands)
|
||||
I196_mulb2, // Multiply short-integers (2 operands)
|
||||
I196_mulb3, // Multiply short-integers (3 operands)
|
||||
I196_mulu2, // Multiply words, unsigned (2 operands)
|
||||
I196_mulu3, // Multiply words, unsigned (3 operands)
|
||||
I196_mulub2, // Multiply bytes, unsigned (2 operands)
|
||||
I196_mulub3, // Multiply bytes, unsigned (3 operands)
|
||||
|
||||
I196_neg, // Negate integer
|
||||
I196_negb, // Negate short-integer
|
||||
|
||||
I196_nop, // No operation
|
||||
|
||||
I196_norml, // Normalize long-integer
|
||||
|
||||
I196_not, // Complement word
|
||||
I196_notb, // Complement byte
|
||||
|
||||
I196_or, // Logical OR words
|
||||
I196_orb, // Logical OR bytes
|
||||
|
||||
I196_pop, // Pop word
|
||||
I196_popa, // Pop all
|
||||
I196_popf, // Pop flags
|
||||
I196_push, // Push word
|
||||
I196_pusha, // Push all
|
||||
I196_pushf, // Push flags
|
||||
|
||||
I196_ret, // Return from subroutine
|
||||
|
||||
I196_rst, // Reset system
|
||||
|
||||
I196_scall, // Short call
|
||||
|
||||
I196_setc, // Set carry flag
|
||||
|
||||
I196_shl, // Shift word left
|
||||
I196_shlb, // Shift byte left
|
||||
I196_shll, // Shift double-word left
|
||||
I196_shr, // Logical right shift word
|
||||
I196_shra, // Arithmetic right shift word
|
||||
I196_shrab, // Arithmetic right shift byte
|
||||
I196_shral, // Arithmetic right shift double-word
|
||||
I196_shrb, // Logical right shift byte
|
||||
I196_shrl, // Logical right shift double-word
|
||||
|
||||
I196_sjmp, // Short jump
|
||||
|
||||
I196_skip, // Two byte no-operation
|
||||
|
||||
I196_st, // Store word
|
||||
I196_stb, // Store byte
|
||||
|
||||
I196_sub2, // Subtract words (2 operands)
|
||||
I196_sub3, // Subtract words (3 operands)
|
||||
I196_subb2, // Subtract bytes (2 operands)
|
||||
I196_subb3, // subtract bytes (3 operands)
|
||||
|
||||
I196_subc, // Subtract words with borrow
|
||||
I196_subcb, // Subtract bytes with borrow
|
||||
|
||||
I196_tijmp, // Table indirect jump
|
||||
|
||||
I196_trap, // Software trap
|
||||
|
||||
I196_xch, // Exchange word
|
||||
I196_xchb, // Exchange byte
|
||||
|
||||
I196_xor, // Logical exclusive-or words
|
||||
I196_xorb, // Logical exclusive-or bytes
|
||||
|
||||
// 8x196NU, NP instructions
|
||||
|
||||
I196_ebmovi, // Extended interruptable block move
|
||||
I196_ebr, // Extended branch indirect
|
||||
I196_ecall, // Extended call
|
||||
I196_ejmp, // Extended jump
|
||||
I196_eld, // Extended load word
|
||||
I196_eldb, // Extended load byte
|
||||
I196_est, // Extended store word
|
||||
I196_estb, // Extended store byte
|
||||
|
||||
I196_last
|
||||
};
|
||||
|
||||
#endif
|
||||
40
idasdk75/module/80196/makefile
Normal file
40
idasdk75/module/80196/makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
PROC=i196
|
||||
|
||||
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)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 ana.cpp i196.hpp ins.hpp
|
||||
$(F)emu$(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)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 emu.cpp i196.hpp ins.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)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 i196.hpp ins.cpp ins.hpp
|
||||
$(F)out$(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)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 i196.hpp ins.hpp out.cpp
|
||||
$(F)reg$(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)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 i196.hpp ins.hpp reg.cpp
|
||||
168
idasdk75/module/80196/out.cpp
Normal file
168
idasdk75/module/80196/out.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_i196_t : public outctx_t
|
||||
{
|
||||
out_i196_t(void) = delete; // not used
|
||||
public:
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_i196_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_i196_t)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi i196_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_PROC_AND_ASM);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi i196_footer(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void i196_t::i196_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, Sarea);
|
||||
ctx.gen_cmt_line(COLSTR("segment %s", SCOLOR_AUTOCMT), name.c_str());
|
||||
|
||||
ea_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);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(818, seg) could be made const
|
||||
void idaapi i196_segend(outctx_t &ctx, segment_t *seg)
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, seg);
|
||||
ctx.gen_cmt_line("end of '%s'", name.c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_i196_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
out_one_operand(0);
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool is_ext_insn(const insn_t &insn)
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I196_ebmovi: // Extended interruptable block move
|
||||
case I196_ebr: // Extended branch indirect
|
||||
case I196_ecall: // Extended call
|
||||
case I196_ejmp: // Extended jump
|
||||
case I196_eld: // Extended load word
|
||||
case I196_eldb: // Extended load byte
|
||||
case I196_est: // Extended store word
|
||||
case I196_estb: // Extended store byte
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_i196_t::out_operand(const op_t &x)
|
||||
{
|
||||
uval_t v, v1;
|
||||
// const char *ptr;
|
||||
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, OOF_SIGNED | OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_indexed:
|
||||
out_value(x, OOF_ADDR|OOF_SIGNED|(is_ext_insn(insn) ? OOFW_32 : OOFW_16)); //.addr
|
||||
v = x.value;
|
||||
out_symbol('[');
|
||||
if ( v != 0 )
|
||||
goto OUTPHRASE;
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_indirect:
|
||||
case o_indirect_inc:
|
||||
out_symbol('[');
|
||||
// fallthrough
|
||||
|
||||
case o_mem:
|
||||
case o_near:
|
||||
v = x.addr;
|
||||
OUTPHRASE:
|
||||
v1 = to_ea(get_sreg(insn.ea, (x.type == o_near) ? rVcs : rVds), v);
|
||||
if ( !out_name_expr(x, v1, v ) )
|
||||
{
|
||||
out_value(x, (x.type == o_indexed ? 0 : OOF_ADDR)
|
||||
| OOF_NUMBER|OOFS_NOSIGN
|
||||
| (x.type == o_near
|
||||
? (is_ext_insn(insn) ? OOFW_32 : OOFW_16)
|
||||
: OOFW_8));
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
|
||||
if ( x.type == o_indirect
|
||||
|| x.type == o_indirect_inc
|
||||
|| x.type == o_indexed )
|
||||
{
|
||||
out_symbol(']');
|
||||
if ( x.type == o_indirect_inc )
|
||||
out_symbol('+');
|
||||
}
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_bit:
|
||||
out_symbol(char('0' + x.reg));
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
500
idasdk75/module/80196/reg.cpp
Normal file
500
idasdk75/module/80196/reg.cpp
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const predefined_t iregs[] =
|
||||
{
|
||||
{ 0x00, "ZERO_REG", "Zero register" },
|
||||
{ 0x08, "INT_MASK", "Interrupt mask register" },
|
||||
{ 0x09, "INT_PEND", "Interrupt pending register" },
|
||||
{ 0x0F, "IOPORT1", "Input/output port 1" },
|
||||
{ 0x10, "IOPORT2", "Input/output port 2" },
|
||||
{ 0x12, "INT_PEND1", "Interrupt pending register 1" },
|
||||
{ 0x13, "INT_MASK1", "Interrupt mask register 1" },
|
||||
{ 0x14, "WSR", "Window selection register" },
|
||||
{ 0x15, "WSR1", "Window selection register 1" },
|
||||
{ 0x18, "SP", "Stack pointer" },
|
||||
{ 0x00, NULL, NULL }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/* 80196 memory map
|
||||
*
|
||||
* 0000-03FF - register file
|
||||
* 0000 - CPU SFRs
|
||||
* 0018 - SP (LO)
|
||||
* 0019 - SP (HI)
|
||||
* 001A - Register RAM
|
||||
* 0100 - Register RAM (upper file)
|
||||
* 0400-1FFD - ext memory
|
||||
* 1FFE - port 3 (word)
|
||||
* 1FFF - port 4 (word)
|
||||
* 2000-207F - special purpose memory
|
||||
* 2000 - lower int vectors
|
||||
* 2000 - INT00 - Timer overflow
|
||||
* 2002 - INT01 - A/D conversion complete
|
||||
* 2004 - INT02 - HSI data available
|
||||
* 2006 - INT03 - High speed output
|
||||
* 2008 - INT04 - HSI.0
|
||||
* 200A - INT05 - Software timer
|
||||
* 200C - INT06 - Serial port
|
||||
* 200E - INT07 - EXTINT
|
||||
* 2010 - Software trap
|
||||
* 2012 - Unimplemented opcode
|
||||
* 2014 - reserved (FF)
|
||||
* 2018 - CCB
|
||||
* D0 - PD - Power down
|
||||
* D1 - BW0 - Bus width control
|
||||
* D2 - WR - Write strobe mode
|
||||
* D3 - ALE - Addres valid strobe mode
|
||||
* D45 - IRC - Internal ready control
|
||||
* D67 - LOC - Lock bits
|
||||
* 2019 - reserved (20)
|
||||
* 201A - reserved (FF)
|
||||
* 2020 - security key
|
||||
* 2030 - upper int vectors
|
||||
* 2030 - INT08 - Transmit
|
||||
* 2032 - INT09 - Receive
|
||||
* 2034 - INT10 - HSI FIFO 4
|
||||
* 2036 - INT11 - Timer 2 capture
|
||||
* 2038 - INT12 - Timer 2 overflow
|
||||
* 203A - INT13 - EXTINT1
|
||||
* 203C - INT14 - HSI FIFO FULL
|
||||
* 203E - INT15 - NMI
|
||||
* 2040 - PTS vectors
|
||||
* 2040 - INT00 - Timer overflow
|
||||
* 2042 - INT01 - A/D conversion complete
|
||||
* 2044 - INT02 - HSI data available
|
||||
* 2046 - INT03 - High speed output
|
||||
* 2048 - INT04 - HSI.0
|
||||
* 204A - INT05 - Software timer
|
||||
* 204C - INT06 - Serial port
|
||||
* 204E - INT07 - EXTINT
|
||||
* 2050 - INT08 - Transmit
|
||||
* 2052 - INT09 - Receive
|
||||
* 2054 - INT10 - HSI FIFO 4
|
||||
* 2056 - INT11 - Timer 2 capture
|
||||
* 2058 - INT12 - Timer 2 overflow
|
||||
* 205A - INT13 - EXTINT1
|
||||
* 205C - INT14 - HSI FIFO FULL
|
||||
* 205E - reserved (FF)
|
||||
* 2080-FFFF - program/ext memory
|
||||
*/
|
||||
|
||||
#define I196F_CMT 0 // global comment
|
||||
#define I196F_OFF 1 // offset to code
|
||||
#define I196F_BTS 2 // byte(s)
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
char type;
|
||||
int off; //lint !e958 padding is required to align members
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
};
|
||||
|
||||
static const char cmt01[] = "Timer overflow";
|
||||
static const char cmt02[] = "A/D conversion complete";
|
||||
static const char cmt03[] = "HSI data available";
|
||||
static const char cmt04[] = "High speed output";
|
||||
static const char cmt05[] = "HSI.0";
|
||||
static const char cmt06[] = "Software timer";
|
||||
static const char cmt07[] = "Serial port";
|
||||
static const char cmt08[] = "EXTINT";
|
||||
static const char cmt09[] = "reserved (FF)";
|
||||
static const char cmt10[] = "Transmit";
|
||||
static const char cmt11[] = "Receive";
|
||||
static const char cmt12[] = "HSI FIFO 4";
|
||||
static const char cmt13[] = "Timer 2 capture";
|
||||
static const char cmt14[] = "Timer 2 overflow";
|
||||
static const char cmt15[] = "EXTINT1";
|
||||
static const char cmt16[] = "HSI FIFO FULL";
|
||||
|
||||
static entry_t const entries[] =
|
||||
{
|
||||
//
|
||||
// { I196F_CMT, 0x2000, 0, "\nlower int vectors\n" },
|
||||
|
||||
{ I196F_OFF, 0x2000, "Int00", cmt01 },
|
||||
{ I196F_OFF, 0x2002, "Int01", cmt02 },
|
||||
{ I196F_OFF, 0x2004, "Int02", cmt03 },
|
||||
{ I196F_OFF, 0x2006, "Int03", cmt04 },
|
||||
{ I196F_OFF, 0x2008, "Int04", cmt05 },
|
||||
{ I196F_OFF, 0x200A, "Int05", cmt06 },
|
||||
{ I196F_OFF, 0x200C, "Int06", cmt07 },
|
||||
{ I196F_OFF, 0x200E, "Int07", cmt08 },
|
||||
{ I196F_OFF, 0x2010, "Trap", "Software trap" },
|
||||
{ I196F_OFF, 0x2012, "NoOpCode", "Unimplemented opcode" },
|
||||
|
||||
{ I196F_CMT, 0x2014, 0, 0 }, // empty line
|
||||
|
||||
{ I196F_BTS, 0x2014, 0, cmt09 },
|
||||
{ I196F_BTS, 0x2018, "CCB", "D0 - PD - Power down\n"
|
||||
"D1 - BW0 - Bus width control\n"
|
||||
"D2 - WR - Write strobe mode\n"
|
||||
"D3 - ALE - Addres valid strobe mode\n"
|
||||
"D45 - IRC - Internal ready control\n"
|
||||
"D67 - LOC - Lock bits" },
|
||||
{ I196F_BTS, 0x2019, 0, "reserved (20)" },
|
||||
{ I196F_BTS, 0x201A, 0, cmt09 },
|
||||
{ I196F_BTS, 0x2020, 0, "security key" },
|
||||
|
||||
{ I196F_CMT, 0x2030, 0, "\nupper int vectors\n" },
|
||||
|
||||
{ I196F_OFF, 0x2030, "Int08", cmt10 },
|
||||
{ I196F_OFF, 0x2032, "Int09", cmt11 },
|
||||
{ I196F_OFF, 0x2034, "Int10", cmt12 },
|
||||
{ I196F_OFF, 0x2036, "Int11", cmt13 },
|
||||
{ I196F_OFF, 0x2038, "Int12", cmt14 },
|
||||
{ I196F_OFF, 0x203A, "Int13", cmt15 },
|
||||
{ I196F_OFF, 0x203C, "Int14", cmt16 },
|
||||
{ I196F_OFF, 0x203E, "Int15", "NMI" },
|
||||
|
||||
{ I196F_CMT, 0x2040, 0, "\nPTS vectors\n" },
|
||||
|
||||
{ I196F_OFF, 0x2040, "PTS_Int00", cmt01 },
|
||||
{ I196F_OFF, 0x2042, "PTS_Int01", cmt02 },
|
||||
{ I196F_OFF, 0x2044, "PTS_Int02", cmt03 },
|
||||
{ I196F_OFF, 0x2046, "PTS_Int03", cmt04 },
|
||||
{ I196F_OFF, 0x2048, "PTS_Int04", cmt05 },
|
||||
{ I196F_OFF, 0x204A, "PTS_Int05", cmt06 },
|
||||
{ I196F_OFF, 0x204C, "PTS_Int06", cmt07 },
|
||||
{ I196F_OFF, 0x204E, "PTS_Int07", cmt08 },
|
||||
{ I196F_OFF, 0x2050, "PTS_Int08", cmt10 },
|
||||
{ I196F_OFF, 0x2052, "PTS_Int09", cmt11 },
|
||||
{ I196F_OFF, 0x2054, "PTS_Int10", cmt12 },
|
||||
{ I196F_OFF, 0x2056, "PTS_Int11", cmt13 },
|
||||
{ I196F_OFF, 0x2058, "PTS_Int12", cmt14 },
|
||||
{ I196F_OFF, 0x205A, "PTS_Int13", cmt15 },
|
||||
{ I196F_OFF, 0x205C, "PTS_Int14", cmt16 },
|
||||
|
||||
{ I196F_CMT, 0x205E, 0, 0 },
|
||||
|
||||
{ I196F_BTS, 0x205E, 0, cmt09 },
|
||||
|
||||
// { I196F_CMT, 0x2080, 0, "\nProgram entry point\n" },
|
||||
|
||||
{ I196F_CMT, 0x2080, 0, 0 }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] = { "cs", "ds", "WSR", "WSR1" };
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static bool idaapi can_have_type(const op_t &x) // returns 1 - operand can have
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
case o_reg:
|
||||
case o_indirect:
|
||||
case o_indirect_inc:
|
||||
case o_bit:
|
||||
case o_mem:
|
||||
case o_near:
|
||||
return 0;
|
||||
// case o_phrase: can have type because of ASI or 0 struct offsets
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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 i196_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi i196_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
// if necessary, add to ida.cfg:
|
||||
// #ifdef __80196__
|
||||
// DUMMY_NAMES_TYPE = NM_SHORT
|
||||
// #endif
|
||||
|
||||
segment_t *sptr = get_first_seg();
|
||||
if ( sptr != NULL )
|
||||
set_segm_class(sptr, "CODE");
|
||||
|
||||
ea_t ea, ea1;
|
||||
|
||||
for ( int i = 0; i < qnumber(entries); i++ )
|
||||
{
|
||||
ea = to_ea(inf_get_baseaddr(), entries[i].off);
|
||||
|
||||
if ( is_mapped(ea) )
|
||||
{
|
||||
switch ( entries[i].type )
|
||||
{
|
||||
case I196F_BTS:
|
||||
if ( i < qnumber(entries)-1 )
|
||||
{
|
||||
create_byte(ea, entries[i+1].off-entries[i].off);
|
||||
set_cmt(ea, entries[i].cmt, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case I196F_CMT:
|
||||
if ( entries[i].cmt != NULL )
|
||||
add_extra_cmt(ea, true, "%s", entries[i].cmt);
|
||||
else
|
||||
add_extra_line(ea, true, "");
|
||||
break;
|
||||
|
||||
case I196F_OFF:
|
||||
create_word(ea, 2);
|
||||
op_plain_offset(ea, 0, to_ea(inf_get_baseaddr(), 0));
|
||||
|
||||
ea1 = to_ea(inf_get_baseaddr(), get_word(ea));
|
||||
auto_make_proc(ea1);
|
||||
// add a simple comment
|
||||
// after function is created, it will be converted
|
||||
// to function comment
|
||||
set_cmt(ea1, entries[i].cmt, 1);
|
||||
}
|
||||
|
||||
set_name(ea, entries[i].name, SN_NODUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
ea = to_ea(inf_get_baseaddr(), 0x2080);
|
||||
if ( is_mapped(ea) )
|
||||
{
|
||||
inf_set_start_ea(ea);
|
||||
inf_set_start_ip(0x2080);
|
||||
}
|
||||
|
||||
segment_t s;
|
||||
s.start_ea = to_ea(inf_get_baseaddr(), 0);
|
||||
s.end_ea = to_ea(inf_get_baseaddr(), 0x400);
|
||||
s.sel = inf_get_baseaddr();
|
||||
s.type = SEG_IMEM; // internal memory
|
||||
add_segm_ex(&s, "INTMEM", NULL, ADDSEG_OR_DIE);
|
||||
|
||||
const predefined_t *ptr;
|
||||
for ( ptr = iregs; ptr->name != NULL; ptr++ )
|
||||
{
|
||||
ea = to_ea(inf_get_baseaddr(), ptr->addr);
|
||||
ea_t oldea = get_name_ea(BADADDR, ptr->name);
|
||||
if ( oldea != ea )
|
||||
{
|
||||
if ( oldea != BADADDR )
|
||||
set_name(oldea, NULL);
|
||||
del_items(ea, DELIT_EXPAND);
|
||||
set_name(ea, ptr->name, SN_NODUMMY);
|
||||
}
|
||||
if ( ptr->cmt != NULL )
|
||||
set_cmt(ea, ptr->cmt, 1);
|
||||
}
|
||||
}
|
||||
// create_16bit_data(0x18, 2); // SP always word
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
// default DS is equal to Base Address
|
||||
{
|
||||
segment_t *sg = va_arg(va, segment_t *);
|
||||
sg->defsr[rVds-ph.reg_first_sreg] = inf_get_baseaddr();
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
// restore ptype
|
||||
extended = ph.get_proc_index();
|
||||
goto SETFLAG;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
extended = va_arg(va,int) != 0;
|
||||
SETFLAG:
|
||||
if ( !extended )
|
||||
ph.flag &= ~PR_SEGS;
|
||||
else
|
||||
ph.flag |= PR_SEGS;
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
i196_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
i196_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 *);
|
||||
i196_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
i196_segend(*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_can_have_type:
|
||||
{
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return can_have_type(*op) ? 1 : -1;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Could not find a standard assembler for this CPU :(
|
||||
static const asm_t unkasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0,
|
||||
0,
|
||||
"Abstract Assembler",
|
||||
0,
|
||||
NULL,
|
||||
"org",
|
||||
"end",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\0', // char delimiter (no char consts)
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
"db", // ascii string directive
|
||||
"db", // byte directive
|
||||
"dw", // word directive
|
||||
"dd", // 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
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
"ds %s", // uninited arrays
|
||||
"equ", // Equ
|
||||
NULL, // seg prefix
|
||||
"$",
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
"and", // and
|
||||
"or", // or
|
||||
NULL, // xor
|
||||
"not", // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
"SIZE", // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &unkasm, NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#define FAMILY "Intel 196 series:"
|
||||
static const char *const shnames[] = { "80196", "80196NP", NULL };
|
||||
static const char *const lnames[] = { FAMILY"Intel 80196", "Intel 80196NP", NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcode[] = { 0xF0 }; // ret
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode), retcode },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_80196, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_USE32
|
||||
| PR_SEGS
|
||||
| PR_BINMEM
|
||||
| PR_RNAMESOK,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // short processor names (null term)
|
||||
lnames, // long processor names (null term)
|
||||
|
||||
asms, // array of enabled assemblers
|
||||
|
||||
notify, // Various messages:
|
||||
|
||||
RegNames, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs,WSR1,
|
||||
2, // size of a segment register
|
||||
rVcs,rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0, I196_last,
|
||||
Instructions, // instruc
|
||||
};
|
||||
Reference in New Issue
Block a user