This commit is contained in:
olari
2021-06-05 21:10:25 +03:00
parent 807cffd9de
commit e0e0f2be99
923 changed files with 911857 additions and 15 deletions

View 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 &reg, 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;
}

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

View 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 &reg, 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

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

View 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

View 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

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

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