//------------------------------------------------------------------------ // Fetchs an instruction (uses ua_next_xxx()) of a correct size (ready for decoding) // Returns the size of the instruction int fetch_instruction(uint32 *w) { uint16 hw = ua_next_word(); int r = detect_inst_len(hw); if ( r == 4 ) *w = (ua_next_word() << 16) | hw; else *w = hw; return r; }
//-------------------------------------------------------------------------- inline void aa16(op_t &x, char dtyp) { cmd.auxpref |= aux_disp16; x.type = o_mem; x.dtyp = dtyp; x.addr = ua_next_word(); }
//-------------------------------------------------------------------------- inline void imm16(op_t &x) { cmd.auxpref |= aux_disp16; x.type = o_imm; x.dtyp = dt_word; x.value = ua_next_word(); }
//-------------------------------------------------------------------------- inline void ds16(op_t &x, int reg, char dtyp) { cmd.auxpref |= aux_disp16; x.type = o_displ; x.dtyp = dtyp; x.reg = reg & 7; x.addr = ua_next_word(); }
//---------------------------------------------------------------------- static int LoadIndex(void) { register ushort top; cmd.Op1.type = o_mem; // cmd.Op1.ref = 0; cmd.Op1.offb = char(cmd.size); cmd.Op1.addr = top = cmd.wid ? ua_next_word() : ua_next_byte(); if( ((cmd.Op1.dtyp == dt_qword || cmd.Op1.dtyp == dt_double) && !++top) || top >= curSeg.DataSize) { if ( !debugmode) return(0 ); ++cmd.Op1.ref; } return(1); }
//---------------------------------------------------------------------- int idaapi ana(void) { cmd.Op1.dtyp = dt_byte; code = ua_next_byte(); cmd.itype = (is_cmos ? cmos : nmos)[code]; if ( cmd.itype == M65_null ) return 0; switch ( code & 0x1F ) { // +08 PHP PLP PHA PLA DEY TAY INY INX Implied // +18 CLC SEC CLI SEI TYA CLV CLD SED Implied // +1a NOP* NOP* NOP* NOP* TXS TSX NOP* NOP* Implied // +1a inc dec phy ply txs tsx phx ply case 0x1A: case 0x08: case 0x18: switch ( cmd.itype ) { case M65_inc: case M65_dec: cmd.Op1.type = o_reg; cmd.Op1.reg = rA; } break; // +0a ASL ROL LSR ROR TXA TAX DEX NOP Accu/impl case 0x0A: switch ( cmd.itype ) { case M65_asl: case M65_rol: case M65_lsr: case M65_ror: cmd.Op1.type = o_reg; cmd.Op1.reg = rA; } break; // +00 BRK JSR RTI RTS NOP*/bra LDY CPY CPX Impl/immed // +02 t t t t NOP*t LDX NOP*t NOP*t ? /immed // +09 ORA AND EOR ADC NOP* LDA CMP SBC Immediate // +0b ANC** ANC** ASR** ARR** ANE** LXA** SBX** SBC* Immediate case 0x00: case 0x02: case 0x09: case 0x0B: switch ( cmd.itype ) { case M65_jsr: cmd.Op1.dtyp = dt_code; cmd.Op1.type = o_near; cmd.Op1.addr = ua_next_word(); break; case M65_brk: case M65_rti: case M65_rts: break; case M65_bra: goto M65_RELATIVE; default: cmd.Op1.type = o_imm; cmd.Op1.value = ua_next_byte(); break; } break; // +0c NOP*/tsb BIT JMP JMP () STY LDY CPY CPX Absolute // +0d ORA AND EOR ADC STA LDA CMP SBC Absolute // +0e ASL ROL LSR ROR STX LDX DEC INC Absolute // +0f SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* Absolute // +0f bbr0 bbr2 bbr4 bbr6 bbs0 bbs2 bbs4 bbs6 Zero page relative case 0x0F: if ( is_cmos ) goto ZP_RELATIVE; case 0x0C: case 0x0D: case 0x0E: M65_ABSOLUTE: switch ( cmd.itype ) { case M65_jmp: cmd.Op1.dtyp = dt_code; cmd.Op1.type = o_near; break; case M65_jmpi: cmd.Op1.dtyp = dt_word; cmd.indirect = 1; /* no break */ default: cmd.Op1.type = o_mem; break; } cmd.Op1.addr = ua_next_word(); break; // +1c NOP*/trb NOP*/bit NOP* NOP*/jmp SHY**/stz LDY NOP* NOP* Absolute,x // +1d ORA AND EOR ADC STA LDA CMP SBC Absolute,x // +1e ASL ROL LSR ROR SHX**y) LDX y) DEC INC Absolute,x // +1f SLO* RLA* SRE* RRA* SHA**y) LAX* y) DCP ISB Absolute,x // +0f bbr1 bbr3 bbr5 bbr7 bbs1 bbs3 bbs5 bbs7 Zero page relative case 0x1F: if ( is_cmos ) { ZP_RELATIVE: cmd.Op1.type = o_mem; cmd.Op1.addr = ua_next_byte(); cmd.Op2.dtyp = dt_code; cmd.Op2.type = o_near; char x = ua_next_byte(); cmd.Op2.addr = cmd.ip + cmd.size + x; break; } /* fall thru */ case 0x1C: case 0x1D: case 0x1E: cmd.Op1.type = o_displ; cmd.Op1.phrase = rX; switch ( cmd.itype ) { case M65_stz: if ( code == 0x9E ) break; case M65_trb: goto M65_ABSOLUTE; case M65_shx: case M65_sha: case M65_ldx: case M65_lax: cmd.Op1.phrase = rY; break; case M65_jmpi: cmd.Op1.phrase = riX; break; } cmd.Op1.addr = ua_next_word(); break; // +19 ORA AND EOR ADC STA LDA CMP SBC Absolute,y // +1b SLO* RLA* SRE* RRA* SHS** LAS** DCP* ISB* Absolute,y case 0x19: case 0x1B: cmd.Op1.type = o_displ; cmd.Op1.phrase = rY; cmd.Op1.addr = ua_next_word(); break; // +10 BPL BMI BVC BVS BCC BCS BNE BEQ Relative case 0x10: M65_RELATIVE: cmd.Op1.dtyp = dt_code; cmd.Op1.type = o_near; { char x = ua_next_byte(); cmd.Op1.addr = cmd.ip + cmd.size + x; } break; // +01 ORA AND EOR ADC STA LDA CMP SBC (indir,x) // +03 SLO* RLA* SRE* RRA* SAX* LAX* y) DCP* ISB* (indir,x) case 0x01: case 0x03: cmd.Op1.type = o_displ; cmd.Op1.phrase = uint16((cmd.itype == M65_lax) ? riY : riX); cmd.Op1.addr = ua_next_byte(); // а для LAX? break; // +11 ORA AND EOR ADC STA LDA CMP SBC (indir),y // +13 SLO* RLA* SRE* RRA* SHA** LAX* DCP* ISB* (indir),y case 0x11: case 0x13: cmd.Op1.type = o_displ; cmd.Op1.phrase = riY; cmd.Op1.addr = ua_next_byte(); break; // +04 NOP*/tsb BIT NOP* NOP*/stz STY LDY CPY CPX Zeropage // +05 ORA AND EOR ADC STA LDA CMP SBC Zeropage // +06 ASL ROL LSR ROR STX LDX DEC INC Zeropage // +07 SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* Zeropage // +07 rmb0 rmb2 rmb4 rmb6 smb0 smb2 smb4 smb6 Zeropage case 0x04: case 0x05: case 0x06: case 0x07: ZEROPAGE: cmd.Op1.type = o_mem; cmd.Op1.addr = ua_next_byte(); break; // +14 NOP*/trb NOP*/bit NOP* NOP*/stz STY LDY NOP* NOP* Zeropage,x // +15 ORA AND EOR ADC STA LDA CMP SBC Zeropage,x // +16 ASL ROL LSR ROR STX y) LDX y) DEC INC Zeropage,x // +17 SLO* RLA* SRE* RRA* SAX* y) LAX* y) DCP ISB Zeropage,x // +17 rmb1 rmb3 rmb5 rmb7 smb1 smb3 smb5 smb7 Zeropage case 0x17: if ( is_cmos ) goto ZEROPAGE; /* fall thru */ case 0x14: case 0x15: case 0x16: cmd.Op1.type = o_displ; cmd.Op1.phrase = zX; switch ( cmd.itype ) { case M65_trb: goto ZEROPAGE; case M65_stx: case M65_sax: case M65_ldx: case M65_lax: cmd.Op1.phrase = zY; break; } cmd.Op1.addr = ua_next_byte(); break; // +12 ora and eor adc sta lda cmp sbc Zeropage, indirect case 0x12: cmd.indirect = 1; cmd.Op1.type = o_mem; cmd.Op1.addr = ua_next_byte(); break; default: error("ana: bad code %x",code); } if ( cmd.itype == M65_nop ) cmd.Op1.type = o_void; return cmd.size; }
// fill the cmd structure according to the addressing mode of the // current analyzed instruction static void fill_cmd(m740_addr_mode_t addr, const uchar flags = 0) { switch ( addr ) { case A_IMM: // immediate set_op_imm(cmd.Op1, ua_next_byte()); break; case A_ACC: // accumulator set_op_acc(cmd.Op1); break; case A_ZP: // zero page if ( cmd.itype == m740_ldm ) { // special case set_op_imm(cmd.Op1, ua_next_byte()); set_op_mem(cmd.Op2, ua_next_byte(), flags); } else set_op_mem(cmd.Op1, ua_next_byte(), flags); break; case A_ZPX: // zero page X set_op_displ(ua_next_byte(), rX); cmd.auxpref |= INSN_DISPL_ZPX; break; case A_ZPY: // zero page Y set_op_displ(ua_next_byte(), rY); cmd.auxpref |= INSN_DISPL_ZPY; break; case A_ABS: // absolute if ( cmd.itype == m740_jmp || cmd.itype == m740_jsr ) { set_op_addr(cmd.Op1, ua_next_word()); } else { set_op_mem(cmd.Op1, ua_next_word(), flags); } break; case A_ABSX: // absolute X set_op_displ(ua_next_word(), rX); cmd.auxpref |= INSN_DISPL_ABSX; break; case A_ABSY: // absolute Y set_op_displ(ua_next_word(), rY); cmd.auxpref |= INSN_DISPL_ABSY; break; case A_IMPL: // implied // nothing to do.. break; case A_REL: // relative set_op_addr(cmd.Op1, (signed char) ua_next_byte() + cmd.ea + 2); break; case A_INDX: // indirect X set_op_displ(ua_next_byte(), rX, dt_word); cmd.auxpref |= INSN_DISPL_INDX; break; case A_INDY: // indirect Y set_op_displ(ua_next_byte(), rY, dt_word); cmd.auxpref |= INSN_DISPL_INDY; break; case A_INDABS: // indirect absolute set_op_mem(cmd.Op1, ua_next_word(), flags, dt_word); cmd.Op1.specflag1 |= OP_ADDR_IND; break; case A_ZPIND: // zero page indirect set_op_mem(cmd.Op1, ua_next_byte(), 0, dt_word); cmd.Op1.specflag1 |= OP_ADDR_IND; break; case A_SP: // special page set_op_addr(cmd.Op1, ua_next_byte() | 0xFF00); cmd.Op1.specflag1 |= OP_ADDR_SP; break; case A_ZPB: // zero page bit set_op_mem(cmd.Op2, ua_next_byte(), flags, dt_word); break; case A_ACCB: // accumulator bit set_op_acc(cmd.Op2); break; case A_ACCBREL: // accumulator bit relative set_op_acc(cmd.Op2); set_op_addr(cmd.Op3, (signed char) ua_next_byte() + cmd.ea + 2); break; case A_ZPBREL: // zero page bit relative set_op_mem(cmd.Op2, ua_next_byte(), flags); set_op_addr(cmd.Op3, (signed char) ua_next_byte() + cmd.ea + 3); break; default: IDA_ERROR("Invalid addressing mode in fill_cmd()"); } }
//---------------------------------------------------------------------- // analyze an basic instruction static int ana_basic(void) { // get the command code byte ushort code = ua_next_byte(); // decode the special case (annoying) instructions switch ( code ) { case 0x30: reg_operand(0, true, false, true, ua_next_byte()); return finalise_insn(SAM8_JP); case 0x31: { // need to decode second byte to determine exact type ushort tmp = ua_next_byte(); switch ( tmp & 0x03 ) { case 0: imm_operand(0, 1, tmp & 0xF0, dt_byte); return finalise_insn(SAM8_SRP); case 1: imm_operand(0, 1, tmp & 0xF8, dt_byte); return finalise_insn(SAM8_SRP1); case 2: imm_operand(0, 1, tmp & 0xF8, dt_byte); return finalise_insn(SAM8_SRP0); case 3: return 0; // invalid instruction } } case 0x82: case 0x92: case 0x83: case 0x93: { // work out correct code ushort opcode = 0; switch ( code ) { case 0x82: opcode = SAM8_PUSHUD; break; case 0x92: opcode = SAM8_POPUD; break; case 0x83: opcode = SAM8_PUSHUI; break; case 0x93: opcode = SAM8_POPUI; break; } // setup operands if ( (opcode == SAM8_POPUD) || (opcode == SAM8_POPUI) ) { reg_operand(1, true, false, false, ua_next_byte()); reg_operand(0, false, false, false, ua_next_byte()); } else { reg_operand(0, true, false, false, ua_next_byte()); reg_operand(1, false, false, false, ua_next_byte()); } return finalise_insn(opcode); } case 0xC2: case 0xD2: { // work out correct code ushort opcode = 0; switch ( code ) { case 0xC2: opcode = SAM8_CPIJE; break; case 0xD2: opcode = SAM8_CPIJNE; break; } // decode it ushort tmp = ua_next_byte(); reg_operand(0, false, true, false, bottom_nibble(tmp)); reg_operand(1, true, true, false, top_nibble(tmp)); code_operand(2, 2, cmd.ea + 3 + (char) ua_next_byte()); return finalise_insn(opcode); } case 0xE2: case 0xF2: case 0xC3: case 0xD3: case 0xE3: case 0xF3: { // need the next byte to tell whether data or code memory ushort opcode = 0; ushort tmp = ua_next_byte(); ushort operandT = top_nibble(tmp); ushort operandB = bottom_nibble(tmp); if ( operandB & 1 ) { switch ( code ) { case 0xE2: opcode = SAM8_LDED; break; case 0xF2: opcode = SAM8_LDEPD; break; case 0xC3: opcode = SAM8_LDE; break; case 0xD3: opcode = SAM8_LDE; break; case 0xE3: opcode = SAM8_LDEI; break; case 0xF3: opcode = SAM8_LDEPI; break; } operandB--; } else { switch ( code ) { case 0xE2: opcode = SAM8_LDCD; break; case 0xF2: opcode = SAM8_LDCPD; break; case 0xC3: opcode = SAM8_LDC; break; case 0xD3: opcode = SAM8_LDC; break; case 0xE3: opcode = SAM8_LDCI; break; case 0xF3: opcode = SAM8_LDCPI; break; } } // decode it if ( code & 0x10 ) { reg_operand(0, true, true, true, operandB); reg_operand(1, false, true, false, operandT); } else { reg_operand(0, false, true, false, operandT); reg_operand(1, true, true, true, operandB); } return finalise_insn(opcode); } case 0xD4: { // get indirect address & check it is valid ushort tmp = ua_next_byte(); if ( tmp & 1 ) return 0; // generate operation ind_code_operand(0, 1, tmp); return finalise_insn(SAM8_CALL); } case 0xF4: reg_operand(0, true, false, true, ua_next_byte()); return finalise_insn(SAM8_CALL); case 0xF6: code_operand(0, 1, ua_next_word()); return finalise_insn(SAM8_CALL); case 0xE4: { reg_operand(1, false, false, false, ua_next_byte()); reg_operand(0, false, false, false, ua_next_byte()); return finalise_insn(SAM8_LD); } case 0xE5: { reg_operand(1, true, false, false, ua_next_byte()); reg_operand(0, false, false, false, ua_next_byte()); return finalise_insn(SAM8_LD); } case 0xF5: { reg_operand(1, false, false, false, ua_next_byte()); reg_operand(0, true, false, false, ua_next_byte()); return finalise_insn(SAM8_LD); } case 0xD5: return 0; // invalid instruction case 0x87: case 0x97: { // get next byte ushort tmp = ua_next_byte(); // setup operands switch ( code ) { case 0x87: reg_operand(0, false, true, false, top_nibble(tmp)); idx_reg_operand(1, ua_next_byte(), bottom_nibble(tmp)); break; case 0x97: idx_reg_operand(0, ua_next_byte(), bottom_nibble(tmp)); reg_operand(1, false, true, false, top_nibble(tmp)); break; } // finalise the instruction return finalise_insn(SAM8_LD); } case 0xd6: reg_operand(0, true, false, false, ua_next_byte()); imm_operand(1, 2, ua_next_byte(), dt_byte); return finalise_insn(SAM8_LD); case 0xe6: reg_operand(0, false, false, false, ua_next_byte()); imm_operand(1, 2, ua_next_byte(), dt_byte); return finalise_insn(SAM8_LD); case 0xc7: { ushort tmp = ua_next_byte(); reg_operand(0, false, true, false, top_nibble(tmp)); reg_operand(1, true, true, false, bottom_nibble(tmp)); return finalise_insn(SAM8_LD); } case 0xd7: { ushort tmp = ua_next_byte(); reg_operand(0, true, true, false, top_nibble(tmp)); reg_operand(1, false, true, false, bottom_nibble(tmp)); return finalise_insn(SAM8_LD); } case 0xa7: case 0xb7: { // extract data ushort tmp = ua_next_byte(); // decode opcode + setup operands ushort opcode; switch ( bottom_nibble(tmp) ) { case 0: opcode = SAM8_LDC; switch ( code ) { case 0xa7: reg_operand(0, false, true, false, top_nibble(tmp)); addr_cdata_operand(1, 2, next_word_le()); break; case 0xb7: addr_cdata_operand(0, 2, next_word_le()); reg_operand(1, false, true, false, top_nibble(tmp)); break; } break; case 1: opcode = SAM8_LDE; switch ( code ) { case 0xa7: reg_operand(0, false, true, false, top_nibble(tmp)); addr_edata_operand(1, 2, next_word_le()); break; case 0xb7: addr_edata_operand(0, 2, next_word_le()); reg_operand(1, false, true, false, top_nibble(tmp)); break; } break; default: // extract operand nibbles ushort operandT = top_nibble(tmp); ushort operandB = bottom_nibble(tmp); // decode the correct opcode if ( operandB & 1 ) { opcode = SAM8_LDE; operandB--; } else { opcode = SAM8_LDC; } // generate operands switch ( code ) { case 0xA7: reg_operand(0, false, true, false, operandT); if ( opcode == SAM8_LDC ) idx_cdata_operand(1, 2, next_word_le(), operandB); else idx_edata_operand(1, 2, next_word_le(), operandB); break; case 0xB7: if ( opcode == SAM8_LDC ) idx_cdata_operand(0, 2, next_word_le(), operandB); else idx_edata_operand(0, 2, next_word_le(), operandB); reg_operand(1, false, true, false, operandT); break; } } // finalise instruction return finalise_insn(opcode); } case 0xE7: case 0xF7: { // extract data ushort tmp = ua_next_byte(); ushort operandT = top_nibble(tmp); ushort operandB = bottom_nibble(tmp); // decode the correct opcode ushort opcode; if ( operandB & 1 ) { opcode = SAM8_LDE; operandB--; } else { opcode = SAM8_LDC; } // generate operands switch ( code ) { case 0xE7: reg_operand(0, false, true, false, operandT); if ( opcode == SAM8_LDC ) idx_cdata_operand(1, 2, (int) (char) ua_next_byte(), operandB); else idx_edata_operand(1, 2, (int) (char) ua_next_byte(), operandB); break; case 0xF7: if ( opcode == SAM8_LDC ) idx_cdata_operand(0, 2, (int) (char) ua_next_byte(), operandB); else idx_edata_operand(0, 2, (int) (char) ua_next_byte(), operandB); reg_operand(1, false, true, false, operandT); break; } // finalise the instruction return finalise_insn(opcode); } case 0x84: case 0x85: case 0x86: case 0x94: case 0x95: case 0x96: { // decode correct opcode ushort opcode = 0; switch ( top_nibble(code) ) { case 8: opcode = SAM8_MULT; break; case 9: opcode = SAM8_DIV; break; } // Now, generate instruction ushort src = ua_next_byte(); ushort dst = ua_next_byte(); reg_operand(0, false, false, true, dst); switch ( bottom_nibble(code) ) { case 4: reg_operand(1, false, false, false, src); break; case 5: reg_operand(1, true, false, false, src); break; case 6: imm_operand(1, 1, src, dt_byte); break; } return finalise_insn(opcode); } case 0xC4: case 0xC5: { // get data ushort src = ua_next_byte(); ushort dst = ua_next_byte(); // generate instruction reg_operand(0, false, false, true, dst); // decode addrmode for opcode 2 switch ( code ) { case 0xC4: reg_operand(1, false, false, true, src); break; case 0xC5: reg_operand(1, true, false, false, src); break; } return finalise_insn(SAM8_LDW); } case 0xC6: reg_operand(0, false, false, true, ua_next_byte()); imm_operand(1, 2, ua_next_word(), dt_word); return finalise_insn(SAM8_LDW); case 0x17: { // get data ushort operandA = ua_next_byte(); ushort src = ua_next_byte(); // ensure operandA bit0 is 0 if ( operandA & 1 ) return 0; // generate instruction reg_operand(0, false, true, false, top_nibble(operandA)); regbit_operand(1, false, src, bottom_nibble(operandA) >> 1); return finalise_insn(SAM8_BCP); } case 0x37: { // get data ushort operandA = ua_next_byte(); ushort dst = ua_next_byte(); // generate operands code_operand(0, 2, cmd.ea + 3 + (char) dst); regbit_operand(1, true, top_nibble(operandA), bottom_nibble(operandA) >> 1); // generate operand switch ( operandA & 1 ) { case 0: return finalise_insn(SAM8_BTJRF); case 1: return finalise_insn(SAM8_BTJRT); } } case 0x57: { // get data ushort operandA = ua_next_byte(); // ensure operandA bit0 is 0 if ( operandA & 1 ) return 0; // generate instruction regbit_operand(0, true, top_nibble(operandA), bottom_nibble(operandA) >> 1); return finalise_insn(SAM8_BITC); } case 0x77: { // get data ushort operandA = ua_next_byte(); // generate instruction regbit_operand(0, true, top_nibble(operandA), bottom_nibble(operandA) >> 1); switch ( operandA & 1 ) { case 0: return finalise_insn(SAM8_BITR); case 1: return finalise_insn(SAM8_BITS); } } } // Decode bit instructions if ( (bottom_nibble(code) == 7) && (top_nibble(code) < 8) ) { static const uint16 codeTable[] = { SAM8_BOR, SAM8_null, SAM8_BXOR, SAM8_null, SAM8_LDB, SAM8_null, SAM8_BAND, SAM8_null }; // extract data ushort operandA = ua_next_byte(); ushort operandB = ua_next_byte(); // generate instruction switch ( operandA & 1 ) { case 0: reg_operand(0, false, true, false, top_nibble(operandA)); regbit_operand(1, false, operandB, bottom_nibble(operandA) >> 1); break; case 1: regbit_operand(0, false, operandB, bottom_nibble(operandA) >> 1); reg_operand(1, false, true, false, top_nibble(operandA)); break; } return finalise_insn(codeTable[top_nibble(code)]); } // Do the instructions with stuff encoded in them switch ( bottom_nibble(code) ) { case 0x08: reg_operand(0, false, true, false, top_nibble(code)); reg_operand(1, false, false, false, ua_next_byte()); return finalise_insn(SAM8_LD); case 0x09: reg_operand(0, false, false, false, ua_next_byte()); reg_operand(1, false, true, false, top_nibble(code)); return finalise_insn(SAM8_LD); case 0x0A: reg_operand(0, false, true, false, top_nibble(code)); code_operand(1, 1, cmd.ea + 2 + (char) ua_next_byte()); return finalise_insn(SAM8_DJNZ); case 0x0B: code_operand(0, 1, cmd.ea + 2 + (char) ua_next_byte()); return finalise_insn(SAM8_JR, top_nibble(code)); case 0x0C: reg_operand(0, false, true, false, top_nibble(code)); imm_operand(1, 1, ua_next_byte(), dt_byte); return finalise_insn(SAM8_LD); case 0x0D: code_operand(0, 1, ua_next_word()); // UNSURE **** return finalise_insn(SAM8_JP, top_nibble(code)); case 0x0E: reg_operand(0, false, true, false, top_nibble(code)); return finalise_insn(SAM8_INC); case 0x0F: { static const uint16 codeTable[] = { SAM8_NEXT, SAM8_ENTER, SAM8_EXIT, SAM8_WFI, SAM8_SB0, SAM8_SB1, SAM8_IDLE, SAM8_STOP, SAM8_DI, SAM8_EI, SAM8_RET, SAM8_IRET, SAM8_RCF, SAM8_SCF, SAM8_CCF, SAM8_NOP }; return finalise_insn(codeTable[top_nibble(code)]); } } // Do R/RR/IR-only mode instructions if ( bottom_nibble(code) < 2 ) { static const uint16 codeTable[] = { SAM8_DEC, SAM8_RLC, SAM8_INC, SAM8_null, SAM8_DA, SAM8_POP, SAM8_COM, SAM8_PUSH, SAM8_DECW, SAM8_RL, SAM8_INCW, SAM8_CLR, SAM8_RRC, SAM8_SRA, SAM8_RR, SAM8_SWAP }; // do the operand if ( code & 1 ) { reg_operand(0, true, false, false, ua_next_byte()); } else { if ( (top_nibble(code) == 8) || (top_nibble(code) == 0xA) ) { reg_operand(0, false, false, true, ua_next_byte()); } else { reg_operand(0, false, false, false, ua_next_byte()); } } // finalise it return finalise_insn(codeTable[top_nibble(code)]); } // Decode arithmetic-style instructions if ( (bottom_nibble(code) > 1) && (bottom_nibble(code) < 7) ) { static const uint16 codeTable[] = { SAM8_ADD, SAM8_ADC, SAM8_SUB, SAM8_SBC, SAM8_OR, SAM8_AND, SAM8_TCM, SAM8_TM, SAM8_null, SAM8_null, SAM8_CP, SAM8_XOR, SAM8_null, SAM8_null, SAM8_null, SAM8_null }; ushort operandA = ua_next_byte(); switch ( bottom_nibble(code) ) { case 2: reg_operand(0, false, true, false, top_nibble(operandA)); reg_operand(1, false, true, false, bottom_nibble(operandA)); return finalise_insn(codeTable[top_nibble(code)]); case 3: reg_operand(0, false, true, false, top_nibble(operandA)); reg_operand(1, true, true, false, bottom_nibble(operandA)); return finalise_insn(codeTable[top_nibble(code)]); case 4: reg_operand(0, false, false, false, ua_next_byte()); reg_operand(1, false, false, false, operandA); return finalise_insn(codeTable[top_nibble(code)]); case 5: reg_operand(0, false, false, false, ua_next_byte()); reg_operand(1, true, false, false, operandA); return finalise_insn(codeTable[top_nibble(code)]); case 6: reg_operand(0, false, false, false, operandA); imm_operand(1, 1, ua_next_byte(), dt_byte); return finalise_insn(codeTable[top_nibble(code)]); } } // If we get here, we've got an invalid instruction return 0; }
//------------------------------------------------------------------------ // 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 ana(void) { cmd.Op1.dtyp = dt_byte; uint8 code = ua_next_byte(); // Fetch instruction info const struct opcode_info_t &opinfo = get_opcode_info(code); cmd.itype = opinfo.itype; int op_i = 0; if ( opinfo.dreg != -1 ) { cmd.Operands[op_i].type = o_reg; cmd.Operands[op_i].phrase = opinfo.dreg; op_i++; } switch ( opinfo.addr ) { case IMPLIED: if ( cmd.itype == SPC_tcall ) { cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rTCall; cmd.Operands[op_i].value = code >> 4; cmd.Operands[op_i].addr = 0xffde - (cmd.Operands[op_i].value << 1); op_i++; } break; case INDIR_IX: cmd.Operands[op_i].type = o_phrase; cmd.Operands[op_i].phrase = riX; op_i++; break; case INDIR_IX_INC: cmd.Operands[op_i].type = o_phrase; cmd.Operands[op_i].phrase = riXinc; op_i++; break; case INDIR_IX_IY: cmd.Operands[op_i].type = o_phrase; cmd.Operands[op_i].phrase = riX; op_i++; cmd.Operands[op_i].type = o_phrase; cmd.Operands[op_i].phrase = riY; op_i++; break; case IMM: cmd.Operands[op_i].type = o_imm; cmd.Operands[op_i].value = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case IMM_DP: cmd.Operands[op_i + 1].type = o_imm; cmd.Operands[op_i + 1].value = ua_next_byte(); cmd.Operands[op_i + 1].dtyp = dt_byte; cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rD; cmd.Operands[op_i].addr = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i += 2; break; case ABS: cmd.Operands[op_i].type = o_mem; cmd.Operands[op_i].addr = ua_next_word(); if ( cmd.itype == SPC_call || cmd.itype == SPC_jmp ) { cmd.Operands[op_i].type = o_near; cmd.Operands[op_i].full_target_ea = cmd.Operands[op_i].addr; } else cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case ABS_IX: case ABS_IY: cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = opinfo.addr == ABS_IX ? rAbsX : rAbsY; cmd.Operands[op_i].addr = ua_next_word(); cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case ABS_IX_INDIR: cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rAbsXi; cmd.Operands[op_i].addr = ua_next_word(); if ( cmd.itype == SPC_jmp ) cmd.Operands[op_i].dtyp = dt_word; else cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case BIT_OP: { uint16 v = ua_next_word(); cmd.Operands[op_i].type = o_displ; if ( code == 0x2a || code == 0x6a ) cmd.Operands[op_i].phrase = rDbitnot; else cmd.Operands[op_i].phrase = rDbit; cmd.Operands[op_i].addr = v & 0x1fff; cmd.Operands[op_i].value = v >> 13; cmd.Operands[op_i].dtyp = dt_byte; op_i++; } break; case DP: if ( cmd.itype == SPC_pcall ) { cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rPCall; cmd.Operands[op_i].value = ua_next_byte(); cmd.Operands[op_i].addr = 0xff00 | cmd.Operands[op_i].value; op_i++; } else { cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rD; cmd.Operands[op_i].addr = ua_next_byte(); if ( cmd.itype == SPC_decw || cmd.itype == SPC_incw || cmd.itype == SPC_cmpw || cmd.itype == SPC_addw || cmd.itype == SPC_subw || cmd.itype == SPC_movw) cmd.Operands[op_i].dtyp = dt_word; else cmd.Operands[op_i].dtyp = dt_byte; op_i++; } break; case DP_IY: case DP_IX: cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = opinfo.addr == DP_IX ? rDX : rDY; cmd.Operands[op_i].addr = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case DP_IX_INDIR: cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = riDX; cmd.Operands[op_i].addr = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case DP_INDIR_IY: cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rDiY; cmd.Operands[op_i].addr = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i++; break; case DP_DP: cmd.Operands[op_i + 1].type = o_displ; cmd.Operands[op_i + 1].phrase = rD; cmd.Operands[op_i + 1].addr = ua_next_byte(); cmd.Operands[op_i + 1].dtyp = dt_byte; cmd.Operands[op_i].type = o_displ; cmd.Operands[op_i].phrase = rD; cmd.Operands[op_i].addr = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i += 2; break; case DP_PC_REL: case DP_IX_PC_REL: cmd.Operands[op_i].type = o_displ; if ( opinfo.addr == DP_IX_PC_REL ) cmd.Operands[op_i].phrase = rDX; else cmd.Operands[op_i].phrase = rD; cmd.Operands[op_i].addr = ua_next_byte(); cmd.Operands[op_i].dtyp = dt_byte; op_i++; cmd.Operands[op_i].type = o_near; { char x = ua_next_byte(); cmd.Operands[op_i].addr = uint16(cmd.ip + cmd.size + x); } op_i++; break; case PC_REL: cmd.Operands[op_i].type = o_near; { char x = ua_next_byte(); cmd.Operands[op_i].addr = uint16(cmd.ip + cmd.size + x); } op_i++; break; default: warning("ana: bad code 0x%x, @: 0x%a (IP=%a)", code, cmd.ea, cmd.ip); return 0; }
//---------------------------------------------------------------------- int ana(void) { CIC_param ctype; register segment_t *s = getMySeg(cmd.ea); // also set curSeg if ( s->type != SEG_CODE || cmd.ip >= curSeg.CodeSize ) { warning("Can't decode non-code fragment!"); return(0); } cmd.Op1.dtyp = dt_void; cmd.wid = cmd.swit = 0; cmd.Op1.ref = 0; if ( (cmd.itype = ua_next_byte()) == j_wide ) { if( (cmd.itype = ua_next_byte()) == j_iinc || (cmd.itype >= j_iload && cmd.itype <= j_aload) || (cmd.itype >= j_istore && cmd.itype <= j_astore) || cmd.itype == j_ret) cmd.wid = 1; //_w else { if ( !debugmode) return(0 ); cmd.size = 1; cmd.itype = j_wide; } } if ( cmd.itype >= j_lastnorm ) { if ( !debugmode) return(0 ); if ( cmd.itype < j_quick_last ) { static const uchar redefcmd[j_quick_last - j_lastnorm] = { j_ldc, //j_ldc_quick j_ldcw, //j_ldcw_quick j_ldc2w, //j_ldc2w_quick j_getfield, //j_getfield_quick j_putfield, //j_putfield_quick j_getfield, //j_getfield2_quick j_putfield, //j_putfield2_quick j_getstatic, //j_getstatic_quick j_putstatic, //j_putstatic_quick j_getstatic, //j_getstatic2_quick j_putstatic, //j_putstatic2_quick j_invokevirtual, //j_invokevirtual_quick j_invokespecial, //j_invokenonvirtual_quick j_a_invokesuper, //j_invokesuper_quick j_invokestatic, //j_invokestatic_quick j_invokeinterface, //j_invokeinterface_quick j_a_invokevirtualobject, //j_invokevirtualobject_quick j_a_invokeignored, //j_invokeignored_quick j_new, //j_new_quick j_anewarray, //j_anewarray_quick j_multianewarray, //j_multianewarray_quick j_checkcast, //j_checkcast_quick j_instanceof, //j_instanceof_quick j_invokevirtual, //j_invokevirtual_quick_w j_getfield, //j_getfield_quick_w j_putfield //j_putfield_quick_w }; cmd.wid = 2; //_quick; switch ( cmd.itype ) { case j_getstatic2_quick: case j_putstatic2_quick: case j_getfield2_quick: case j_putfield2_quick: cmd.wid = 3; //2_quick break; case j_invokevirtual_quick_w: case j_getfield_quick_w: case j_putfield_quick_w: cmd.wid = 4; //_quick_w break; default: break; } cmd.itype = redefcmd[cmd.itype - j_lastnorm]; } else if ( cmd.itype < j_software) return(0 ); else cmd.itype -= (j_software - j_a_software); } //--- switch ( cmd.itype ) { default: { register unsigned refs, ref2f; if ( cmd.itype >= j_iload_0 && cmd.itype <= j_aload_3 ) { refs = (cmd.itype - j_iload_0) % 4; ref2f = (cmd.itype - j_iload_0) / 4; ref2f = ref2f == ((j_lload_0 - j_iload_0) / 4) || ref2f == ((j_dload_0 - j_iload_0) / 4); goto refer; } if ( cmd.itype >= j_istore_0 && cmd.itype <= j_astore_3 ) { refs = (cmd.itype - j_istore_0) % 4; ref2f = (cmd.itype - j_istore_0) / 4; ref2f = ref2f == ((j_lstore_0 - j_istore_0) / 4) || ref2f == ((j_dstore_0 - j_istore_0) / 4); refer: cmd.Op1.addr = curSeg.DataBase + (ushort)refs; cmd.Op1.ref = (uchar)(ref2f + 1); if ( (ushort)(refs + ref2f) >= curSeg.DataSize ) cmd.Op1.ref |= 0x80; break; } } // end refs/refx if ( cmd.itype < j_ifeq || cmd.itype > j_jsr ) break; case j_ifnull: case j_ifnonnull: cmd.Op1.addr = (short)ua_next_word(); b_near: cmd.Op1.type = o_near; cmd.Op1.offb = 1; cmd.Op1.addr += cmd.ip; if ( cmd.Op1.addr >= curSeg.CodeSize ) goto set_bad_ref; break; case j_goto_w: case j_jsr_w: cmd.Op1.addr = ua_next_long(); goto b_near; case j_bipush: cmd.Op1.dtyp = dt_byte; cmd.Op1.value = (char)ua_next_byte(); goto setdat; case j_sipush: cmd.Op1.dtyp = dt_word; cmd.Op1.value = (short)ua_next_word(); setdat: cmd.Op1.type = o_imm; cmd.Op1.offb = 1; break; case j_ldc: cmd.Op1.cp_ind = ua_next_byte(); ctype = C_4byte; goto constchk; case j_ldcw: ctype = C_4byte; goto const2w; case j_ldc2w: ctype = C_8byte; const2w: cmd.Op1.cp_ind = ua_next_word(); constchk: if ( !ConstLoad(ctype)) return(0 ); break; case j_getstatic: case j_putstatic: case j_getfield: case j_putfield: if ( cmd.wid > 1 ) { //_quick form cmd.Op1.type = o_imm; cmd.Op1.ref = 2; //#data cmd.Op1.offb = 1; if ( cmd.wid == 4 ) { //??? cmd.Op1.dtyp = dt_word; cmd.Op1.value = ua_next_word(); } else { cmd.Op1.dtyp = dt_byte; cmd.Op1.value = ua_next_byte(); ++cmd.size; // SKIP } break; } ctype = C_Field; goto const2w; case j_new: ctype = C_Class; goto const2w; case j_anewarray: //\\ ?/ case j_checkcast: case j_instanceof: ctype = C_TypeName; goto const2w; case j_a_invokesuper: case j_a_invokeignored: goto fictarg; case j_invokevirtual: case j_a_invokevirtualobject: cmd.Op2.dtyp = dt_void; if ( cmd.wid > 1 ) { if ( cmd.wid == 4 ) { fictarg: cmd.Op1.value = ua_next_word(); //??? cmd.Op1.dtyp = dt_word; } else { cmd.Op2.type = o_imm; cmd.Op1.ref = 2; //#data cmd.Op1.dtyp = cmd.Op2.dtyp = dt_byte; cmd.Op1.value = ua_next_byte(); cmd.Op2.offb = 2; cmd.Op2.value = ua_next_byte(); } cmd.Op1.offb = 1; cmd.Op1.type = o_imm; cmd.Op1.ref = 2; //#data break; } case j_invokespecial: case j_invokestatic: case j_invokedynamic: ctype = C_Method; goto const2w; case j_invokeinterface: ctype = C_Interface; cmd.Op1.cp_ind = ua_next_word(); cmd.Op2.type = o_imm; cmd.Op2.ref = 1; //not descriptor cmd.Op2.dtyp = dt_byte; cmd.Op2.value = ua_next_byte(); if ( cmd.wid > 1 ) { cmd.Op3.type = o_imm; cmd.Op3.ref = 2; //#data cmd.Op3.value = ua_next_byte(); cmd.Op3.offb = 4; cmd.Op3.dtyp = dt_byte; } else { ++cmd.size; //reserved cmd.Op3.dtyp = dt_void; } goto constchk; case j_multianewarray: cmd.Op1.cp_ind = ua_next_word(); cmd.Op2.type = o_imm; cmd.Op2.ref = 1; // not descriptor cmd.Op2.dtyp = dt_byte; if ( (cmd.Op2.value = ua_next_byte()) == 0 && !debugmode) return(0 ); ctype = C_Type; goto constchk; case j_iinc: case j_iload: case j_istore: cmd.Op1.dtyp = dt_dword; goto memref; case j_lload: case j_lstore: cmd.Op1.dtyp = dt_qword; goto memref; case j_fload: case j_fstore: cmd.Op1.dtyp = dt_float; goto memref; case j_dload: case j_dstore: cmd.Op1.dtyp = dt_double; goto memref; case j_aload: case j_astore: cmd.Op1.dtyp = dt_string; goto memref; case j_ret: cmd.Op1.dtyp = dt_code; memref: if ( !LoadIndex()) return(0 ); if ( cmd.itype == j_iinc ) { cmd.Op2.type = o_imm; cmd.Op2.ref = 0; cmd.Op2.offb = (uchar)cmd.size; //\\??? Это надо??? if ( cmd.wid ) { cmd.Op2.dtyp = dt_word; cmd.Op2.value = (short)ua_next_word(); } else { cmd.Op2.dtyp = dt_byte; cmd.Op2.value = (char)ua_next_byte(); } } break; case j_tableswitch: case j_lookupswitch: { int32 count; register uint32 top; cmd.swit = 1; for(top = (4 - uint32((cmd.ip + cmd.size) % 4)) & 3; top; top--) if ( ua_next_byte() ) { if ( !debugmode) return(0 ); cmd.swit |= 0100; } cmd.Op3.type = o_near; cmd.Op3.offb = (uchar)cmd.size; cmd.Op3.addr = ua_next_long(); cmd.Op3.addr += cmd.ip; cmd.Op3.ref = 0; if ( cmd.Op3.addr >= curSeg.CodeSize ) { if ( !debugmode) return(0 ); ++cmd.Op3.ref; } cmd.swit |= 2; // start out arguments count = ua_next_long(); if ( cmd.itype == j_tableswitch ) { cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_dword; cmd.Op1.value = count; // minimal value cmd.Op2.ref = 0; cmd.Op2.type = o_imm; cmd.Op2.dtyp = dt_dword; count = (uint32(cmd.Op2.value = ua_next_long()) - count + 1); } cmd.Op3.value = count; cmd.Op2.addr = cmd.ip + cmd.size; top = uint32(curSeg.CodeSize - cmd.ip); while ( count-- ) { if ( cmd.itype == j_lookupswitch) ua_next_long( ); // skip pairs; if ( (cmd.ip + ua_next_long()) >= curSeg.CodeSize ) { if ( !debugmode) return(0 ); cmd.swit |= 0200; } if ( (uint32)cmd.size >= top) return(0 ); } } break; case j_newarray: cmd.Op1.type = o_array; // type! cmd.Op1.offb = 1; if( (cmd.Op1.cp_type = ua_next_byte()) < T_BOOLEAN || (uchar)cmd.Op1.cp_type > T_LONG) { set_bad_ref: if ( !debugmode) return(0 ); ++cmd.Op1.ref; } break; } // switch ( cmd.itype ) return(cmd.size); }
//-------------------------------------------------------------------------- int ana(void) { int code = ua_next_byte(); int saved_code = code; char dtyp = dt_byte; if ( code < 0x60 ) { cmd.itype = A2[code]; } else { if ( code & 8 ) { cmd.auxpref |= aux_word; dtyp = dt_word; } else { cmd.auxpref |= aux_byte; dtyp = dt_byte; } cmd.itype = A2tail[(code>>4)-6]; } if ( cmd.itype == H8500_null ) return 0; switch ( code ) { case 0x02: // ldm.w @sp+, <reglist> // cmd.auxpref |= aux_word; phrase(cmd.Op1, SP, ph_post, dt_word); cmd.Op2.type = o_reglist; cmd.Op2.reg = ua_next_byte(); if ( !cmd.Op2.reg ) return 0; break; case 0x12: // stm.w <reglist>, @-sp // cmd.auxpref |= aux_word; cmd.Op1.type = o_reglist; cmd.Op1.reg = ua_next_byte(); if ( !cmd.Op1.reg ) return 0; phrase(cmd.Op2, SP, ph_pre, dt_word); break; case 0x01: // scb/f cmd.auxpref |= aux_f; break; case 0x06: // scb/ne cmd.auxpref |= aux_ne; break; case 0x07: // scb/eq cmd.auxpref |= aux_eq; break; case 0x08: // trapa #xx code = ua_next_byte(); if ( (code & 0xF0) != 0x10 ) return 0; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_byte; cmd.Op1.value = code & 15; break; case 0x0F: // unlk reg(cmd.Op1, FP, dt_word); break; case 0x10: // jmp @aa:16 case 0x18: // jsr @aa:16 aa16(cmd.Op1, dt_code); cmd.Op1.type = o_near; cmd.Op1.addr += cmd.ea & ~0xFFFF; break; case 0x17: // link #xx:8 reg(cmd.Op1, FP, dt_word); imm8(cmd.Op2); break; case 0x1F: // link #xx:16 reg(cmd.Op1, FP, dt_word); imm16(cmd.Op2); break; case 0x03: // pjsr @aa:24 case 0x13: // pjmp @aa:24 { cmd.auxpref |= aux_disp24; uint32 page = ua_next_byte(); cmd.Op1.type = o_far; cmd.Op1.dtyp = dt_code; cmd.Op1.addr = (page<<16) | ua_next_word(); } break; case 0x04: // #xx:8 cmd.auxpref |= aux_byte; case 0x14: // #xx:8 imm8(cmd.Op1); break; case 0x05: // #aa:8.B cmd.auxpref |= aux_byte; aa8(cmd.Op1, dt_byte); break; case 0x15: // #aa:16.B cmd.auxpref |= aux_byte; aa16(cmd.Op1, dt_byte); break; case 0x0C: // #xx:16 cmd.auxpref |= aux_word; case 0x1C: // #xx:16 imm16(cmd.Op1); break; case 0x0D: // #aa:8.W cmd.auxpref |= aux_word; aa8(cmd.Op1, dt_word); dtyp = dt_word; break; case 0x1D: // #aa:16.W cmd.auxpref |= aux_word; aa16(cmd.Op1, dt_word); dtyp = dt_word; break; case 0x0E: // bsr d:8 case 0x20: case 0x21: case 0x22: case 0x23: // d:8 case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: d8(cmd.Op1); break; case 0x1E: // bsr d:16 case 0x30: case 0x31: case 0x32: case 0x33: // d:16 case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: { cmd.auxpref |= aux_disp16; int32 disp = short(ua_next_word()); cmd.Op1.type = o_near; cmd.Op1.dtyp = dt_code; cmd.Op1.addr = cmd.ip + cmd.size + disp; } break; case 0x40: case 0x41: case 0x42: case 0x43: // cmp:e #xx:8, Rn case 0x44: case 0x45: case 0x46: case 0x47: case 0x50: case 0x51: case 0x52: case 0x53: // mov:e #xx:8, Rn case 0x54: case 0x55: case 0x56: case 0x57: cmd.auxpref |= aux_byte; imm8(cmd.Op1); reg(cmd.Op2, code, dtyp); break; case 0x48: case 0x49: case 0x4A: case 0x4B: // cmp:i #xx:16, Rn case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x58: case 0x59: case 0x5A: case 0x5B: // mov:i #xx:16, Rn case 0x5C: case 0x5D: case 0x5E: case 0x5F: cmd.auxpref |= aux_word; imm16(cmd.Op1); reg(cmd.Op2, code, dtyp); break; case 0x60: case 0x61: case 0x62: case 0x63: // @aa:8, Rn case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: aa8(cmd.Op1, dtyp); reg(cmd.Op2, code, dtyp); break; case 0x70: case 0x71: case 0x72: case 0x73: // Rn, @aa:8 case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: reg(cmd.Op1, code, dtyp); aa8(cmd.Op2, dtyp); break; case 0x80: case 0x81: case 0x82: case 0x83: // mov:f @(d:8, R6), Rn case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: ds8(cmd.Op1, R6, dtyp); reg(cmd.Op2, code, dtyp); break; case 0x90: case 0x91: case 0x92: case 0x93: // mov:f Rn, @(d:8, R6) case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: reg(cmd.Op1, code, dtyp); ds8(cmd.Op2, R6, dtyp); break; case 0xA0: case 0xA1: case 0xA2: case 0xA3: // Rn, Rn case 0xA4: case 0xA5: case 0xA6: case 0xA7: case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: reg(cmd.Op1, code, dtyp); break; case 0xB0: case 0xB1: case 0xB2: case 0xB3: // @-Rn, Rn case 0xB4: case 0xB5: case 0xB6: case 0xB7: case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: phrase(cmd.Op1, code, ph_pre, dtyp); break; case 0xC0: case 0xC1: case 0xC2: case 0xC3: // @Rn+, Rn case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: phrase(cmd.Op1, code, ph_post, dtyp); break; case 0xD0: case 0xD1: case 0xD2: case 0xD3: // @Rn, Rn case 0xD4: case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: phrase(cmd.Op1, code, ph_normal, dtyp); break; case 0xE0: case 0xE1: case 0xE2: case 0xE3: // @(d:8,Rn), Rn case 0xE4: case 0xE5: case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF: ds8(cmd.Op1, code, dtyp); break; case 0xF0: case 0xF1: case 0xF2: case 0xF3: // @(d:16,Rn), Rn case 0xF4: case 0xF5: case 0xF6: case 0xF7: case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: ds16(cmd.Op1, code, dtyp); break; } while ( cmd.itype > H8500_last ) // while MAPs are not resolved { int index = -(3+short(cmd.itype)); if ( index < 0 || index >= qnumber(tables) ) interr("ana1"); code = ua_next_byte(); if ( code < 0x20 ) { cmd.itype = tables[index].head[code]; } else { cmd.itype = tables[index].tail[(code>>3)-4]; reg(cmd.Op2, code, dtyp); } if ( index == 3 ) switch ( saved_code ) // MAP6 { case 0x01: case 0x06: case 0x07: if ( cmd.itype != H8500_scb ) return 0; break; case 0x11: if ( cmd.itype != H8500_prts && cmd.itype != H8500_prtd && cmd.itype != H8500_jmp && cmd.itype != H8500_pjmp && cmd.itype != H8500_jsr && cmd.itype != H8500_pjsr ) return 0; break; default: if ( cmd.itype != H8500_movfpe && cmd.itype != H8500_movtpe && cmd.itype != H8500_dadd && cmd.itype != H8500_dsub ) return 0; } switch ( cmd.itype ) { case H8500_null: return 0; case H8500_add_q: cmd.Op2 = cmd.Op1; switch ( code ) { case 0x08: immv(cmd.Op1, 1); break; case 0x09: immv(cmd.Op1, 2); break; case 0x0C: immv(cmd.Op1, -1); break; case 0x0D: immv(cmd.Op1, -2); break; } break; case H8500_bset: case H8500_bclr: case H8500_bnot: case H8500_btst: cmd.Op2 = cmd.Op1; if ( code < 0xC0 ) reg(cmd.Op1, code, dtyp); else immv(cmd.Op1, code & 15); break; case H8500_mov_g: if ( (code & 0xF8) == 0x80 ) break; cmd.Op2 = cmd.Op1; if ( code == 0x06 ) { if ( (cmd.auxpref & aux_word) == 0 ) cmd.auxpref |= aux_byte; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_byte; cmd.Op1.value = ua_next_byte(); } else if ( code == 0x07 ) { if ( (cmd.auxpref & aux_byte) == 0 ) cmd.auxpref |= aux_word; cmd.auxpref |= aux_mov16; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_word; cmd.Op1.value = ua_next_word(); } else reg(cmd.Op1, code, dtyp); break; case H8500_cmp_g: if ( code > 5 ) break; cmd.Op2 = cmd.Op1; if ( code == 0x04 ) { cmd.auxpref |= aux_byte; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_byte; cmd.Op1.value = ua_next_byte(); } else { cmd.auxpref |= aux_word; cmd.Op1.type = o_imm; cmd.Op1.dtyp = dt_word; cmd.Op1.value = ua_next_word(); } break; case H8500_andc: case H8500_orc: case H8500_xorc: case H8500_ldc: case H8500_stc: cmd.Op2.reg += SR; if ( cmd.Op2.reg == RES1 || cmd.Op2.reg == CP ) return 0; if ( ((cmd.auxpref & aux_word) != 0) != (cmd.Op2.reg == SR) ) return 0; if ( cmd.itype != H8500_stc ) break; // no break case H8500_movtpe: { op_t x = cmd.Op1; cmd.Op1 = cmd.Op2; cmd.Op2 = x; } break; case H8500_pjmp: case H8500_pjsr: case H8500_jmp: case H8500_jsr: cmd.Op2.type = o_void; switch ( code & 0xF0 ) { case 0xC0: case 0xD0: phrase(cmd.Op1, code, ph_normal, dt_code); break; case 0xE0: ds8(cmd.Op1, code, dt_code); break; case 0xF0: ds16(cmd.Op1, code, dt_code); break; } break; case H8500_rtd: case H8500_prtd: if ( code == 0x14 ) imm8(cmd.Op1); else imm16(cmd.Op1); break; case H8500_scb: cmd.Op1 = cmd.Op2; d8(cmd.Op2); break; case H8500_dadd: case H8500_dsub: if ( (cmd.auxpref & aux_byte) == 0 ) return 0; cmd.auxpref &= ~aux_byte; break; } } if ( (idpflags & AFIDP_MIXSIZE) == 0 ) // Disassemble mixed size instructions? { if ( (cmd.auxpref & aux_word) && cmd.Op1.dtyp == dt_byte || (cmd.auxpref & aux_byte) && cmd.Op1.dtyp == dt_word ) if ( cmd.itype != H8500_mov_g ) return 0; } return cmd.size; }