/* * 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" //---------------------------------------------------------------------- static void loadoper(insn_t &insn, op_t *Op, uint16 nibble) { ushort base; switch ( nibble ) { case 027: { flags_t F1 = get_flags(insn.ea); flags_t F2 = get_flags(insn.ea+insn.size); Op->type = o_imm; Op->ill_imm = is_head(F1) ? !is_tail(F2) : is_head(F2); Op->offb = (uchar)insn.size; Op->value = insn.get_next_word(); } break; case 037: case 077: case 067: Op->type = o_mem; Op->offb = (uchar)insn.size; base = insn.get_next_word(); if ( (Op->phrase = nibble) != 037 ) base += (short)(insn.ip + insn.size); Op->addr16 = base; break; default: if ( (nibble & 070) == 0 ) { Op->type = o_reg; Op->reg = nibble; } else { Op->phrase = nibble; if ( nibble < 060 ) { Op->type = o_phrase; } else { Op->type = o_displ; Op->offb = (uchar)insn.size; Op->addr16 = insn.get_next_word(); } } break; } } //---------------------------------------------------------------------- void pdp11_t::jmpoper(insn_t &insn, op_t *Op, uint16 nibble) { loadoper(insn, Op, nibble); if ( Op->type == o_mem && Op->phrase != 077 ) Op->type = o_near; if ( Op->type == o_near && Op->addr16 >= ml.ovrcallbeg && Op->addr16 <= ml.ovrcallend ) { uint32 trans = (uint32)ovrtrans.altval(Op->addr16); // msg("addr=%o, trans=%lo\n", Op->addr16, trans); if ( trans != 0 ) { segment_t *S = getseg(trans); if ( S != NULL ) { Op->type = o_far; Op->segval = (uint16)S->sel; Op->addr16 = (ushort)(trans - to_ea(Op->segval,0)); } } } } //---------------------------------------------------------------------- int pdp11_t::ana(insn_t *_insn) { insn_t &insn = *_insn; static const char twoop[5] = { pdp_mov, pdp_cmp, pdp_bit, pdp_bic, pdp_bis }; static const char onecmd[12] = { pdp_clr, pdp_com, pdp_inc, pdp_dec, pdp_neg, pdp_adc, pdp_sbc, pdp_tst, pdp_ror, pdp_rol, pdp_asr, pdp_asl }; static const char cc2com[8] = { pdp_bpl, pdp_bmi, pdp_bhi, pdp_blos, pdp_bvc, pdp_bvs, pdp_bcc, pdp_bcs }; if ( insn.ip & 1 ) return 0; insn.Op1.dtype = insn.Op2.dtype = dt_word; // insn.bytecmd = 0; uint code = insn.get_next_word(); uchar nibble0 = (code & 077); uchar nibble1 = (code >> 6 ) & 077; uchar nibble2 = (code >> 12) & 017; uchar nib1swt = nibble1 >> 3; switch ( nibble2 ) { case 017: if ( nibble1 == 0 ) { switch ( nibble0 ) { case 0: insn.itype = pdp_cfcc; break; case 1: insn.itype = pdp_setf; break; case 2: insn.itype = pdp_seti; break; case 011: insn.itype = pdp_setd; break; case 012: insn.itype = pdp_setl; break; default: return 0; } break; } loadoper(insn, &insn.Op1, nibble0); if ( nib1swt != 0 ) { static const char fpcom2[14] = { pdp_muld, pdp_modd, pdp_addd, pdp_ldd, pdp_subd, pdp_cmpd, pdp_std, pdp_divd, pdp_stexp, pdp_stcdi, pdp_stcdf, pdp_ldexp, pdp_ldcif, pdp_ldcfd }; insn.Op2.type = o_fpreg; insn.Op2.reg = (nibble1 & 3); insn.Op2.dtype = dt_double; int idx = (nibble1 >> 2) - 2; QASSERT(10084, idx >= 0 && idx < qnumber(fpcom2)); insn.itype = fpcom2[idx]; if ( insn.itype != pdp_ldexp && insn.itype != pdp_stexp ) { if ( insn.Op1.type == o_reg ) insn.Op1.type = o_fpreg; if ( insn.itype != pdp_stcdi && insn.itype != pdp_ldcif ) insn.Op1.dtype = dt_double; } if ( insn.itype == pdp_std || insn.itype == pdp_stexp || insn.itype == pdp_stcdi || insn.itype == pdp_stcdf ) { op_t temp; temp = insn.Op2; insn.Op2 = insn.Op1; insn.Op1 = temp; insn.Op1.n = 0; insn.Op2.n = 1; } } else { static const char fpcom1[7] = { pdp_ldfps, pdp_stfps, pdp_stst, pdp_clrd, pdp_tstd, pdp_absd, pdp_negd }; if ( nibble1 >= 4 ) { insn.Op1.dtype = insn.Op2.dtype = dt_double; if ( insn.Op1.type == o_reg ) insn.Op1.type = o_fpreg; } QASSERT(10085, (nibble1-1) >= 0 && nibble1-1 < qnumber(fpcom1)); insn.itype = fpcom1[nibble1 - 1]; //lint !e676 possibly indexing before the beginning of an allocation } break; case 7: switch ( nib1swt ) { case 6: // CIS return 0; case 5: // FIS { static const char ficom[4] = { pdp_fadd, pdp_fsub, pdp_fmul, pdp_fdiv }; if ( nibble1 != 050 || nibble0 >= 040 ) return 0; insn.Op1.type = o_reg; insn.Op1.reg = nibble0 & 7; insn.itype = ficom[nibble0 >> 3]; break; } case 7: // SOB insn.itype = pdp_sob; insn.Op1.type = o_reg; insn.Op1.reg = nibble1 & 7; insn.Op2.type = o_near; insn.Op2.phrase = 0; insn.Op2.addr16 = (ushort)(insn.ip + 2 - (2*nibble0)); break; default: { static const char eiscom[5] = { pdp_mul, pdp_div, pdp_ash, pdp_ashc, pdp_xor }; insn.Op2.type = o_reg; insn.Op2.reg = nibble1 & 7; loadoper(insn, &insn.Op1, nibble0); insn.itype = eiscom[nib1swt]; break; } } break; case 016: insn.itype = pdp_sub; goto twoopcmd; case 6: insn.itype = pdp_add; goto twoopcmd; default: // Normal 2 op insn.itype = twoop[(nibble2 & 7) - 1]; insn.bytecmd = ((nibble2 & 010) != 0); twoopcmd: loadoper(insn, &insn.Op1, nibble1); loadoper(insn, &insn.Op2, nibble0); break; case 010: if ( nibble1 >= 070 ) return 0; if ( nibble1 >= 064 ) { static const char mt1cmd[4] = { pdp_mtps, pdp_mfpd, pdp_mtpd, pdp_mfps }; insn.itype = mt1cmd[nibble1 - 064]; loadoper(insn, &insn.Op1, nibble0); break; } if ( nibble1 >= 050 ) { insn.bytecmd = 1; oneoper: loadoper(insn, &insn.Op1, nibble0); insn.itype = onecmd[nibble1 - 050]; break; } if ( nibble1 >= 040 ) { insn.Op1.type = o_number; // EMT/TRAP insn.Op1.value = code & 0377; insn.itype = (nibble1 >= 044) ? pdp_trap : pdp_emt; break; } insn.itype = cc2com[nibble1 >> 2]; condoper: insn.Op1.type = o_near; insn.Op1.phrase = 0; insn.Op1.addr16 = (ushort)(insn.ip + insn.size + (2*(short)((char)code))); break; case 0: if ( nibble1 >= 070 ) return 0; if ( nibble1 > 064 ) { static const char mt2cmd[3] = { pdp_mfpi, pdp_mtpi, pdp_sxt }; insn.itype = mt2cmd[nibble1 - 065]; loadoper(insn, &insn.Op1, nibble0); break; } if ( nibble1 == 064 ) { insn.itype = pdp_mark; insn.Op1.type = o_number; insn.Op1.value = nibble0; break; } if ( nibble1 >= 050 ) goto oneoper; if ( nibble1 >= 040 ) { if ( (nibble1 & 7) == 7 ) { insn.itype = pdp_call; jmpoper(insn, &insn.Op1, nibble0); } else { insn.itype = pdp_jsr; insn.Op1.type = o_reg; insn.Op1.reg = nibble1 & 7; jmpoper(insn, &insn.Op2, nibble0); } break; } switch ( nibble1 ) { case 3: insn.itype = pdp_swab; loadoper(insn, &insn.Op1, nibble0); break; case 1: insn.itype = pdp_jmp; jmpoper(insn, &insn.Op1, nibble0); break; case 2: if ( nibble0 == 7 ) { insn.itype = pdp_return; break; } if ( nibble0 < 7 ) { insn.itype = pdp_rts; insn.Op1.type = o_reg; insn.Op1.reg = nibble0; break; } if ( nibble0 < 030 ) return 0; if ( nibble0 < 040 ) { insn.itype = pdp_spl; insn.Op1.value = nibble0 & 7; insn.Op1.type = o_number; break; } switch ( nibble0 & 037 ) { case 000: insn.itype = pdp_nop; break; case 001: insn.itype = pdp_clc; break; case 002: insn.itype = pdp_clv; break; case 004: insn.itype = pdp_clz; break; case 010: insn.itype = pdp_cln; break; case 017: insn.itype = pdp_ccc; break; case 021: insn.itype = pdp_sec; break; case 022: insn.itype = pdp_sev; break; case 024: insn.itype = pdp_sez; break; case 030: insn.itype = pdp_sen; break; case 037: insn.itype = pdp_scc; break; default: insn.itype = pdp_compcc; insn.Op1.phrase = nibble0 & 037; break; } break; case 0: { static const char misc0[16] = { pdp_halt, pdp_wait, pdp_rti, pdp_bpt, pdp_iot, pdp_reset, pdp_rtt, pdp_mfpt }; if ( nibble0 > 7 ) return 0; insn.itype = misc0[nibble0]; break; } default: // >=4 { static const char lcc2com[7] = { pdp_br, pdp_bne, pdp_beq, pdp_bge, pdp_blt, pdp_bgt, pdp_ble }; insn.itype = lcc2com[(nibble1 >> 2) - 1]; goto condoper; } } break; } if ( insn.bytecmd ) { if ( insn.Op1.type == o_mem && insn.Op1.phrase != 077 || insn.Op1.type == o_displ && (insn.Op1.phrase & 070) == 060 ) { insn.Op1.dtype = dt_byte; } if ( insn.Op2.type == o_mem && insn.Op2.phrase != 077 || insn.Op2.type == o_displ && (insn.Op2.phrase & 070) == 060 ) { insn.Op2.dtype = dt_byte; } } if ( insn.Op1.type == o_imm && insn.Op1.ill_imm ) insn.size -= 2; if ( insn.Op2.type == o_imm && insn.Op2.ill_imm ) insn.size -= 2; return int(insn.size); }