/* header: frame.hpp #<pydoc> def add_stkvar3(op, v, flags): """ Automatically add stack variable if doesn't exist Processor modules should use ua_stkvar2() @param op: reference to instruction operand @param v: immediate value in the operand (usually op.addr) @param flags: combination of STKVAR_... constants @return: Boolean """ pass #</pydoc> */ bool py_add_stkvar3(PyObject *py_op, PyObject *py_v, int flags) { PYW_GIL_CHECK_LOCKED_SCOPE(); op_t *op = op_t_get_clink(py_op); uint64 v; return ( op == NULL || !PyW_GetNumber(py_v, &v) || !add_stkvar3(*op, sval_t(v), flags)) ? false : true; }
/* #<pydoc> def get_stkvar(op, v): """ Get pointer to stack variable @param op: reference to instruction operand @param v: immediate value in the operand (usually op.addr) @return: - None on failure - tuple(member_t, actval) where actval: actual value used to fetch stack variable """ pass #</pydoc> */ PyObject *py_get_stkvar(PyObject *py_op, PyObject *py_v) { PYW_GIL_CHECK_LOCKED_SCOPE(); op_t *op = op_t_get_clink(py_op); uint64 v; if ( op == NULL || !PyW_GetNumber(py_v, &v) ) Py_RETURN_NONE; sval_t actval; member_t *member = get_stkvar(*op, sval_t(v), &actval); if ( member == NULL ) Py_RETURN_NONE; return Py_BuildValue("(O" PY_SFMT64 ")", SWIG_NewPointerObj(SWIG_as_voidptr(member), SWIGTYPE_p_member_t, 0), pyl_t(actval)); }
//------------------------------------------------------------------------ // Decodes an instruction "w" into cmd structure bool decode_instruction(uint32 w, insn_t &cmd) { #define PARSE_L12 (((w & 1) << 11) | (w >> 21)) #define PARSE_R1 (w & 0x1F) #define PARSE_R2 ((w & 0xF800) >> 11) typedef struct { int itype; int flags; } itype_flags_t; // If an instruction deals with displacement it should // initialize this pointer to the operand location. // At the end we will transform the operand to o_mem // if we know how to resolve its address op_t *displ_op = NULL; do { uint32 op; // // Format I // op = (w & 0x7E0) >> 5; // Take bit5->bit10 if ( op <= 0xF ) { static const int inst_1[] = { /* MOV reg1, reg2 */ NEC850_MOV, /* NOT reg1, reg2 */ NEC850_NOT, /* DIVH reg1, reg2 */ NEC850_DIVH, /* JMP [reg1] */ NEC850_JMP, /* SATSUBR reg1, reg2 */ NEC850_SATSUBR, /* SATSUB reg1, reg2 */ NEC850_SATSUB, /* SATADD reg1, reg2 */ NEC850_SATADD, /* MULH reg1, reg2 */ NEC850_MULH, /* OR reg1, reg2 */ NEC850_OR, /* XOR reg1, reg2 */ NEC850_XOR, /* AND reg1, reg2 */ NEC850_AND, /* TST reg1, reg2 */ NEC850_TST, /* SUBR reg1, reg2 */ NEC850_SUBR, /* SUB reg1, reg2 */ NEC850_SUB, /* ADD reg1, reg2 */ NEC850_ADD, /* CMP reg1, reg2 */ NEC850_CMP }; // // NOP, Equivalent to MOV R, r (where R=r=0) if ( w == 0 ) { cmd.itype = NEC850_NOP; cmd.Op1.type = o_void; cmd.Op1.dtyp = dt_void; break; } if ( is_v850e ) { if ( w == 0xF840 ) { cmd.itype = NEC850_DBTRAP; break; } } uint16 r1 = PARSE_R1; uint16 r2 = PARSE_R2; cmd.itype = inst_1[op]; cmd.Op1.reg = r1; cmd.Op1.type = o_reg; cmd.Op1.dtyp = dt_dword; if ( is_v850e ) { if ( r2 == 0 ) { if ( cmd.itype == NEC850_DIVH ) { cmd.itype = NEC850_SWITCH; break; } else if ( cmd.itype == NEC850_SATSUBR ) { cmd.itype = NEC850_ZXB; break; } else if ( cmd.itype == NEC850_SATSUB ) { cmd.itype = NEC850_SXB; break; } else if ( cmd.itype == NEC850_SATADD ) { cmd.itype = NEC850_ZXH; break; } else if ( cmd.itype == NEC850_MULH ) { cmd.itype = NEC850_SXH; break; } } // case when r2 != 0 else { // SLD.BU / SLD.HU if ( cmd.itype == NEC850_JMP ) { bool sld_hu = (w >> 4) & 1; uint32 addr = w & 0xF; if ( sld_hu ) { cmd.itype = NEC850_SLD_HU; cmd.Op1.dtyp = dt_word; addr <<= 1; } else { cmd.itype = NEC850_SLD_BU; cmd.Op1.dtyp = dt_byte; } cmd.Op1.type = o_displ; displ_op = &cmd.Op1; cmd.Op1.reg = rEP; cmd.Op1.addr = addr; cmd.Op1.specflag1 = N850F_USEBRACKETS; cmd.Op2.type = o_reg; cmd.Op2.reg = r2; cmd.Op2.dtyp = dt_dword; break; } } } if ( cmd.itype == NEC850_JMP && r2 == 0 ) { cmd.Op1.specflag1 = N850F_USEBRACKETS; } else { cmd.Op2.reg = r2; cmd.Op2.type = o_reg; cmd.Op2.dtyp = dt_dword; } break; } // Format II else if ( op >= 0x10 && op <= 0x17 ) { // flag used for sign extension static const itype_flags_t inst_2[] = { { NEC850_MOV, 1 }, /* MOV imm5, reg2 */ { NEC850_SATADD, 1}, /* SATADD imm5, reg2 */ { NEC850_ADD, 1 }, /* ADD imm5, reg2 */ { NEC850_CMP, 1 }, /* CMP imm5, reg2 */ { NEC850_SHR, 0 }, /* SHR imm5, reg2 */ { NEC850_SAR, 0 }, /* SAR imm5, reg2 */ { NEC850_SHL, 0 }, /* SHL imm5, reg2 */ { NEC850_MULH, 1 }, /* MULH imm5, reg2 */ }; op -= 0x10; cmd.itype = inst_2[op].itype; uint16 r2 = PARSE_R2; if ( is_v850e ) { // // CALLT // if ( r2 == 0 && (cmd.itype == NEC850_SATADD || cmd.itype == NEC850_MOV) ) { cmd.itype = NEC850_CALLT; cmd.Op1.dtyp = dt_byte; cmd.Op1.type = o_imm; cmd.Op1.value = w & 0x3F; break; } } sval_t v = PARSE_R1; if ( inst_2[op].flags == 1 ) { SIGN_EXTEND(sval_t, v, 5); cmd.Op1.specflag1 |= N850F_OUTSIGNED; } cmd.Op1.type = o_imm; cmd.Op1.value = v; cmd.Op1.dtyp = dt_byte; cmd.Op2.type = o_reg; cmd.Op2.reg = r2; cmd.Op2.dtyp = dt_dword; // ADD imm, reg -> reg = reg + imm if ( cmd.itype == NEC850_ADD && r2 == rSP) cmd.auxpref |= N850F_SP; break; } // Format VI else if ( op >= 0x30 && op <= 0x37 ) { static const itype_flags_t inst_6[] = { { NEC850_ADDI, 1 }, /* ADDI imm16, reg1, reg2 */ { NEC850_MOVEA, 1 }, /* MOVEA imm16, reg1, reg2 */ { NEC850_MOVHI, 0 }, /* MOVHI imm16, reg1, reg2 */ { NEC850_SATSUBI, 1 }, /* SATSUBI imm16, reg1, reg2 */ { NEC850_ORI, 0 }, /* ORI imm16, reg1, reg2 */ { NEC850_XORI, 0 }, /* XORI imm16, reg1, reg2 */ { NEC850_ANDI, 0 }, /* ANDI imm16, reg1, reg2 */ { NEC850_MULHI, 0 }, /* MULHI imm16, reg1, reg2 */ }; op -= 0x30; cmd.itype = inst_6[op].itype; uint16 r1 = PARSE_R1; uint16 r2 = PARSE_R2; uint32 imm = w >> 16; // // V850E instructions if ( is_v850e && r2 == 0 ) { // MOV imm32, R if ( cmd.itype == NEC850_MOVEA ) { imm |= ua_next_word() << 16; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_dword; cmd.Op1.value = imm; cmd.itype = NEC850_MOV; cmd.Op2.type = o_reg; cmd.Op2.reg = r1; cmd.Op2.dtyp = dt_dword; break; } // DISPOSE imm5, list12 (reg1 == 0) // DISPOSE imm5, list12, [reg1] else if ( cmd.itype == NEC850_SATSUBI || cmd.itype == NEC850_MOVHI ) { uint16 r1 = (w >> 16) & 0x1F; uint16 L = PARSE_L12; cmd.auxpref |= N850F_SP; // SP reference cmd.Op1.value = (w & 0x3E) >> 1; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_byte; cmd.Op2.value = L; cmd.Op2.type = o_reglist; cmd.Op2.dtyp = dt_word; if ( r1 != 0 ) { cmd.Op3.dtyp = dt_dword; cmd.Op3.type = o_reg; cmd.Op3.reg = r1; cmd.Op3.specflag1 = N850F_USEBRACKETS; cmd.itype = NEC850_DISPOSE_r; } else { cmd.itype = NEC850_DISPOSE_r0; } break; } } bool is_signed = inst_6[op].flags == 1; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_dword; cmd.Op1.value = is_signed ? sval_t(int16(imm)) : imm; cmd.Op1.specflag1 |= N850F_OUTSIGNED; cmd.Op2.type = o_reg; cmd.Op2.reg = r1; cmd.Op2.dtyp = dt_dword; cmd.Op3.type = o_reg; cmd.Op3.reg = r2; cmd.Op3.dtyp = dt_dword; // (ADDI|MOVEA) imm, sp, sp -> sp = sp + imm if ( (cmd.itype == NEC850_ADDI || cmd.itype == NEC850_MOVEA) && ((r1 == rSP) && (r2 == rSP)) ) { cmd.auxpref |= N850F_SP; } break; }
//---------------------------------------------------------------------- int idaapi emu(void) { uint32 Feature = cmd.get_canon_feature(); int flag1 = is_forced_operand(cmd.ea, 0); int flag2 = is_forced_operand(cmd.ea, 1); int flag3 = is_forced_operand(cmd.ea, 2); flow = (Feature & CF_STOP) == 0; if ( Feature & CF_USE1 ) process_operand(cmd.Op1, flag1, 1); if ( Feature & CF_USE2 ) process_operand(cmd.Op2, flag2, 1); if ( Feature & CF_USE3 ) process_operand(cmd.Op3, flag3, 1); if ( Feature & CF_CHG1 ) process_operand(cmd.Op1, flag1, 0); if ( Feature & CF_CHG2 ) process_operand(cmd.Op2, flag2, 0); if ( Feature & CF_CHG3 ) process_operand(cmd.Op3, flag3, 0); // // Check for: // - the register bank changes // - PCLATH changes // - PCL changes // for ( int i=0; i < 3; i++ ) { int reg = 0; switch ( i ) { case 0: reg = BANK; if ( !is_bank() ) continue; break; case 1: reg = PCLATH; if ( !is_pclath() ) continue; break; case 2: reg = -1; if ( !is_pcl() ) continue; break; } sel_t v = (reg == -1) ? cmd.ip : getSR(cmd.ea, reg); if ( cmd.Op2.type == o_reg && cmd.Op2.reg == F ) { // split(reg, v); } else { switch ( cmd.itype ) { case PIC_bcf: case PIC_bcf3: case PIC_bsf: case PIC_bsf3: if ( ((ptype == PIC12) && (cmd.Op2.value == 5) ) // bank selector || ((ptype == PIC14) && ( (reg == BANK && (cmd.Op2.value == 5 || cmd.Op2.value == 6)) || (reg == PCLATH && (cmd.Op2.value == 3 || cmd.Op2.value == 4)))) || ((ptype == PIC16) && (sval_t(cmd.Op2.value) >= 0 && cmd.Op2.value <= 3))) { if ( v == BADSEL ) v = 0; int shift = 0; if ( ptype == PIC14 && reg == BANK ) shift = 5; if ( cmd.itype == PIC_bcf ) v = v & ~(1 << (cmd.Op2.value-shift)); else v = v | (1 << (cmd.Op2.value-shift)); split(reg, v); } break; case PIC_clrf: case PIC_clrf2: split(reg, 0); break; case PIC_swapf: case PIC_swapf3: split(reg, ((v>>4) & 15) | ((v & 15) << 4)); break; case PIC_movwf: case PIC_movwf2: case PIC_addlw: case PIC_andlw: case PIC_iorlw: case PIC_sublw: case PIC_xorlw: { insn_t saved = cmd; if ( decode_prev_insn(cmd.ea) != BADADDR && ( cmd.itype == PIC_movlw ) ) { switch ( saved.itype ) { case PIC_movwf: case PIC_movwf2: v = cmd.Op1.value; break; case PIC_addlw: v += cmd.Op1.value; break; case PIC_andlw: v &= cmd.Op1.value; break; case PIC_iorlw: v |= cmd.Op1.value; break; case PIC_sublw: v -= cmd.Op1.value; break; case PIC_xorlw: v ^= cmd.Op1.value; break; } } else { v = BADSEL; } cmd = saved; } split(reg, v); break; case PIC_movlw: split(reg, cmd.Op2.value); break; } } } // Such as , IDA doesn't seem to convert the following: // tris 6 // into // tris PORTB ( or whatever ) if ( cmd.itype == PIC_tris && !isDefArg0(uFlag) ) set_offset(cmd.ea, 0, dataseg); // movlw value // followed by a // movwf FSR // should convert value into an offset , because FSR is used as a pointer to // the INDF (indirect addressing file) if ( ptype == PIC12 || ptype == PIC14 && cmd.itype == PIC_movwf && cmd.Op1.type == o_mem && (cmd.Op1.addr & 0x7F) == 0x4 ) // FSR { insn_t saved = cmd; if ( decode_prev_insn(cmd.ea) != BADADDR && cmd.itype == PIC_movlw ) { set_offset(cmd.ea, 0, dataseg); } cmd = saved; } // Also - it seems to make sense to me that a // movlw value // followed by a // tris PORTn (or movwf TRISn) // should convert value into a binary , because the bits indicate whether a // port is defined for input or output. if ( is_load_tris_reg() ) { insn_t saved = cmd; if ( decode_prev_insn(cmd.ea) != BADADDR && cmd.itype == PIC_movlw ) { op_bin(cmd.ea, 0); } cmd = saved; } // Move litteral to BSR if ( cmd.itype == PIC_movlb1 ) split(BANK, cmd.Op1.value); // // Determine if the next instruction should be executed // if ( !flow ) flow = conditional_insn(); if ( segtype(cmd.ea) == SEG_XTRN ) flow = 0; if ( flow ) ua_add_cref(0,cmd.ea+cmd.size,fl_F); return 1; }