/* * Interactive disassembler (IDA) * Copyright (c) 1990-98 by Ilfak Guilfanov. * E-mail: ig@datarescue.com * PDP11 module. * Copyright (c) 1995-2006 by Iouri Kharon. * E-mail: yjh@styx.cabel.net * * ALL RIGHTS RESERVED. * */ #include "pdp.hpp" //------------------------------------------------------------------------ void pdp11_t::loadR0data(const insn_t &insn, const op_t *x, int sme) { if ( insn.Op2.type == o_void ) { if ( insn.itype != pdp_clr ) goto undefdat; if ( sme ) { if ( !insn.bytecmd ) goto undefdat; emuR0data.b[1] = 0; return; } if ( insn.bytecmd ) emuR0data.b[0] = 0; else emuR0data.w = 0; return; } if ( x != &insn.Op2 ) return; if ( insn.Op1.type == o_imm ) { if ( insn.itype == pdp_mov ) { if ( !insn.bytecmd ) { if ( sme ) goto undefdat; emuR0data.w = (ushort)insn.Op1.value; return; } if ( !sme ) emuR0data.b[0] = (uchar)insn.Op1.value; else emuR0data.b[1] = (uchar)insn.Op1.value; return; } if ( !insn.bytecmd ) goto undefdat; undefbyt: if ( !sme ) emuR0data.b[0] = 0xFF; else emuR0data.b[1] = 0xFF; return; } if ( insn.bytecmd ) goto undefbyt; undefdat: emuR0data.w = 0xFFFF; } //------------------------------------------------------------------------ void pdp11_t::handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload) { ea_t jmpa; switch ( x.type ) { case o_near: // Jcc/ [jmp/call 37/67] case o_mem: // 37/67/77 case o_far: jmpa = x.type == o_far ? to_ea(x.segval, x.addr16) : map_code_ea(insn, x.addr16, x.n); if ( x.phrase == 0 ) { insn.add_cref(jmpa, x.offb, fl_JN); // Jcc break; } extxref: if ( (x.phrase & 070) == 070 ) goto xrefset; if ( insn.itype == pdp_jmp ) insn.add_cref(jmpa, x.offb, fl_JF); else if ( insn.itype == pdp_jsr || insn.itype == pdp_call ) { insn.add_cref(jmpa, x.offb, fl_CF); if ( !func_does_return(jmpa) ) flow = false; } else { xrefset: insn.create_op_data(jmpa, x); insn.add_dref(jmpa, x.offb, isload ? dr_R : dr_W); } break; case o_displ: // 6x/7x (!67/!77) set_immd(insn.ea); if ( !isload && x.phrase == (060 + rR0) && x.addr16 <= 1 ) loadR0data(insn, &x, x.addr16); if ( !is_forced && is_off(get_flags(insn.ea), x.n) && (jmpa = get_offbase(insn.ea, x.n)) != BADADDR ) { jmpa += x.addr16; goto extxref; } break; case o_imm: // 27 if ( !x.ill_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_number: // EMT/TRAP/MARK/SPL if ( insn.itype == pdp_emt && get_cmt(NULL, insn.ea, false) <= 0 ) { insn_t tmp = insn; op_t &tmpx = tmp.ops[x.n]; if ( tmpx.value >= 0374 && tmpx.value <= 0375 ) { tmp.Op2.value = (tmpx.value == 0375) ? emuR0data.b[1] : (emuR0 >> 8); tmp.Op2.type = o_imm; } qstring qbuf; if ( get_predef_insn_cmt(&qbuf, tmp) > 0 ) set_cmt(tmp.ea, qbuf.c_str(), false); } break; case o_reg: // 0 if ( x.reg == rR0 ) { if ( insn.Op2.type == o_void ) // one operand insn { if ( insn.itype != pdp_clr ) goto undefall; if ( insn.bytecmd ) emuR0 &= 0xFF00; else emuR0 = 0; goto undefdata; } if ( &x == &insn.Op2 ) { if ( insn.itype != pdp_mov ) { if ( insn.bytecmd ) { emuR0 |= 0xFF; goto undefdata; } goto undefall; } if ( insn.bytecmd ) goto undefall; if ( insn.Op1.type == o_imm ) { if ( (emuR0 = (ushort)insn.Op1.value) & 1 ) goto undefdata; emuR0data.w = get_word(to_ea(insn.cs, emuR0)); } else { undefall: emuR0 = 0xFFFF; undefdata: emuR0data.w = 0xFFFF; } } } break; case o_phrase: // 1x/2x/3x/4x/5x (!27/!37) if ( (x.phrase & 7) == rR0 ) { if ( !isload && x.phrase == (010 + rR0) ) loadR0data(insn, &x, 0); else if ( insn.Op2.type == o_void || &x == &insn.Op2 ) goto undefall; } case o_fpreg: // FPP break; default: warning("%" FMT_EA "o (%s): bad optype %d", insn.ip, insn.get_canon_mnem(ph), x.type); break; } } //---------------------------------------------------------------------- int pdp11_t::emu(const insn_t &insn) { bool flag1 = is_forced_operand(insn.ea, 0); bool flag2 = is_forced_operand(insn.ea, 1); uint32 Feature = insn.get_canon_feature(ph); flow = (Feature & CF_STOP) == 0; if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, flag1, true); if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, flag2, true); if ( Feature & CF_JUMP ) remember_problem(PR_JUMP, insn.ea); if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, flag1, false); if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, flag2, false); ea_t newEA = insn.ea + insn.size; if ( insn.itype == pdp_emt && insn.Op1.value == 0376 ) { create_byte(newEA, 2); goto prompt2; } else if ( flow && !(insn.itype == pdp_emt && insn.Op1.value == 0350) ) { if ( insn.Op1.type == o_imm && insn.Op1.ill_imm ) newEA += 2; if ( insn.Op2.type == o_imm && insn.Op2.ill_imm ) { prompt2: newEA += 2; } add_cref(insn.ea, newEA, fl_F); } return 1; }