/* * TLCS900 processor module for IDA. * Copyright (c) 1998-2006 Konstantin Norvatoff, * Freeware. */ #include "tosh.hpp" // (number of bytes -1) -> dtype static const uchar bt_type[4]= { dt_byte, dt_word, dt_tbyte, dt_dword }; // power of 2 -> dtype static const uchar btp_type[4]= { dt_byte, dt_word, dt_dword, uchar(-1) }; // memory reference (o_mem/o_displ) struct MemRefDef { uint32 disp; // offset ushort off_pos; // place of offset in insn (if any) optype_t type; // dtype: o_mem/o_displ uchar flags; // flags uchar base_reg; // base reg uchar add_reg; // additional reg (DAfull number) uchar inc_size; // increment size (+/-4) uchar dtype; }; //----------------------------------------------------------------------------- // short reg to full reg static uchar Reg7ToFull(uchar reg7, uchar size) { reg7&=7; // fix reg number // byte reg if ( size == 0 ) return 0xE0+(1-(reg7&1))+(reg7&6)*2; // word or double wor dreg return 0xE0+reg7*4; } //----------------------------------------------------------------------------- // set number of the reg into operand // reg_code - byte reg num // size - 0,1,2 (2^x bytes) static void SetRegistr(op_t &op, uchar reg_code, uchar size) { op.type=o_reg; op.addr=op.value=reg_code; op.dtype = btp_type[size&3]; } //----------------------------------------------------------------------------- // set register // regcode - reg number (3 bits) // size - 0,1,2 (2^x bytes) static void SetRegistr7(op_t &op, uchar regcode, uchar size) { SetRegistr(op, Reg7ToFull(regcode, size), size); } //----------------------------------------------------------------------------- // load N ibytes and return result static uint32 LoadDataValue(insn_t &insn, int bytes) { uint32 val=0; for ( int i=0; i < bytes; i++ ) val |= ((uint32)insn.get_next_byte())<<(8*i); return val; } //----------------------------------------------------------------------------- // currnet bytes are the memory address // len - number of bytes static void SetDirectMemRef(insn_t &insn, op_t &op, int len) { op.type = o_mem; // elem offset op.offb = (uchar)insn.size; // size of offset op.dtype = bt_type[(len-1)&3]; // elem value op.addr = op.value = LoadDataValue(insn, len); } //----------------------------------------------------------------------------- // code ref static void SetJmp(insn_t &insn, op_t &op, int len) { op.type = o_near; op.offb = (uchar)insn.size; op.dtype = dt_dword; if ( len > 0 ) { // absolute op.addr = op.value = LoadDataValue(insn, len); } else { // relative len = -len; op.addr = LoadDataValue(insn, len); // sig if ( op.addr & (uval_t(1)<<(8*len-1)) ) { op.addr |= BADADDR<<(8*len); } // target offset op.addr += insn.ip + insn.size; op.value = op.addr; } } //----------------------------------------------------------------------------- // MemRef to Operand static void MemRefToOp(op_t &op, const MemRefDef &mr) { op.value = mr.disp; op.addr = mr.disp; op.dtype = mr.dtype; op.reg = mr.base_reg; op.specflag2 = mr.inc_size; op.offb = (uchar)mr.off_pos; op.specval_shorts.low = mr.add_reg; op.specflag1 = mr.flags; op.type = mr.type; } //----------------------------------------------------------------------------- // load memory ref // first_code - firt insn byte static int LoadMemRef(insn_t &insn, MemRefDef &mr, uchar first_code) { memset(&mr, 0, sizeof(mr)); mr.dtype = btp_type[(first_code>>4)&3]; if ( (first_code&0x40) == 0 ) { // ref is reg (with offset or not) mr.type = o_displ; // reg name mr.base_reg = Reg7ToFull(first_code, 2); if ( first_code&0x8 ) { // offset mr.off_pos = insn.size; mr.disp = insn.get_next_byte(); } } else { switch ( first_code & 7 ) { // direct, byte case 0: mr.off_pos = insn.size; mr.disp = LoadDataValue(insn, 1); mr.type = o_mem; break; // direct, word case 1: mr.off_pos = insn.size; mr.disp = LoadDataValue(insn, 2); mr.type = o_mem; break; // direct, 24 bit case 2: mr.off_pos=insn.size; mr.disp=LoadDataValue(insn, 3); mr.type=o_mem; break; // two regs case 3: { uchar mem_val; mr.type = o_displ; mem_val = insn.get_next_byte(); if ( (mem_val&2) == 0 ) { // with reg mr.base_reg = mem_val & 0xFC; // and ofsset? if ( mem_val&1 ) { mr.off_pos = insn.size; mr.disp = LoadDataValue(insn, 2); } } else { // two regs if ( (mem_val&1) == 0 ) return 0; // wrong if ( (mem_val>>2) > 1 ) { // LDAR! // check for F3/13 //msg("Ldar Op"); if ( first_code == 0xF3 && mem_val == 0x13 ) { // yes! insn.itype=T900_ldar; // elem offset insn.Op2.offb=(uchar)insn.size; uint32 target=LoadDataValue(insn, 2); target+=uint32(insn.ea+4); insn.Op2.type=o_mem; // size of offset insn.Op2.dtype = dt_word; // elem value insn.Op2.addr = insn.Op2.value = target; // get reg mem_val=insn.get_next_byte(); // available? if ( (mem_val&0xE8) != 0x20 ) return 0; SetRegistr7(insn.Op1, mem_val, ((mem_val>>4)-1)&3); //msg("ldar ok"); return 1; } return 0; } mr.base_reg = insn.get_next_byte(); // 1st reg mr.add_reg = insn.get_next_byte(); // 2nd reg if ( mem_val & 0x4 ) mr.flags|=URB_WORD;// 2nd reg - word } } break; // inc/dec case 4: case 5: { uchar regg = insn.get_next_byte(); if ( (regg&3) == 3 ) return 0; mr.type = o_displ; mr.base_reg = regg&0xFC; mr.inc_size = 1<<(regg&3); // negative inc if ( (first_code&1) == 0 ) mr.inc_size|=URB_DECR; } break; } } return 1; } //----------------------------------------------------------------------------- static void SetImmData(insn_t &insn, op_t &op, int bytes) { op.type = o_imm; op.offb = (uchar)insn.size; op.dtype = bt_type[(bytes-1)&3]; op.addr = op.value = LoadDataValue(insn, bytes); } //----------------------------------------------------------------------------- static void SetImm8Op(op_t &op, uchar code) { op.type = o_imm; op.dtype = dt_byte; // actually, it is not a byte op.flags |= OF_NUMBER; op.addr = op.value = code; } //----------------------------------------------------------------------------- // set imm3 for inc/dec static void SetImm3Op(op_t &op, uchar code) { code &= 7; SetImm8Op(op, code ? code : 8); } //----------------------------------------------------------------------------- // condition phrase static void SetCondOp(op_t &op, int cond) { static const uchar cond_p[16] = { fCF, fCLT, fCLE, fCULE, fCPE, fCMI, fCZ, fCC, fCT, fCGE, fCGT, fCUGT, fCPO, fCPL, fCNZ, fCNC }; op.type = o_phrase; op.phrase = cond_p[cond&0xf]; } //----------------------------------------------------------------------------- // arith insns static const uchar Add_List[8] = { T900_add, T900_adc, T900_sub, T900_sbc, T900_and, T900_xor, T900_or, T900_cp }; // shift insns (not simple) static const uchar Shift_List[8] = { T900_rlc, T900_rrc, T900_rl, T900_rr, T900_sla, T900_sra, T900_sll, T900_srl }; // shift for memory cells static const uchar Shift_List1[8] = { T900_rlc_mem, T900_rrc_mem, T900_rl_mem, T900_rr_mem, T900_sla_mem, T900_sra_mem, T900_sll_mem, T900_srl_mem }; // flag C static const uchar COp_List[5] = { T900_andcf, T900_orcf, T900_xorcf, T900_ldcf, T900_stcf }; // other flag C static const uchar COp2_List[5] = { T900_res, T900_set, T900_chg, T900_bit, T900_tset }; //----------------------------------------------------------------------------- // parse regs static int RegAnalyser(insn_t &insn, uchar code) { static const uchar reg_codes[32] = { 255, 255, 255, 255, T900_andcf, T900_andcf, T900_res, T900_minc1, T900_mul, T900_muls, T900_div, T900_divs, T900_inc, T900_dec, T900_scc, T900_scc, T900_add, T900_ld, T900_adc, T900_ld, T900_sub, T900_ld, T900_sbc, T900_ex, T900_and, 254, T900_xor, 253, T900_or, T900_rlc, T900_cp, T900_rlc }; uchar reg_size = (code>>4) & 3; // 0 - byte, 1 - word, 2 - long uchar reg_num; // byte reg number if ( code & 8 ) { reg_num = Reg7ToFull(code, reg_size); } else { // aux byte reg_num = insn.get_next_byte(); } uchar reg_op = 0; // Op1 is reg by default uchar reg_byte = insn.get_next_byte(); insn.itype = reg_codes[(reg_byte>>3)&0x1F]; switch ( insn.itype ) { case T900_ex: case T900_add: case T900_adc: case T900_sub: case T900_sbc: case T900_and: case T900_xor: case T900_or: case T900_cp: SetRegistr7(insn.Op1, reg_byte, reg_size); reg_op=1; break; case 255: { static const uchar LCodes[] = { 0, 0, 0, T900_ld, T900_push, T900_pop, T900_cpl, T900_neg, T900_mul, T900_muls, T900_div, T900_divs, T900_link, T900_unlk, T900_bs1f, T900_bs1b, T900_daa, 0, T900_extz, T900_exts, T900_paa, 0, T900_mirr, 0, 0, T900_mula, 0, 0, T900_djnz, 0, 0, 0 }; if ( reg_byte >= qnumber(LCodes) ) return 0; insn.itype = LCodes[reg_byte]; switch ( insn.itype ) { // illegal case 0: return 0; // LD r, # case T900_ld: SetImmData(insn, insn.Op2, 1< 0x2C ) { switch ( reg_byte ) { case 0x2D: return 0; // compilcated insn LDC - skip it for now case 0x2E: SetImmData(insn, insn.Op1, 1); reg_op=1; break; case 0x2F: SetImmData(insn, insn.Op2, 1); break; } insn.itype=T900_ldc; } else if ( (reg_byte&7) < 5 ) // not an LDC { reg_op = 1; insn.itype = COp_List[reg_byte&7]; if ( reg_byte & 8 ) SetRegistr7(insn.Op1, 1, 0); else SetImmData(insn, insn.Op1, 1); } else { return 0; } break; // RES-TSET case T900_res: if ( (reg_byte&7) > 4 ) return 0; insn.itype = COp2_List[reg_byte&7]; SetImmData(insn, insn.Op1, 1); reg_op = 1; break; // MINC/MDEC case T900_minc1: { static const uchar dinc[8] = { T900_minc1, T900_minc2, T900_minc4, 0, T900_mdec1, T900_mdec2, T900_mdec4, 0 }; if ( (insn.itype=dinc[reg_byte&7]) == 0 ) return 0; SetImmData(insn, insn.Op1, 2); // fix op insn.Op1.value += uval_t(1)<<(reg_byte&3); insn.Op1.addr = insn.Op1.value; reg_op = 1; } break; // mul/div XXX R, r case T900_mul: case T900_muls: case T900_div: case T900_divs: SetRegistr7(insn.Op1, reg_size == 0 ? (reg_byte&7)/2 : reg_byte, reg_size+1); reg_op=1; break; // INC/DEC #3, r case T900_inc: case T900_dec: SetImm3Op(insn.Op1, reg_byte); reg_op=1; break; // set SCC, r case T900_scc: SetCondOp(insn.Op1, reg_byte&0xF); reg_op=1; break; // LD case T900_ld: if ( reg_byte < 0x90 ) reg_op = 1; if ( reg_byte < 0xA0 ) SetRegistr7(insn.ops[1-reg_op], reg_byte, reg_size); else SetImm8Op(insn.Op2, reg_byte&7); break; // another arithmetics XXX r, #) case 254: insn.itype=Add_List[reg_byte&7]; SetImmData(insn, insn.Op2, 1<= 0xF8 ) { SetRegistr7(insn.Op1, 1, 0); } else { uchar ShL = insn.get_next_byte(); SetImm8Op(insn.Op1, ShL == 0 ? 16 : ShL); } reg_op = 1; break; default: return 0; } // set reg SetRegistr(insn.ops[reg_op], reg_num, reg_size); return insn.size; } //----------------------------------------------------------------------------- // parse 2nd byte DST static int DSTAnalyser(insn_t &insn, uchar code) { // memory op number char memrefop = 1; MemRefDef mr; // memory ref // main opcodes static const uchar dst_codes[32] = { 255, 0, 255, 0, T900_lda, 255, T900_lda, 0, T900_ld, 0, T900_ldw, 0, T900_ld, 0, 0, 0, T900_andcf, T900_orcf, T900_xorcf, T900_ldcf, T900_stcf, T900_tset, T900_res, T900_set, T900_chg, T900_bit, T900_jp_cond, T900_jp_cond, T900_call, T900_call, T900_ret_cond, T900_ret_cond }; // get mem ref if ( LoadMemRef(insn, mr, code) == 0 ) return 0; // check for LDAR if ( insn.itype == T900_ldar ) return insn.size; // opcode uchar dst_byte = insn.get_next_byte(); // need to check for mr.dtyp - byte by default mr.dtype = dt_byte; insn.itype=dst_codes[(dst_byte>>3)&0x1F]; switch ( insn.itype ) { case 0: return 0; // go further case 255: if ( dst_byte < 0x2D && dst_byte >= 0x28 ) { // bit insn insn.itype = COp_List[dst_byte-0x28]; // reg A SetRegistr7(insn.Op1, 1, 0); // mem ref break; } switch ( dst_byte ) { // ld byte case 0x00: insn.itype=T900_ld; SetImmData(insn, insn.Op2, 1); memrefop=0; break; // ld word case 0x02: insn.itype = T900_ldw; SetImmData(insn, insn.Op2, 2); mr.dtype = dt_word; memrefop = 0; break; // pop byte case 0x04: insn.itype=T900_pop; memrefop=0; break; // pop word case 0x06: insn.itype = T900_popw; mr.dtype = dt_word; memrefop = 0; break; // ld byte xx case 0x14: insn.itype = T900_ld; SetDirectMemRef(insn, insn.Op2, 2); memrefop = 0; break; // ld word case 0x16: insn.itype = T900_ldw; SetDirectMemRef(insn, insn.Op2, 2); mr.dtype = dt_word; memrefop = 0; break; default: return 0; } break; // load 40, 50, 60 case T900_ldw: case T900_ld: SetRegistr7(insn.Op2, dst_byte, (dst_byte>>4)&0x3); mr.dtype = btp_type[(dst_byte>>4)&3]; memrefop = 0; break; // load 20, 30 case T900_lda: { uchar size = ((dst_byte>>4)&0x3)-1; SetRegistr7(insn.Op1, dst_byte, size); mr.dtype = btp_type[size]; mr.flags |= URB_LDA|URB_LDA2;// address, not data! } break; // branches case T900_jp_cond: if ( (dst_byte&0xF) == 0x8 ) insn.itype=T900_jp; // fallthrough case T900_call: // set cond code SetCondOp(insn.Op1, dst_byte&0xF); mr.flags |= URB_LDA; // address, not data! break; // return case T900_ret_cond: // 1st byte == 0xb0 if ( code != 0xB0 ) return 0; if ( (dst_byte&0xF) == 0x8 ) insn.itype=T900_ret; SetCondOp(insn.Op1, dst_byte&0xF); return insn.size; // ANDCF, .... default: SetImm8Op(insn.Op1, dst_byte&7); break; } MemRefToOp(insn.ops[uchar(memrefop)], mr); return insn.size; } //----------------------------------------------------------------------------- static int SRCAnalyser(insn_t &insn, uchar code) { uchar memrefop=1; // number of operand with mem ref MemRefDef mr; static const uchar aa[] = { 255, 0, 255, 255, T900_ld, 0, T900_ex, 254, T900_mul, T900_muls, T900_div, T900_divs, T900_inc, T900_dec, 0, 253, T900_add, T900_add, T900_adc, T900_adc, T900_sub, T900_sub, T900_sbc, T900_sbc, T900_and, T900_and, T900_xor, T900_xor, T900_or, T900_or, T900_cp, T900_cp }; if ( LoadMemRef(insn, mr, code) == 0 ) return 0; uchar src_byte = insn.get_next_byte(); insn.itype=aa[(src_byte>>3)&0x1F]; uchar reg_size = (code>>4)&3; // 0, 1, 2 switch ( insn.itype ) { case 0: return 0; case 255: switch ( src_byte ) { default: return 0; // push case 4: insn.itype=T900_push; memrefop=0; break; // rld case 6: insn.itype=T900_rld; SetRegistr7(insn.Op1, 1, 0); break; // rrd case 7: insn.itype=T900_rrd; SetRegistr7(insn.Op1, 1, 0); break; // ldi case 0x10: insn.itype=T900_ldi; mr.inc_size|=URB_UINC; mr.base_reg--; MemRefToOp(insn.Op1, mr); mr.base_reg++; if ( reg_size ) insn.itype++; break; // ldir case 0x11: insn.itype=T900_ldir; mr.inc_size|=URB_UINC; mr.base_reg--; MemRefToOp(insn.Op1, mr); mr.base_reg++; if ( reg_size ) insn.itype++; break; // ldd case 0x12: insn.itype=T900_ldd; mr.inc_size|=URB_UDEC; mr.base_reg--; MemRefToOp(insn.Op1, mr); mr.base_reg++; if ( reg_size ) insn.itype++; break; // lddr case 0x13: insn.itype=T900_lddr; mr.inc_size|=URB_UDEC; mr.base_reg--; MemRefToOp(insn.Op1, mr); mr.base_reg++; if ( reg_size ) insn.itype++; break; // cpi case 0x14: insn.itype=T900_cpi; mr.inc_size|=URB_UINC; if ( reg_size ) SetRegistr7(insn.Op1, 0, 1); else SetRegistr7(insn.Op1, 1, 0); break; // cpir case 0x15: insn.itype=T900_cpir; mr.inc_size|=URB_UINC; if ( reg_size ) SetRegistr7(insn.Op1, 0, 1); else SetRegistr7(insn.Op1, 1, 0); break; // cpd case 0x16: insn.itype=T900_cpd; mr.inc_size|=URB_UDEC; if ( reg_size ) SetRegistr7(insn.Op1, 0, 1); else SetRegistr7(insn.Op1, 1, 0); break; // cpdr case 0x17: insn.itype=T900_cpdr; mr.inc_size|=URB_UDEC; if ( reg_size ) SetRegistr7(insn.Op1, 0, 1); else SetRegistr7(insn.Op1, 1, 0); break; // ld case 0x19: if ( code&0x10 ) insn.itype=T900_ldw; else insn.itype=T900_ld; SetDirectMemRef(insn, insn.Op1, 2); break; } break; // add and others case 254: insn.itype=Add_List[src_byte&7]; SetImmData(insn, insn.Op2, 1<<((code>>4)&3)); // word size if ( reg_size != 0 ) insn.itype++; memrefop=0; break; // shifts xxxx (mem) case 253: insn.itype=Shift_List1[src_byte&7]; // word size if ( reg_size != 0 ) insn.itype++; memrefop=0; break; // inc case T900_inc: case T900_dec: SetImm3Op(insn.Op1, src_byte); // wor size if ( reg_size != 0 ) insn.itype++; break; case T900_ld: SetRegistr7(insn.Op1, src_byte, reg_size); break; // mul/div case T900_mul: case T900_div: case T900_muls: case T900_divs: SetRegistr7(insn.Op1, reg_size == 0 ? (src_byte&7)/2 : src_byte, reg_size+1); break; // ex case T900_ex: SetRegistr7(insn.Op2, src_byte, reg_size); memrefop=0; break; // add and others case T900_add: case T900_adc: case T900_sub: case T900_sbc: case T900_and: case T900_xor: case T900_or: case T900_cp: if ( src_byte&0x8 ) memrefop=0; SetRegistr7(insn.ops[1-memrefop], src_byte, reg_size); break; } MemRefToOp(insn.ops[memrefop], mr); return insn.size; } //----------------------------------------------------------------------------- static void ClearOperand(op_t &op) { op.dtype = dt_byte; op.type = o_void; op.specflag1 = 0; op.specflag2 = 0; op.offb = 0; op.offo = 0; op.reg = 0; op.value = 0; op.addr = 0; op.specval = 0; } //----------------------------------------------------------------------------- int idaapi T900_ana(insn_t *_insn) { insn_t &insn = *_insn; ClearOperand(insn.Op1); ClearOperand(insn.Op2); ClearOperand(insn.Op3); uchar code = insn.get_next_byte(); // split u pto two parts if ( code&0x80 ) { // check for illegal if ( (code&0xF8) == 0xF8 ) { // SWI (F8-FF) insn.itype=T900_swi; // trap number SetImm8Op(insn.Op1, code&7); // trap addres - is not working for now insn.Op1.addr = 0xFFFF00+(code&7)*4; insn.Op1.value = insn.Op1.addr; return insn.size; } if ( code == 0xF7 ) { // LDX insn.itype=T900_ldx; // skip zero byte if ( insn.get_next_byte() != 0 ) return 0; // address is in regs SetDirectMemRef(insn, insn.Op1, 1); // skip zero byte if ( insn.get_next_byte() != 0 ) return 0; // data SetImmData(insn, insn.Op2, 1); // length is 6 bytes insn.size = 6; return insn.size; } // unknow codes (C6, D6, E6, F6) if ( (code & 0xCF) == 0xC6 ) return 0; // large general reg (C8, D8, E8) if ( (code & 0x48) == 0x48 ) return RegAnalyser(insn, code); // is smart reg ? (C7, D7, E7, F7) if ( (code & 0xCF) == 0xC7 ) return RegAnalyser(insn, code); // memref // segments dst (B0, B8, F0) if ( (code & 0xB0) == 0xB0 ) return DSTAnalyser(insn, code); // src return SRCAnalyser(insn, code); } // low part else if ( code < 0x20 ) { static const uchar FirstOp[] = { T900_nop, T900_normal, T900_push, T900_pop, T900_max, T900_halt, T900_ei, T900_reti, T900_ld, T900_push, T900_ldw, T900_pushw, T900_incf, T900_decf, T900_ret, T900_retd, T900_rcf, T900_scf, T900_ccf, T900_zcf, T900_push, T900_pop, T900_ex, T900_ldf, T900_push, T900_pop, T900_jp, T900_jp, T900_call, T900_call, T900_calr, 0 }; insn.itype = FirstOp[code]; switch ( insn.itype ) { case 0x00: return 0; case T900_push: case T900_pop: switch ( code&0x18 ) { case 0x00: insn.Op1.type=o_phrase; insn.Op1.phrase=fSR; break; // push only case 0x08: SetImmData(insn, insn.Op1, 1); break; // xxx A case 0x10: SetRegistr7(insn.Op1, 1, 0); break; // xxx F case 0x18: insn.Op1.type=o_phrase; insn.Op1.phrase=fSF; break; } break; // ei case T900_ei: // next byte is imm SetImmData(insn, insn.Op1, 1); if ( insn.Op1.value == 7 ) { insn.itype=T900_di; insn.Op1.type=o_void; } break; // ld (n), n case T900_ld: SetDirectMemRef(insn, insn.Op1, 1); SetImmData(insn, insn.Op2, 1); break; // ldw case T900_ldw: SetDirectMemRef(insn, insn.Op1, 1); SetImmData(insn, insn.Op2, 2); break; // pushW // retd case T900_pushw: case T900_retd: SetImmData(insn, insn.Op1, 2); break; // ex F, F' case T900_ex: insn.Op1.type = o_phrase; insn.Op1.phrase = fSF; insn.Op2.type = o_phrase; insn.Op2.phrase = fSF1; break; // ldf case T900_ldf: SetImmData(insn, insn.Op1, 1); break; case T900_jp: case T900_call: SetJmp(insn, insn.Op1, 2+(code&1)); insn.Op1.specflag1 |= URB_LDA; break; // callr 16 case T900_calr: SetJmp(insn, insn.Op1, -2); insn.Op1.specflag1 |= URB_LDA; break; } } else { switch ( code & 0x78 ) { // ld case 0x20: case 0x30: case 0x40: insn.itype=T900_ld; SetRegistr7(insn.Op1, code, (code>>4)-2); SetImmData(insn, insn.Op2, 1<<((code>>4)-2)); break; // push case 0x28: case 0x38: insn.itype=T900_push; SetRegistr7(insn.Op1, code, (code>>4)-1); break; // pop case 0x48: case 0x58: insn.itype=T900_pop; SetRegistr7(insn.Op1, code, (code>>4)-3); break; // reserved case 0x50: return 0; // JR case 0x60: case 0x68: if ( (code&0xF) == 0x8 ) insn.itype = T900_jr; else insn.itype = T900_jr_cond; SetCondOp(insn.Op1, code&0xF); SetJmp(insn, insn.Op2, -1); insn.Op2.specflag1|=URB_LDA; break; // JRL case 0x70: case 0x78: if ( (code&0xF) == 0x8 ) insn.itype=T900_jrl; else insn.itype=T900_jrl_cond; SetCondOp(insn.Op1, code&0xF); SetJmp(insn, insn.Op2, -2); insn.Op2.specflag1 |= URB_LDA; break; } } return insn.size; }