/* * Interactive disassembler (IDA). * Copyright (c) 2012-2021 Hex-Rays * ALL RIGHTS RESERVED. * * ARC (Argonaut RISC Core) processor module * * Based on code contributed by by Felix Domke */ #include "arc.hpp" #include /* doRegisterOperand converts the 6 bit field 'code' to an IDA-"op_t"-operand. 'd' is the maybe-used (signed) immediate in the lowest 9 bits, li is the long-immediate which is loaded in the instruction decoding, since it's loaded only once, even if an instructions uses multiple times a long immediate when it's all about a branch (isbranch is true), we have to multiply the absolute address by 4, since it's granularity are words then (and not bytes) FYI: register code 61 means "short immediate with .f-flag set", 63 "short immediate without .f-flag" and 62 means "long immediate (4 bytes following the instruction, making the instruction 8 bytes long (insn.size)). */ //---------------------------------------------------------------------- void doRegisterOperand(int code, op_t &op, int d, int li, int isbranch) { /* we always deal with double words, exceptions are load/stores with 8 or 16 bits. these are covered by the instruction decoding */ op.dtype = dt_dword; if ( code == SHIMM_F || code == SHIMM ) // short immediate with/wo flags { if ( isbranch ) { op.type = o_near; op.addr = d * 4; } else { op.type = o_imm; op.value = d; } } else if ( code == LIMM ) // long immediate { if ( isbranch ) { op.type = o_near; /* the upper 7 bits containing processor flags to set */ /* they are handled in the instruction decoding, since */ /* they produce a second (ida-)operand */ op.addr = (li & 0x1FFFFFF) * 4; } else { op.type = o_imm; op.value = li; } op.offb = 4; } else /* just a register */ { op.type = o_reg; op.reg = uint16(code); } } //---------------------------------------------------------------------- // make indirect [b,c] operand // b c // imm imm mem: [imm1+imm2] // reg imm displ: [reg, imm] // imm reg displ: [imm, reg] (membase=1) // reg reg phrase: [reg, reg] void arc_t::doIndirectOperand(const insn_t &insn, int b, int c, op_t &op, int d, int li, bool special) { if ( is_imm(b) && is_imm(c) ) { // [#imm, #imm] int imm1 = b == LIMM ? li : d; int imm2 = c == LIMM ? li : d; if ( special ) { // use a simple immediate for AUX reg numbers op.type = o_imm; op.value = imm1; } else { op.type = o_mem; op.immdisp = is_a4() ? 0 : imm2; op.addr = imm1 + imm2 * get_scale_factor(insn); } } else if ( !is_imm(b) && !is_imm(c) ) { // [reg, reg] op.type = o_phrase; op.reg = b; op.secreg = c; } else { op.type = o_displ; if ( is_imm(c) ) { // [reg, #imm] op.reg = b; op.addr = c == LIMM ? li : d; if ( special ) op.addr = 0; op.membase = 0; } else { // [#imm, reg] op.reg = c; op.addr = b == LIMM ? li : d; op.membase = 1; } } switch ( insn.auxpref & aux_zmask ) { default: op.dtype = dt_dword; break; case aux_b: op.dtype = dt_byte; break; case aux_w: op.dtype = dt_word; break; } } //---------------------------------------------------------------------- // doBranchOperand handles pc-relative word offsets. // nothing special here. void doBranchOperand(const insn_t &insn, op_t &op, int l) { op.dtype = dt_dword; op.type = o_near; op.addr = insn.ip + l * 4 + 4; op.offb = 0; } //---------------------------------------------------------------------- void arc_t::doRegisterInstruction(insn_t &insn, uint32 code) { int i = (code >> 27) & 31; int a = (code >> 21) & 63; int b = (code >> 15) & 63; int c = (code >> 9) & 63; /* the (maybe used?) short immediate value */ uint32 d = code & 0x1FF; // sign-extend if ( d >= 0x100 ) d -= 0x200; /* store the flags. if there are actually no flags at that place, they */ /* will be reconstructed later */ insn.auxpref = code & (aux_cmask|aux_f); switch ( i ) { case 0: // LD register+register insn.itype = ARC_ld; insn.auxpref |= (code & aux_di); break; case 1: // LD register+offset, LR if ( code & (1 << 13) ) insn.itype = ARC_lr; else insn.itype = ARC_ld; break; case 2: // ST, SR if ( code & (1 << 25) ) { insn.itype = ARC_sr; } else { insn.itype = ARC_st; // 26 = Di // 24 = A // 23..22 = ZZ insn.auxpref = (code >> 20) & (aux_di|aux_amask|aux_zmask); } break; case 3: // single operand instructions switch ( c ) { case 0: insn.itype = ARC_flag; a = b; // flag has no 'a' operand, so we're moving the b-operand to a. break; case 1: insn.itype = ARC_asr; break; case 2: insn.itype = ARC_lsr; break; case 3: insn.itype = ARC_ror; break; case 4: insn.itype = ARC_rrc; break; case 5: insn.itype = ARC_sexb; break; case 6: insn.itype = ARC_sexw; break; case 7: insn.itype = ARC_extb; break; case 8: insn.itype = ARC_extw; break; case 9: insn.itype = ARC_swap; break; case 10: insn.itype = ARC_norm; break; case 0x3F: switch ( d ) { case 0: insn.itype = ARC_brk; break; case 1: insn.itype = ARC_sleep; break; case 2: insn.itype = ARC_swi; break; default: return; } a = b = -1; insn.auxpref = 0; break; } c = -1; // c operand is no real operand, so don't try to convert it. break; case 7: // Jcc, JLcc insn.itype = ARC_j; if ( code & (1<<9) ) insn.itype = ARC_jl; else insn.itype = ARC_j; // copy the NN bits insn.auxpref |= (code & aux_nmask); break; case 8: // ADD insn.itype = ARC_add; break; case 9: // ADC insn.itype = ARC_adc; break; case 10: // SUB insn.itype = ARC_sub; break; case 11: // SBC insn.itype = ARC_sbc; break; case 12: // AND insn.itype = ARC_and; break; case 13: // OR insn.itype = ARC_or; break; case 14: // BIC insn.itype = ARC_bic; break; case 15: // XOR insn.itype = ARC_xor; break; case 0x10: insn.itype = ARC_asl; break; case 0x11: insn.itype = ARC_lsr; break; case 0x12: insn.itype = ARC_asr; break; case 0x13: insn.itype = ARC_ror; break; case 0x14: insn.itype = ARC_mul64; break; case 0x15: insn.itype = ARC_mulu64; break; case 0x1E: insn.itype = ARC_max; break; case 0x1F: insn.itype = ARC_min; break; } uint32 immediate = 0; int noop3 = 0, isnop = 0; if ( a == SHIMM_F || b == SHIMM_F || c == SHIMM_F ) insn.auxpref = aux_f; // .f if ( b == SHIMM || c == SHIMM ) insn.auxpref = 0; if ( b == LIMM || c == LIMM ) immediate = insn.get_next_dword(); /* pseudo instruction heuristic: we have some types of pseudo-instructions: (rS might be an immediate) insn will be coded as move rD, rS and rD, rS, rS asl rD, rS add rD, rS, rS lsl rD, rS add rD, rS, rS (the same as asl, of course...) rlc rD, rS adc.f rD, rS, rS rol rD, rS add.f rD, rS, rS; adc rD, rD, 0 nop xxx 0, 0, 0 */ switch ( insn.itype ) { case ARC_flag: // special handling for flag, since its a-operand is a source here b = -1; break; case ARC_and: case ARC_or: if ( b == c ) { noop3 = 1; insn.itype = ARC_mov; } break; case ARC_add: if ( b == c ) { noop3 = 1; if ( b >= SHIMM_F ) { // add rD, imm, imm -> move rD, imm*2 insn.itype = ARC_mov; d <<= 1; immediate <<= 1; } else { insn.itype = ARC_lsl; } } break; case ARC_adc: if ( b == c ) { noop3 = 1; insn.itype = ARC_rlc; } break; case ARC_xor: if ( code == 0x7FFFFFFF ) // XOR 0x1FF, 0x1FF, 0x1FF isnop = 1; break; } if ( !isnop ) { if ( i == 0 ) { // ld a, [b,c] doRegisterOperand(a, insn.Op1, d, immediate, 0); doIndirectOperand(insn, b, c, insn.Op2, d, immediate, false); } else if ( i == 1 || i == 2 ) { /* fetch the flag-bits from the right location */ if ( insn.itype == ARC_ld ) insn.auxpref = (code >> 9) & 0x3F; else if ( insn.itype == ARC_st ) insn.auxpref = (code >> 21) & 0x3F; else insn.auxpref = 0; if ( insn.itype == ARC_st || insn.itype == ARC_sr ) { /* in a move to special register or load from special register, we have the target operand somewhere else */ a = c; /* c=-1; not used anyway */ } doRegisterOperand(a, insn.Op1, d, immediate, 0); doIndirectOperand(insn, b, SHIMM, insn.Op2, d, immediate, insn.itype == ARC_lr || insn.itype == ARC_sr); } else if ( i == 7 ) { /* the jump (absolute) instruction, with a special imm-encoding */ doRegisterOperand(b, insn.Op1, d, immediate, 1); } else { if ( a != -1 ) doRegisterOperand(a, insn.Op1, 0, immediate, 0); /* this is a bugfix for the gnu-as: long immediate must be equal, while short */ /* immediates don't have to. */ if ( b != -1 ) doRegisterOperand(b, insn.Op2, d, immediate, 0); if ( c != -1 && !noop3 ) doRegisterOperand(c, insn.Op3, d, immediate, 0); } } else { insn.itype = ARC_nop; insn.auxpref = 0; } } //---------------------------------------------------------------------- void doBranchInstruction(insn_t &insn, uint32 code) { int i = (code >> 27) & 31; int l = (code >> 7) & 0xFFFFF; // note: bits 21..2, so it's in WORDS if ( l >= 0x80000 ) // sign-extend l = l - 0x100000; doBranchOperand(insn, insn.Op1, l); switch ( i ) { case 4: // Bcc insn.itype = ARC_b; break; case 5: // BLcc insn.itype = ARC_bl; break; case 6: // LPcc insn.itype = ARC_lp; break; } insn.auxpref = code & (aux_cmask | aux_nmask); } //---------------------------------------------------------------------- // analyze ARCTangent-A4 (32-bit) instruction int arc_t::ana_old(insn_t &insn) { if ( insn.ea & 3 ) return 0; insn.Op1.dtype = dt_dword; insn.Op2.dtype = dt_dword; insn.Op3.dtype = dt_dword; uint32 code = insn.get_next_dword(); int i = (code >> 27) & 31; insn.itype = 0; switch ( i ) { case 0: // LD register+register case 1: // LD register+offset, LR case 2: // ST, SR case 3: // single operand instructions doRegisterInstruction(insn, code); break; case 4: // Bcc case 5: // BLcc case 6: // LPcc doBranchInstruction(insn, code); break; case 7: // Jcc, JLcc case 8: // ADD case 9: // ADC case 10: // SUB case 11: // ADC case 12: // AND case 13: // OR case 14: // BIC case 15: // XOR default: doRegisterInstruction(insn, code); break; } return insn.size; } #define SUBTABLE(high, low, name) (0x80000000 | (high << 8) | low), 0, { 0,0,0 }, name #define SUBTABLE2(high1, low1, high2, low2, name) (0x80000000 | (high1 << 24) | (low1 << 16) | (high2 << 8) | low2), 0, { 0,0,0 }, name //---------------------------------------------------------------------- struct arcompact_opcode_t { uint32 mnem; // instruction itype, or indicator of sub-field decoding uint32 aux; // auxpref and other flags uint32 ops[3]; // description of operands const arcompact_opcode_t *subtable; //lint !e958 padding is required to align members }; enum aux_flags_t ENUM_SIZE(uint32) { AUX_B = 1, // implicit byte size access AUX_W = 2, // implicit word size access Q_4_0 = 4, // 4..0 QQQQQ condition code AAZZXD_23_15 = 8, // 23..22,18..15 aa, ZZ, X, D flags (load reg+reg) DAAZZX_11_6 = 0x10, // 11..6 Di, aa, ZZ, X flags (load) DAAZZ_5_1 = 0x20, // 5..0 Di, aa, ZZ, R flags (store) AUX_D = 0x40, // implicit delay slot (.d) AUX_X = 0x80, // implicit sign extend (.x) AUX_CND = 0x100, // implicit condition (in low 5 bits) N_5 = 0x200, // 5..5 N delay slot bit AUX_GEN = 0x400, // 4..0 = Q if 23..22=0x3, bit 15 = F AUX_GEN2 = 0x800, // 4..0 = Q if 23..22=0x3 AUX_GEN3 = AUX_GEN|AUX_GEN2, // 4..0 = Q if 23..22=0x3, bit 15 = Di AUX_V2 = 0x1000, // only available on ARCv2 AUX_F = 0x2000, // use alternative instruction when F = 1 AUX_AS = 0x8000, // implicit scaled access Q_5_0 = 0x10000, // 5..0 0QQQQQ condition code Y_3 = 0x20000, // 3 Y static branch prediction bit }; enum op_fields_t ENUM_SIZE(uint32) { fA32=1, // 5..0 a register operand (6 bits, r0-r63) fA16, // 2..0 a register operand (3 bits, r0-r3, r12-r15) fB32, // 14..12 & 26..24 b register operand (6 bits) fB16, // 10..8 b register operand (3 bits) fC32, // 11..6 c register operand (6 bits) fC32_w6, // 11..6 & 0 c/w6 register/immediate operand (6 bits) fC16, // 7..5 c register operand (3 bits) fH16, // 2..0 & 7..5 h register operand (6 bits) fH16v2, // 1..0 & 7..5 h register operand (5 bits) fH16v2_U5, // 1..0 & 7..5, 10&4..3 [h, u5] (u5=u3*4) fG16, // 4..3 & 10..8 g register operand (5 bits) fR16_2, // 9..8 R register operand (2 bits) fR16_1, // 7 R register operand (1 bit) S25, // 15..6 & 26..17 & 0..3 s25 signed branch displacement S21, // 15..6 & 26..17 s21 signed branch displacement S25L, // 15..6 & 26..18 & 0..3 s25 signed branch displacement for branch and link S21L, // 15..6 & 26..18 s21 signed branch displacement for branch and link S10, // 8..0 s10 signed branch displacement S9, // 15..15 & 23..17 s9 signed branch displacement S8, // 6..0 s8 signed branch displacement S7, // 5..0 s7 signed branch displacement S13, // 10..0 s13 signed branch displacement U3, // 2..0 u2 unsigned immediate U5, // 4..0 u5 unsigned immediate U6, // 11..6 u6 unsigned immediate U6_SWI, // 10..5 u6 unsigned immediate U7, // 6..0 u7 unsigned immediate U7L, // 4..0 u7 unsigned immediate (u5*4) U8, // 7..0 u8 unsigned immediate U6_16, // 6..4 & 2..0 u6 unsigned immediate U7_16, // 7..4 & 2..0 u7 unsigned immediate U10_16, // 9..0 u10 unsigned immediate SP_U7, // 4..0 [SP, u7] stack + offset (u7 = u5*4) PCL_U10, // 7..0 [PCL, u10] PCL + offset (u8*4) fB_U5, // 10..8 & 4..0 [b, u5] fB_U6, // 10..8 & 4..0 [b, u6] (u6=u5*2) fB_U7, // 10..8 & 4..0 [b, u7] (u6=u5*4) fB_S9, // 14..12&26..26, 15&23..16 [b, s9] GENA, // 5..0 GENB, // 14..12 & 26..24 GENC, // 11..6 or 5..0 & 11..6 GENC_PCREL, // 11..6 or 5..0 & 11..6 fBC_IND, // 14..12 & 26..24, 11..6 [b, c] fBC16_IND, // 10..8, 7..5 [b, c] R_SP, // implicit SP R_BLINK, // implicit BLINK O_ZERO, // implicit immediate 0 R_R0, // implicit R0 R_R1, // implicit R1 R_GP, // implicit GP GP_S9, // 8..0 [GP, s9] GP + offset GP_S10, // 8..0 [GP, s10] GP + offset (s10 = s9*2) GP_S11, // 8..0 [GP, s11] GP + offset (s11 = s9*4) S11, // 8..0 s11 signed immediate (s11 = s9*4) GP_S11_16, // 10..5 & 4..2 [GP, s11] GP + offset (s11 = s9*4) S3, // 10..8 s3 signed immediate EL, // 4..1 & 10..8 enter / leave register set O_IND = 0x80000000, // [reg], [imm] (jumps: only [reg]) O_WIDE = 0x40000000, // register pair rNrN+1 with N even O_IDX = 0x20000000, // instruction specific index O_FLAGS = O_IND|O_WIDE|O_IDX, }; // indexed by bit 16 (maj = 0) static const arcompact_opcode_t arcompact_maj0[2] = { { ARC_b, Q_4_0 | N_5, {S21, 0, 0}, NULL }, // 0 { ARC_b, N_5, {S25, 0, 0}, NULL }, // 1 }; // indexed by bit 17 (maj = 1, b16 = 0) static const arcompact_opcode_t arcompact_bl[2] = { { ARC_bl, Q_4_0 | N_5, {S21L, 0, 0}, NULL }, // 0 { ARC_bl, N_5, {S25L, 0, 0}, NULL }, // 1 }; // indexed by bits 3..0 (maj = 1, b16 = 1, b4 = 0) static const arcompact_opcode_t arcompact_br_regreg[0x10] = { { ARC_br, AUX_CND|cEQ|N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x00 { ARC_br, AUX_CND|cNE|N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x01 { ARC_br, AUX_CND|cLT|N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x02 { ARC_br, AUX_CND|cGE|N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x03 { ARC_br, AUX_CND|cLO|N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x04 { ARC_br, AUX_CND|cHS|N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x05 { ARC_bbit0, N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x06 { ARC_bbit1, N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x07 { ARC_br, AUX_CND|cEQ|N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x08 { ARC_br, AUX_CND|cNE|N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x09 { ARC_br, AUX_CND|cLT|N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x0A { ARC_br, AUX_CND|cGE|N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x0B { ARC_br, AUX_CND|cLO|N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x0C { ARC_br, AUX_CND|cHS|N_5|Y_3|AUX_V2, {fB32, fC32, S9}, NULL }, // 0x0D { ARC_bbit0, N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x0E { ARC_bbit1, N_5|Y_3, {fB32, fC32, S9}, NULL }, // 0x0F }; // indexed by bits 3..0 (maj = 1, b16 = 1, b4 = 1) static const arcompact_opcode_t arcompact_br_regimm[0x10] = { { ARC_br, AUX_CND|cEQ|N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x00 { ARC_br, AUX_CND|cNE|N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x01 { ARC_br, AUX_CND|cLT|N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x02 { ARC_br, AUX_CND|cGE|N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x03 { ARC_br, AUX_CND|cLO|N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x04 { ARC_br, AUX_CND|cHS|N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x05 { ARC_bbit0, N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x06 { ARC_bbit1, N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x07 { ARC_br, AUX_CND|cEQ|N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x08 { ARC_br, AUX_CND|cNE|N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x09 { ARC_br, AUX_CND|cLT|N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x0A { ARC_br, AUX_CND|cGE|N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x0B { ARC_br, AUX_CND|cLO|N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x0C { ARC_br, AUX_CND|cHS|N_5|Y_3|AUX_V2, {fB32, U6, S9}, NULL }, // 0x0D { ARC_bbit0, N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x0E { ARC_bbit1, N_5|Y_3, {fB32, U6, S9}, NULL }, // 0x0F }; // indexed by bit 4 (maj = 1, b16 = 1) static const arcompact_opcode_t arcompact_br[4] = { { SUBTABLE( 3, 0, arcompact_br_regreg) }, // 0 { SUBTABLE( 3, 0, arcompact_br_regimm) }, // 1 }; // indexed by bit 16 (maj = 1) static const arcompact_opcode_t arcompact_maj1[0x40] = { { SUBTABLE(17, 17, arcompact_bl) }, // 0 { SUBTABLE( 4, 4, arcompact_br) }, // 1 }; // indexed by bits 14..12 & 26..24 (maj = 4, 21..16=0x2F, 5..0=0x3F) static const arcompact_opcode_t arcompact_zop[0x40] = { { 0 }, // 0x00 { ARC_sleep, 0, {GENC, 0, 0}, NULL }, // 0x01 { ARC_swi, 0, { 0, 0, 0}, NULL }, // 0x02 { ARC_sync, 0, { 0, 0, 0}, NULL }, // 0x03 { ARC_rtie, 0, { 0, 0, 0}, NULL }, // 0x04 { ARC_brk, 0, { 0, 0, 0}, NULL }, // 0x05 { ARC_seti,AUX_V2,{GENC, 0, 0}, NULL }, // 0x06 { ARC_clri,AUX_V2,{GENC, 0, 0}, NULL }, // 0x07 { ARC_wevt, 0, {GENC, 0, 0}, NULL }, // 0x08 { 0 }, // 0x09 { 0 }, // 0x0A { 0 }, // 0x0B { 0 }, // 0x0C { 0 }, // 0x0D { 0 }, // 0x0E { 0 }, // 0x0F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { 0 }, // 0x28 { 0 }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { 0 }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F }; // indexed by bits 5..0 (maj = 4, 21..16=0x2F) static const arcompact_opcode_t arcompact_sop[0x40] = { { ARC_asl, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x00 { ARC_asr, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x01 { ARC_lsr, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x02 { ARC_ror, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x03 { ARC_rrc, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x04 { ARC_sexb, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x05 { ARC_sexw, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x06 { ARC_extb, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x07 { ARC_extw, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x08 { ARC_abs, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x09 { ARC_not, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x0A { ARC_rlc, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x0B { ARC_ex, AUX_GEN, {GENB, GENC|O_IND,0},NULL}, // 0x0C { ARC_rol, AUX_V2|AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x0D { 0 }, // 0x0E { 0 }, // 0x0F { ARC_llock,AUX_GEN, {GENB, GENC|O_IND, 0}, NULL }, // 0x10 { ARC_scond,AUX_GEN, {GENB, GENC|O_IND, 0}, NULL }, // 0x11 { 0 }, // 0x12 { 0 }, // 0x13 { 0 }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { 0 }, // 0x18 { 0 }, // 0x19 { 0 }, // 0x1A { 0 }, // 0x1B { 0 }, // 0x1C { 0 }, // 0x1D { 0 }, // 0x1E { 0 }, // 0x1F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { 0 }, // 0x28 { 0 }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { 0 }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { SUBTABLE2(14, 12, 26, 24, arcompact_zop) },// 0x3F }; // indexed by bits 21..16 (maj = 4) static const arcompact_opcode_t arcompact_maj4[0x40] = { { ARC_add, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x00 { ARC_adc, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x01 { ARC_sub, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x02 { ARC_sbc, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x03 { ARC_and, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x04 { ARC_or, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x05 { ARC_bic, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x06 { ARC_xor, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x07 { ARC_max, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x08 { ARC_min, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x09 { ARC_mov, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x0A { ARC_tst, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x0B { ARC_cmp, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x0C { ARC_rcmp, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x0D { ARC_rsub, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0E { ARC_bset, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0F { ARC_bclr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x10 { ARC_btst, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x11 { ARC_bxor, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x12 { ARC_bmsk, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x13 { ARC_add1, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x14 { ARC_add2, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x15 { ARC_add3, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x16 { ARC_sub1, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x17 { ARC_sub2, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x18 { ARC_sub3, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x19 { ARC_mpy, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1A { ARC_mpyh, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1B { ARC_mpyhu,AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1C { ARC_mpyu, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1D { ARC_mpyw, AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1E { ARC_mpyuw,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1F { ARC_j, AUX_GEN, {GENC|O_IND, 0, 0}, NULL }, // 0x20 { ARC_j, AUX_GEN|AUX_D, {GENC|O_IND, 0, 0}, NULL }, // 0x21 { ARC_jl, AUX_GEN, {GENC|O_IND, 0, 0}, NULL }, // 0x22 { ARC_jl, AUX_GEN|AUX_D, {GENC|O_IND, 0, 0}, NULL }, // 0x23 { ARC_bi, AUX_V2, {fC32|O_IDX, 0, 0}, NULL }, // 0x24 { ARC_bih, AUX_V2, {fC32|O_IDX, 0, 0}, NULL }, // 0x25 { ARC_ldi, AUX_V2|Q_5_0, {GENB, GENC|O_IDX, 0}, NULL }, // 0x26 { ARC_aex, AUX_V2|AUX_GEN2, {fB32, GENC|O_IND, 0}, NULL }, // 0x27 { ARC_lp, AUX_GEN2, {GENC_PCREL, 0, 0}, NULL }, // 0x28 { ARC_flag, AUX_GEN2, {GENC, 0, 0}, NULL }, // 0x29 { ARC_lr, 0, {GENB, GENC|O_IND, 0}, NULL }, // 0x2A { ARC_sr, 0, {GENB, GENC|O_IND, 0}, NULL }, // 0x2B { ARC_bmskn,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2C { ARC_null, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1C { ARC_null, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1D { SUBTABLE(5, 0, arcompact_sop) }, // 0x2F { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x30 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x31 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x32 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x33 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x34 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x35 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x36 { ARC_ld, AAZZXD_23_15, {fA32, fBC_IND, 0}, NULL }, // 0x37 { ARC_seteq,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x38 { ARC_setne,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x39 { ARC_setlt,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3A { ARC_setge,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3B { ARC_setlo,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3C { ARC_seths,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3D { ARC_setle,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3E { ARC_setgt,AUX_V2|AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3F }; // indexed by bits 14..12 & 26..24 (maj = 5, 21..16=0x2F, 5..0=0x3F) static const arcompact_opcode_t arcompact_zop5[0x40 * 2] = { { ARC_aslacc, AUX_V2|AUX_F, {GENC, 0, 0}, NULL }, // 0x00 { ARC_aslsacc, AUX_V2|AUX_F, {GENC, 0, 0}, NULL }, // 0x01 { 0 }, // 0x02 { 0 }, // 0x03 { 0, AUX_F, {0, 0, 0}, NULL }, // 0x04(F=0) { ARC_modif, AUX_V2|AUX_F, {GENC, 0, 0}, NULL }, // 0x05 { 0 }, // 0x06 { 0 }, // 0x07 { 0 }, // 0x08 { 0 }, // 0x09 { 0 }, // 0x0A { 0 }, // 0x0B { 0 }, // 0x0C { 0 }, // 0x0D { 0 }, // 0x0E { 0 }, // 0x0F { 0 }, // 0x10 { 0 }, // 0x11 { 0 }, // 0x12 { 0 }, // 0x13 { 0 }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { 0 }, // 0x18 { 0 }, // 0x19 { 0 }, // 0x1A { 0 }, // 0x1B { 0 }, // 0x1C { 0 }, // 0x1D { 0 }, // 0x1E { 0 }, // 0x1F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { 0 }, // 0x28 { 0 }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { 0 }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F { 0 }, // 0x00 { 0 }, // 0x01 { 0 }, // 0x02 { 0 }, // 0x03 { ARC_flagacc, AUX_V2, {GENC, 0, 0}, NULL }, // 0x04(F=1) { 0 }, // 0x05 { 0 }, // 0x06 { 0 }, // 0x07 { 0 }, // 0x08 { 0 }, // 0x09 { 0 }, // 0x0A { 0 }, // 0x0B { 0 }, // 0x0C { 0 }, // 0x0D { 0 }, // 0x0E { 0 }, // 0x0F { 0 }, // 0x10 { 0 }, // 0x11 { 0 }, // 0x12 { 0 }, // 0x13 { 0 }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { 0 }, // 0x18 { 0 }, // 0x19 { 0 }, // 0x1A { 0 }, // 0x1B { 0 }, // 0x1C { 0 }, // 0x1D { 0 }, // 0x1E { 0 }, // 0x1F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { 0 }, // 0x28 { 0 }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { 0 }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F }; // indexed by bits 5..0 (maj = 5, 21..16=0x2F) static const arcompact_opcode_t arcompact_sop5[0x40] = { { ARC_swap, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x00 { ARC_norm, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x01 { ARC_sat16, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x02 { ARC_rnd16, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x03 { ARC_abssw, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x04 { ARC_abss, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x05 { ARC_negsw, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x06 { ARC_negs, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x07 { ARC_normw, AUX_GEN, {GENB, GENC, 0}, NULL }, // 0x08 { ARC_swape, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x09 { ARC_lsl16, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x0A { ARC_lsr16, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x0B { ARC_asr16, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x0C { ARC_asr8, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x0D { ARC_lsr8, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x0E { ARC_lsl8, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x0F { ARC_rol8, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x10 { ARC_ror8, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x11 { ARC_ffs, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x12 { ARC_fls, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x13 { 0 }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { ARC_getacc, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x18 { ARC_normacc, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x19 { ARC_satf, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x1A { 0 }, // 0x1B { ARC_vpack2hbl, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x1C { ARC_vpack2hbm, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x1D { ARC_vpack2hblf,AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x1E { ARC_vpack2hbmf,AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x1F { ARC_vext2bhlf, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x20 { ARC_vext2bhmf, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x21 { ARC_vrep2hl, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x22 { ARC_vrep2hm, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x23 { ARC_vext2bhl, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x24 { ARC_vext2bhm, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x25 { ARC_vsext2bhl, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x26 { ARC_vsext2bhm, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x27 { ARC_vabs2h, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x28 { ARC_vabss2h, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x29 { ARC_vneg2h, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x2A { ARC_vnegs2h, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x2B { ARC_vnorm2h, AUX_GEN2|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x2C { 0 }, // 0x2D { ARC_bspeek, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x2E { ARC_bspop, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x2F { ARC_sqrt, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x30 { ARC_sqrtf, AUX_GEN|AUX_V2, {GENB, GENC, 0}, NULL }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { SUBTABLE2(14, 12, 26, 24, arcompact_zop5) }, // 0x3F }; // indexed by bits 21..16 (maj = 5) static const arcompact_opcode_t arcompact_maj5[0x40] = { { ARC_asl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x00 { ARC_lsr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x01 { ARC_asr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x02 { ARC_ror, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x03 { ARC_mul64, AUX_GEN, {O_ZERO,GENB,GENC}, NULL }, // 0x04 { ARC_mulu64, AUX_GEN, {O_ZERO,GENB,GENC}, NULL }, // 0x05 { ARC_adds, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x06 { ARC_subs, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x07 { ARC_divaw, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x08 { 0 }, // 0x09 { ARC_asls, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0A { ARC_asrs, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x0B { ARC_muldw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x0C { ARC_muludw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x0D { ARC_mulrdw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x0E { 0 }, // 0x0F { ARC_macdw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x10 { ARC_macudw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x11 { ARC_macrdw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x12 { 0 }, // 0x13 { ARC_msubdw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { 0 }, // 0x18 { 0 }, // 0x19 { 0 }, // 0x1A { 0 }, // 0x1B { 0 }, // 0x1C { 0 }, // 0x1D { 0 }, // 0x1E { 0 }, // 0x1F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { ARC_addsdw, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x28 { ARC_subsdw, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { SUBTABLE(5, 0, arcompact_sop5) }, // 0x2F { ARC_mululw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x30 { ARC_mullw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x31 { ARC_mulflw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x32 { ARC_maclw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x33 { ARC_macflw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x34 { ARC_machulw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x35 { ARC_machlw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x36 { ARC_machflw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x37 { ARC_mulhlw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x38 { ARC_mulhflw, AUX_GEN, {GENB, GENC, GENC}, NULL }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F }; // indexed by bits 21..16 (maj = 5) static const arcompact_opcode_t arcv2_maj5[0x40 * 2] = { { ARC_asl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x00 { ARC_lsr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x01 { ARC_asr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x02 { ARC_ror, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x03 { ARC_div, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x04 { ARC_divu, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x05 { ARC_adds, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x06 { ARC_subs, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x07 { ARC_rem, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x08 { ARC_remu, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x09 { ARC_asls, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0A { ARC_asrs, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0B { ARC_asrsr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0C { ARC_valgn2h, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x0D(F=0) { ARC_mac, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0E { ARC_macu, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0F { ARC_dmpyh, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x10 { ARC_dmpyhu, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x11 { ARC_dmach, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x12 { ARC_dmachu, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x13 { ARC_vadd2h, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x14(F=0) { ARC_vsub2h, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x15(F=0) { ARC_vaddsub2h,AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x16(F=0) { ARC_vsubadd2h,AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x17(F=0) { ARC_mpyd, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x18 { ARC_mpydu, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x19 { ARC_macd, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x1A { ARC_macdu, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x1B { ARC_vmpy2h, AUX_GEN|AUX_F, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x1C(F=0) { ARC_vmpy2hu, AUX_GEN|AUX_F, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x1D(F=0) { ARC_vmac2h, AUX_GEN|AUX_F, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x1E(F=0) { ARC_vmac2hu, AUX_GEN|AUX_F, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x1F(F=0) { ARC_vmpy2hwf, AUX_GEN|AUX_F, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x20(F=0) { ARC_vasl2h, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x21(F=0) { ARC_vasr2h, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x22(F=0) { ARC_vlsr2h, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x23(F=0) { ARC_vadd4b, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x24(F=0) { ARC_vsub4b, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x25(F=0) { ARC_adcs, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x26 { ARC_sbcs, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x27 { ARC_dmpyhwf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x28 { ARC_vpack2hl, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x29(F=0) { ARC_dmpyhf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2A { ARC_dmpyhfr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2B { ARC_dmachf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2C { ARC_dmachfr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2D { ARC_vperm, AUX_GEN|AUX_F, {GENA, GENB, GENC}, NULL }, // 0x2E { SUBTABLE(5, 0, arcompact_sop5) }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F { 0 }, // 0x00(F=1) { 0 }, // 0x01(F=1) { 0 }, // 0x02(F=1) { 0 }, // 0x03(F=1) { 0 }, // 0x04(F=1) { 0 }, // 0x05(F=1) { 0 }, // 0x06(F=1) { 0 }, // 0x07(F=1) { 0 }, // 0x08(F=1) { 0 }, // 0x09(F=1) { 0 }, // 0x0A(F=1) { 0 }, // 0x0B(F=1) { 0 }, // 0x0C(F=1) { ARC_setacc, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x0D(F=1) { 0 }, // 0x0E(F=1) { 0 }, // 0x0F(F=1) { 0 }, // 0x10(F=1) { 0 }, // 0x11(F=1) { 0 }, // 0x12(F=1) { 0 }, // 0x13(F=1) { ARC_vadds2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x14(F=1) { ARC_vsubs2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x15(F=1) { ARC_vaddsubs2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x16(F=1) { ARC_vsubadds2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x17(F=1) { 0 }, // 0x18(F=1) { 0 }, // 0x19(F=1) { 0 }, // 0x1A(F=1) { 0 }, // 0x1B(F=1) { ARC_vmpy2hf, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x1C(F=1) { ARC_vmpy2hfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x1D(F=1) { ARC_vmac2hf, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x1E(F=1) { ARC_vmac2hfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x1F(F=1) { 0 }, // 0x20(F=1) { ARC_vasls2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x21(F=1) { ARC_vasrs2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x22(F=1) { ARC_vasrsr2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x23(F=1) { ARC_vmax2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x24(F=1) { ARC_vmin2h, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x25(F=1) { 0 }, // 0x26(F=1) { 0 }, // 0x27(F=1) { 0 }, // 0x28(F=1) { ARC_vpack2hm, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x29(F=1) { 0 }, // 0x2A(F=1) { 0 }, // 0x2B(F=1) { 0 }, // 0x2C(F=1) { 0 }, // 0x2D(F=1) { ARC_bspush, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x2E(F=1) { 0 }, // 0x2F(F=1) { 0 }, // 0x30(F=1) { 0 }, // 0x31(F=1) { 0 }, // 0x32(F=1) { 0 }, // 0x33(F=1) { 0 }, // 0x34(F=1) { 0 }, // 0x35(F=1) { 0 }, // 0x36(F=1) { 0 }, // 0x37(F=1) { 0 }, // 0x38(F=1) { 0 }, // 0x39(F=1) { 0 }, // 0x3A(F=1) { 0 }, // 0x3B(F=1) { 0 }, // 0x3C(F=1) { 0 }, // 0x3D(F=1) { 0 }, // 0x3E(F=1) { 0 }, // 0x3F(F=1) }; // indexed by bits 21..16 static const arcompact_opcode_t arcompact_maj6_1[0x40] = { { ARC_fmul, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 00 { ARC_fadd, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 01 { ARC_fsub, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 02 { 0 }, // 03 { 0 }, // 04 { 0 }, // 05 { 0 }, // 06 { 0 }, // 07 { ARC_dmulh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 08 { ARC_dmulh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 09 { ARC_dmulh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0a { ARC_dmulh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0b { ARC_daddh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0c { ARC_daddh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0d { ARC_daddh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0e { ARC_daddh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0f { ARC_dsubh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 10 { ARC_dsubh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 11 { ARC_dsubh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 12 { ARC_dsubh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 13 { ARC_drsubh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 14 { ARC_drsubh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 15 { ARC_drsubh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 16 { ARC_drsubh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 17 { ARC_dexcl1, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 18 { ARC_dexcl2, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 19 { 0 }, // 1a { 0 }, // 1b { 0 }, // 1c { 0 }, // 1d { 0 }, // 1e { 0 }, // 1f { ARC_pkqb, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 20 { ARC_upkqb, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 21 { ARC_xpkqb, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 22 { ARC_avgqb, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 23 { ARC_addqbs, AUX_GEN, {GENA, GENB, GENC}, NULL },// 24 { ARC_mpyqb, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 25 { ARC_fxtr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 26 { ARC_iaddr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 27 { ARC_acm, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 28 { ARC_sfxtr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 29 { ARC_clamp, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 2a { 0 }, // 2b { 0 }, // 2c { 0 }, // 2d { 0 }, // 2e { 0 }, // 2f { 0 }, // 30 { 0 }, // 31 { 0 }, // 32 { 0 }, // 33 { 0 }, // 34 { 0 }, // 35 { 0 }, // 36 { 0 }, // 37 { 0 }, // 38 { 0 }, // 39 { 0 }, // 3a { 0 }, // 3b { 0 }, // 3c { 0 }, // 3d { 0 }, // 3e { 0 } // 3f }; // indexed by bits 23..22 static const arcompact_opcode_t arcompact_maj6[4] = { { SUBTABLE(21, 16, arcompact_maj6_1) }, // 00 { SUBTABLE(21, 16, arcompact_maj6_1) }, // 01 { SUBTABLE(21, 16, arcompact_maj6_1) }, // 02 { 0 } // to be implemented }; // indexed by bits 5..0 (maj = 6, 21..16=0x2F) static const arcompact_opcode_t arcv2_sop6[0x40] = { { ARC_fssqrt, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x00(F=0) reference doesn't specify minor opcode { 0 }, // 0x01 { 0 }, // 0x02 { 0 }, // 0x03 { 0 }, // 0x04 { 0 }, // 0x05 { 0 }, // 0x06 { 0 }, // 0x07 { 0 }, // 0x08 { 0 }, // 0x09 { 0 }, // 0x0A { 0 }, // 0x0B { 0 }, // 0x0C { 0 }, // 0x0D { 0 }, // 0x0E { 0 }, // 0x0F { 0 }, // 0x10 { 0 }, // 0x11 { 0 }, // 0x12 { 0 }, // 0x13 { 0 }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { 0 }, // 0x18 { 0 }, // 0x18 { 0 }, // 0x1A { ARC_cbflyhf1r, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x1B(F=0) according to reference { 0 }, // 0x1C { 0 }, // 0x1D { 0 }, // 0x1E { 0 }, // 0x1F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { 0 }, // 0x28 { 0 }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { 0 }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { ARC_cbflyhf1r, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x39(F=0) as encoded by the toolchain { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F }; static const arcompact_opcode_t arcv2_maj6[0x40 * 2] = { { ARC_fmul, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x00(F=0) { ARC_fadd, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x01(F=0) { ARC_fsub, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x02(F=0) { ARC_vmsub2hfr, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x03(F=0) { ARC_vmsub2hf, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x04(F=0) { ARC_fsmadd, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x05(F=0) { ARC_fsmsub, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x06(F=0) { ARC_fsdiv, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x07(F=0) { ARC_fcvt32, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x08(F=0) { 0, AUX_F, {0, 0, 0}, NULL }, // 0x09(F=0) { ARC_mpyf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0A { ARC_mpyfr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0B { ARC_macf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0C { ARC_macfr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0D { ARC_msubf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0E { ARC_msubfr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x0F { ARC_divf, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x10 { ARC_vmac2hnfr, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x11 { ARC_mpydf, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x12 { ARC_macdf, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x13 { ARC_msubwhfl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x14 { ARC_msubdf, AUX_GEN, {GENA|O_WIDE, GENB, GENC}, NULL }, // 0x15 { ARC_dmpyhbl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x16 { ARC_dmpyhbm, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x17 { ARC_dmachbl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x18 { ARC_dmachbm, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x19 { ARC_msubwhflr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1A { ARC_cmpyhfmr, AUX_GEN|AUX_F,{GENA, GENB, GENC}, NULL }, // 0x1B { ARC_mpywhl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1C { ARC_macwhl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1D { ARC_mpywhul, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1E { ARC_macwhul, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x1F { ARC_mpywhfm, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x20 { ARC_mpywhfmr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x21 { ARC_macwhfm, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x22 { ARC_macwhfmr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x23 { ARC_mpywhfl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x24 { ARC_mpywhflr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x25 { ARC_macwhfl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x26 { ARC_macwhflr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x27 { ARC_macwhkl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x28 { ARC_macwhkul, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x29 { ARC_mpywhkl, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2A { ARC_mpywhkul, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2B { ARC_msubwhfm, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2C { ARC_msubwhfmr, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x2D { 0 }, // 0x2E { SUBTABLE(5, 0, arcv2_sop6) }, // 0x2F { ARC_dmulh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x30 { ARC_dmulh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x31 { ARC_dmulh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x32 { ARC_dmulh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x33 { ARC_daddh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x34 { ARC_daddh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x35 { ARC_daddh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x36 { ARC_daddh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x37 { ARC_dsubh11, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x38 { ARC_dsubh12, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x39 { ARC_dsubh21, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3A { ARC_dsubh22, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3B { ARC_dexcl1, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3C { ARC_dexcl2, AUX_GEN, {GENA, GENB, GENC}, NULL }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F { ARC_cmpyhnfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x00 { ARC_cmpyhfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x01 { ARC_cmpychnfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x02 { ARC_fscmp, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x03 { ARC_fscmpf, AUX_GEN2, {GENB, GENC, 0}, NULL }, // 0x04 { ARC_cmpychfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x05 { ARC_cmachnfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x06 { ARC_cmachfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x07 { ARC_cmacchnfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x08 { ARC_cmacchfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x09 { 0 }, // 0x0A { 0 }, // 0x0B { 0 }, // 0x0C { 0 }, // 0x0D { 0 }, // 0x0E { 0 }, // 0x0F { 0 }, // 0x10 { ARC_vmsub2hnfr, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x11 { 0 }, // 0x12 { 0 }, // 0x13 { 0 }, // 0x14 { 0 }, // 0x15 { 0 }, // 0x16 { 0 }, // 0x17 { 0 }, // 0x18 { 0 }, // 0x19 { 0 }, // 0x1A { ARC_cbflyhf0r, AUX_GEN2, {GENA, GENB, GENC}, NULL }, // 0x1B { 0 }, // 0x1C { 0 }, // 0x1D { 0 }, // 0x1E { 0 }, // 0x1F { 0 }, // 0x20 { 0 }, // 0x21 { 0 }, // 0x22 { 0 }, // 0x23 { 0 }, // 0x24 { 0 }, // 0x25 { 0 }, // 0x26 { 0 }, // 0x27 { 0 }, // 0x28 { 0 }, // 0x29 { 0 }, // 0x2A { 0 }, // 0x2B { 0 }, // 0x2C { 0 }, // 0x2D { 0 }, // 0x2E { 0 }, // 0x2F { 0 }, // 0x30 { 0 }, // 0x31 { 0 }, // 0x32 { 0 }, // 0x33 { 0 }, // 0x34 { 0 }, // 0x35 { 0 }, // 0x36 { 0 }, // 0x37 { 0 }, // 0x38 { 0 }, // 0x39 { 0 }, // 0x3A { 0 }, // 0x3B { 0 }, // 0x3C { 0 }, // 0x3D { 0 }, // 0x3E { 0 }, // 0x3F }; // indexed by bits 4..3 (maj = 0xC) static const arcompact_opcode_t arcompact_maj0C[4] = { { ARC_ld, 0, { fA16, fBC16_IND, 0}, NULL }, // 0x0 { ARC_ld, AUX_B, { fA16, fBC16_IND, 0}, NULL }, // 0x1 { ARC_ld, AUX_W, { fA16, fBC16_IND, 0}, NULL }, // 0x2 { ARC_add, 0, { fA16, fB16, fC16 }, NULL }, // 0x3 }; // indexed by bits 4..3 (maj = 0xD) static const arcompact_opcode_t arcompact_maj0D[4] = { { ARC_add, 0, {fC16, fB16, U3 }, NULL }, // 0x00 { ARC_sub, 0, {fC16, fB16, U3 }, NULL }, // 0x01 { ARC_asl, 0, {fC16, fB16, U3 }, NULL }, // 0x02 { ARC_asr, 0, {fC16, fB16, U3 }, NULL }, // 0x03 }; // indexed by bits 4..3 (maj = 0xE) static const arcompact_opcode_t arcompact_maj0E[4] = { { ARC_add, 0, {fB16, fB16, fH16}, NULL }, // 0x00 { ARC_mov, 0, {fB16, fH16, 0 }, NULL }, // 0x01 { ARC_cmp, 0, {fB16, fH16, 0 }, NULL }, // 0x02 { ARC_mov, 0, {fH16, fB16, 0 }, NULL }, // 0x03 }; // indexed by bits 4..3 (maj = 0xE) static const arcompact_opcode_t arcv2_maj0E[8] = { { ARC_add, 0, {fB16, fB16, fH16v2}, NULL }, // 0x00 { ARC_add, 0, {fH16v2, fH16v2, S3 }, NULL }, // 0x01 { 0 }, // 0x02 { ARC_mov, 0, {fH16v2, S3, 0 }, NULL }, // 0x03 { ARC_cmp, 0, {fB16, fH16v2, 0 }, NULL }, // 0x04 { ARC_cmp, 0, {fH16v2, S3, 0 }, NULL }, // 0x05 { 0 }, // 0x06 { ARC_mov, AUX_CND|cNE, {fB16, fH16v2, 0 }, NULL }, // 0x07 }; // indexed by bits 10..8 (maj = 0xF, 4..0 = 0x0, 7..5=0x7) // 01111 iii 111 00000 static const arcompact_opcode_t arcompact_zop16[8] = { { ARC_nop, 0, { 0, 0, 0}, NULL }, // 0x00 { ARC_unimp, 0, { 0, 0, 0}, NULL }, // 0x01 { ARC_swi, 0, { 0, 0, 0}, NULL }, // 0x02 { 0 }, // 0x03 { ARC_j, AUX_CND|cEQ, {R_BLINK|O_IND, 0, 0}, NULL }, // 0x04 { ARC_j, AUX_CND|cNE, {R_BLINK|O_IND, 0, 0}, NULL }, // 0x05 { ARC_j, 0, {R_BLINK|O_IND, 0, 0}, NULL }, // 0x06 { ARC_j, AUX_D, {R_BLINK|O_IND, 0, 0}, NULL }, // 0x07 }; // indexed by bits 7..5 (maj = 0xF, 4..0 = 0x0) // 01111 bbb iii 00000 static const arcompact_opcode_t arcompact_sop16[8] = { { ARC_j, 0, {fB16|O_IND, 0, 0}, NULL }, // 0x00 { ARC_j, AUX_D, {fB16|O_IND, 0, 0}, NULL }, // 0x01 { ARC_jl, 0, {fB16|O_IND, 0, 0}, NULL }, // 0x02 { ARC_jl, AUX_D, {fB16|O_IND, 0, 0}, NULL }, // 0x03 { 0 }, // 0x04 { 0 }, // 0x05 { ARC_sub, AUX_CND|cNE, {fB16, fB16, fB16}, NULL }, // 0x06 { SUBTABLE(10, 8, arcompact_zop16) }, // 0x07 }; // indexed by bits 4..0 (maj = 0xF) // 01111 bbb ccc iiiii static const arcompact_opcode_t arcompact_maj0F[0x20] = { { SUBTABLE(7, 5, arcompact_sop16) }, // 0x00 { 0 }, // 0x01 { ARC_sub, 0, {fB16, fB16, fC16}, NULL }, // 0x02 { 0 }, // 0x03 { ARC_and, 0, {fB16, fB16, fC16}, NULL }, // 0x04 { ARC_or, 0, {fB16, fB16, fC16}, NULL }, // 0x05 { ARC_bic, 0, {fB16, fB16, fC16}, NULL }, // 0x06 { ARC_xor, 0, {fB16, fB16, fC16}, NULL }, // 0x05 { 0 }, // 0x08 { 0 }, // 0x09 { 0 }, // 0x0A { ARC_tst, 0, {fB16, fC16, 0 }, NULL }, // 0x0B { ARC_mul64, 0, {fB16, fC16, 0 }, NULL }, // 0x0C { ARC_sexb, 0, {fB16, fC16, 0 }, NULL }, // 0x0D { ARC_sexw, 0, {fB16, fC16, 0 }, NULL }, // 0x0E { ARC_extb, 0, {fB16, fC16, 0 }, NULL }, // 0x0F { ARC_extw, 0, {fB16, fC16, 0 }, NULL }, // 0x10 { ARC_abs, 0, {fB16, fC16, 0 }, NULL }, // 0x11 { ARC_not, 0, {fB16, fC16, 0 }, NULL }, // 0x12 { ARC_neg, 0, {fB16, fC16, 0 }, NULL }, // 0x13 { ARC_add1, 0, {fB16, fB16, fC16}, NULL }, // 0x14 { ARC_add2, 0, {fB16, fB16, fC16}, NULL }, // 0x15 { ARC_add3, 0, {fB16, fB16, fC16}, NULL }, // 0x16 { 0 }, // 0x17 { ARC_asl, 0, {fB16, fB16, fC16}, NULL }, // 0x18 { ARC_lsr, 0, {fB16, fB16, fC16}, NULL }, // 0x19 { ARC_asr, 0, {fB16, fB16, fC16}, NULL }, // 0x1A { ARC_asl, 0, {fB16, fC16, 0 }, NULL }, // 0x1B { ARC_asr, 0, {fB16, fC16, 0 }, NULL }, // 0x1C { ARC_lsr, 0, {fB16, fC16, 0 }, NULL }, // 0x1D { ARC_trap, 0, { 0, 0, 0 }, NULL }, // 0x1E { ARC_brk, 0, { 0, 0, 0 }, NULL }, // 0x1F }; // indexed by bits 4..0 (maj = 0xF) // 01111 bbb ccc iiiii static const arcompact_opcode_t arcv2_maj0F[0x20] = { { SUBTABLE(7, 5, arcompact_sop16) }, // 0x00 { 0 }, // 0x01 { ARC_sub, 0, {fB16, fB16, fC16}, NULL }, // 0x02 { 0 }, // 0x03 { ARC_and, 0, {fB16, fB16, fC16}, NULL }, // 0x04 { ARC_or, 0, {fB16, fB16, fC16}, NULL }, // 0x05 { ARC_bic, 0, {fB16, fB16, fC16}, NULL }, // 0x06 { ARC_xor, 0, {fB16, fB16, fC16}, NULL }, // 0x05 { 0 }, // 0x08 { ARC_mpyw, 0, {fB16, fB16, fC16}, NULL }, // 0x09 { ARC_mpyuw, 0, {fB16, fB16, fC16}, NULL }, // 0x0A { ARC_tst, 0, {fB16, fC16, 0 }, NULL }, // 0x0B { ARC_mpy, 0, {fB16, fB16, fC16}, NULL }, // 0x0C breaking change { ARC_sexb, 0, {fB16, fC16, 0 }, NULL }, // 0x0D { ARC_sexw, 0, {fB16, fC16, 0 }, NULL }, // 0x0E { ARC_extb, 0, {fB16, fC16, 0 }, NULL }, // 0x0F { ARC_extw, 0, {fB16, fC16, 0 }, NULL }, // 0x10 { ARC_abs, 0, {fB16, fC16, 0 }, NULL }, // 0x11 { ARC_not, 0, {fB16, fC16, 0 }, NULL }, // 0x12 { ARC_neg, 0, {fB16, fC16, 0 }, NULL }, // 0x13 { ARC_add1, 0, {fB16, fB16, fC16}, NULL }, // 0x14 { ARC_add2, 0, {fB16, fB16, fC16}, NULL }, // 0x15 { ARC_add3, 0, {fB16, fB16, fC16}, NULL }, // 0x16 { 0 }, // 0x17 { ARC_asl, 0, {fB16, fB16, fC16}, NULL }, // 0x18 { ARC_lsr, 0, {fB16, fB16, fC16}, NULL }, // 0x19 { ARC_asr, 0, {fB16, fB16, fC16}, NULL }, // 0x1A { ARC_asl, 0, {fB16, fC16, 0 }, NULL }, // 0x1B { ARC_asr, 0, {fB16, fC16, 0 }, NULL }, // 0x1C { ARC_lsr, 0, {fB16, fC16, 0 }, NULL }, // 0x1D { ARC_trap, 0, {U6_SWI, 0, 0 }, NULL }, // 0x1E { ARC_swi, 0, {U6_SWI, 0, 0 }, NULL }, // 0x1F }; // indexed by bits 7..5 (maj = 0x17) static const arcompact_opcode_t arcompact_maj17[8] = { { ARC_asl, 0, {fB16, fB16, U5}, NULL }, // 0x00 { ARC_lsr, 0, {fB16, fB16, U5}, NULL }, // 0x01 { ARC_asr, 0, {fB16, fB16, U5}, NULL }, // 0x02 { ARC_sub, 0, {fB16, fB16, U5}, NULL }, // 0x03 { ARC_bset, 0, {fB16, fB16, U5}, NULL }, // 0x04 { ARC_bclr, 0, {fB16, fB16, U5}, NULL }, // 0x05 { ARC_bmsk, 0, {fB16, fB16, U5}, NULL }, // 0x06 { ARC_btst, 0, {fB16, U5, 0}, NULL }, // 0x07 }; // indexed by bits 10..8 (maj = 0x18, i=5) static const arcompact_opcode_t arcompact_sp_addsub[8] = { { ARC_add, 0, {R_SP, R_SP, U7L }, NULL }, // 0x00 { ARC_sub, 0, {R_SP, R_SP, U7L }, NULL }, // 0x01 { 0 }, // 0x02 { 0 }, // 0x03 { 0 }, // 0x04 { 0 }, // 0x05 { 0 }, // 0x06 { 0 }, // 0x07 }; // indexed by bits 4..0 (maj = 0x18, i=6) static const arcompact_opcode_t arcompact_sp_pops[0x20] = { { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x00 { ARC_pop, 0, {fB16, 0, 0}, NULL }, // 0x01 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x02 { 0 }, // 0x03 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x04 { 0 }, // 0x05 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x06 { 0 }, // 0x07 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x08 { 0 }, // 0x09 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x0A { 0 }, // 0x0B { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x0C { 0 }, // 0x0D { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x0E { 0 }, // 0x0F { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x10 { ARC_pop, 0, {R_BLINK, 0, 0}, NULL }, // 0x11 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x12 { 0 }, // 0x13 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x14 { 0 }, // 0x15 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x16 { 0 }, // 0x17 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x18 { 0 }, // 0x19 { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x1A { 0 }, // 0x1B { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x1C { 0 }, // 0x1D { ARC_leave, AUX_V2, {EL, 0, 0}, NULL }, // 0x1E { 0 }, // 0x1F }; // indexed by bits 4..0 (maj = 0x18, i=7) static const arcompact_opcode_t arcompact_sp_pushs[0x20] = { { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x00 { ARC_push, 0, {fB16, 0, 0}, NULL }, // 0x01 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x02 { 0 }, // 0x03 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x04 { 0 }, // 0x05 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x06 { 0 }, // 0x07 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x08 { 0 }, // 0x09 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x0A { 0 }, // 0x0B { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x0C { 0 }, // 0x0D { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x0E { 0 }, // 0x0F { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x10 { ARC_push, 0, {R_BLINK, 0, 0}, NULL }, // 0x11 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x12 { 0 }, // 0x13 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x14 { 0 }, // 0x15 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x16 { 0 }, // 0x17 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x18 { 0 }, // 0x19 { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x1A { 0 }, // 0x1B { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x1C { 0 }, // 0x1D { ARC_enter, AUX_V2, {EL, 0, 0}, NULL }, // 0x1E { 0 }, // 0x1F }; // indexed by bits 7..5 (maj = 0x18) // sp-based instructions static const arcompact_opcode_t arcompact_maj18[8] = { { ARC_ld, 0, {fB16, SP_U7, 0 }, NULL }, // 0x00 { ARC_ld, AUX_B, {fB16, SP_U7, 0 }, NULL }, // 0x01 { ARC_st, 0, {fB16, SP_U7, 0 }, NULL }, // 0x02 { ARC_st, AUX_B, {fB16, SP_U7, 0 }, NULL }, // 0x03 { ARC_add, 0, {fB16, R_SP, U7L }, NULL }, // 0x04 { SUBTABLE( 10, 8, arcompact_sp_addsub) }, // 0x05 { SUBTABLE( 4, 0, arcompact_sp_pops) }, // 0x06 { SUBTABLE( 4, 0, arcompact_sp_pushs) }, // 0x07 }; // indexed by bits 10..9 (maj = 0x19) // gp-based ld/add (data aligned offset) static const arcompact_opcode_t arcompact_maj19[4] = { { ARC_ld, 0, {R_R0, GP_S11, 0 }, NULL }, // 0x00 { ARC_ld, AUX_B, {R_R0, GP_S9, 0 }, NULL }, // 0x01 { ARC_ld, AUX_W, {R_R0, GP_S10, 0 }, NULL }, // 0x02 { ARC_add, 0, {R_R0, R_GP, S11 }, NULL }, // 0x03 }; // indexed by bits 7..7 (maj = 0x1C) static const arcompact_opcode_t arcompact_maj1C[2] = { { ARC_add, 0, { fB16, fB16, U7}, NULL }, // 0x00 { ARC_cmp, 0, { fB16, U7, 0}, NULL }, // 0x01 }; // indexed by bits 7..7 (maj = 0x1D) static const arcompact_opcode_t arcompact_maj1D[2] = { { ARC_br, AUX_CND|cEQ, { fB16, O_ZERO, S8}, NULL }, // 0x00 { ARC_br, AUX_CND|cNE, { fB16, O_ZERO, S8}, NULL }, // 0x01 }; // indexed by bits 8..6 (maj = 0x1E, 10..9=0x3) static const arcompact_opcode_t arcompact_bcc16[8] = { { ARC_b, AUX_CND|cGT, { S7, 0, 0}, NULL }, // 0x00 { ARC_b, AUX_CND|cGE, { S7, 0, 0}, NULL }, // 0x01 { ARC_b, AUX_CND|cLT, { S7, 0, 0}, NULL }, // 0x02 { ARC_b, AUX_CND|cLE, { S7, 0, 0}, NULL }, // 0x03 { ARC_b, AUX_CND|cHI, { S7, 0, 0}, NULL }, // 0x04 { ARC_b, AUX_CND|cHS, { S7, 0, 0}, NULL }, // 0x05 { ARC_b, AUX_CND|cLO, { S7, 0, 0}, NULL }, // 0x06 { ARC_b, AUX_CND|cLS, { S7, 0, 0}, NULL }, // 0x07 }; // indexed by bits 10..9 (maj = 0x1E) static const arcompact_opcode_t arcompact_maj1E[4] = { { ARC_b, 0, { S10, 0, 0}, NULL }, // 0x00 { ARC_b, AUX_CND|cEQ, { S10, 0, 0}, NULL }, // 0x01 { ARC_b, AUX_CND|cNE, { S10, 0, 0}, NULL }, // 0x02 { SUBTABLE(8, 6, arcompact_bcc16) }, // 0x03 }; // indexed by major opcode (bits 15..11) static const arcompact_opcode_t arcompact_major[0x20] = { { SUBTABLE(16, 16, arcompact_maj0) }, // 0x00 { SUBTABLE(16, 16, arcompact_maj1) }, // 0x01 { ARC_ld, DAAZZX_11_6, {fA32, fB_S9, 0}, NULL},// 0x02 { ARC_st, DAAZZ_5_1, {fC32, fB_S9, 0}, NULL},// 0x03 { SUBTABLE(21, 16, arcompact_maj4) }, // 0x04 { SUBTABLE(21, 16, arcompact_maj5) }, // 0x05 { SUBTABLE(23, 22, arcompact_maj6) }, // 0x06 { 0 }, // 0x07 { 0 }, // 0x08 { 0 }, // 0x09 { 0 }, // 0x0A { 0 }, // 0x0B { SUBTABLE( 4, 3, arcompact_maj0C) }, // 0x0C { SUBTABLE( 4, 3, arcompact_maj0D) }, // 0x0D { SUBTABLE( 4, 3, arcompact_maj0E) }, // 0x0E { SUBTABLE( 4, 0, arcompact_maj0F) }, // 0x0F { ARC_ld, 0, { fC16, fB_U7, 0}, NULL }, // 0x10 { ARC_ld, AUX_B, { fC16, fB_U5, 0}, NULL }, // 0x11 { ARC_ld, AUX_W, { fC16, fB_U6, 0}, NULL }, // 0x12 { ARC_ld, AUX_W|AUX_X, { fC16, fB_U6, 0}, NULL },// 0x13 { ARC_st, 0, { fC16, fB_U7, 0}, NULL }, // 0x14 { ARC_st, AUX_B, { fC16, fB_U5, 0}, NULL }, // 0x15 { ARC_st, AUX_W, { fC16, fB_U6, 0}, NULL }, // 0x16 { SUBTABLE( 7, 5, arcompact_maj17) }, // 0x17 { SUBTABLE( 7, 5, arcompact_maj18) }, // 0x18 { SUBTABLE(10, 9, arcompact_maj19) }, // 0x19 { ARC_ld, 0, { fB16, PCL_U10, 0}, NULL }, // 0x1A { ARC_mov, 0, { fB16, U8, 0}, NULL }, // 0x1B { SUBTABLE( 7, 7, arcompact_maj1C) }, // 0x1C { SUBTABLE( 7, 7, arcompact_maj1D) }, // 0x1D { SUBTABLE(10, 9, arcompact_maj1E) }, // 0x1E { ARC_bl, 0, { S13, 0, 0}, NULL }, // 0x1F }; // indexed by bit 2 (maj = 8) static const arcompact_opcode_t arcv2_maj8[2] = { { ARC_mov, 0, {fG16, fH16v2, 0}, NULL }, // 0x00 { ARC_ld, 0, {fR16_2, fH16v2_U5, 0}, NULL }, // 0x01 }; // indexed by bits 4..3 (maj = 8) static const arcompact_opcode_t arcv2_maj9[4] = { { ARC_ld, AUX_AS, {fA16, fBC16_IND, 0}, NULL }, // 0x00 { ARC_add, 0, {fR16_1, fB16, U6_16}, NULL }, // 0x01 { ARC_sub, 0, {fA16, fB16, fC16}, NULL }, // 0x02 { ARC_add, 0, {fR16_1, fB16, U6_16}, NULL }, // 0x03 }; // indexed by bits 4..3 (maj = 0x0A) static const arcompact_opcode_t arcv2_maj0A[4] = { { ARC_ld, 0, {R_R1, GP_S11_16, 0}, NULL }, // 0x00 { ARC_ldi, 0, {fB16, U7_16|O_IDX, 0}, NULL }, // 0x01 { ARC_st, 0, {R_R0, GP_S11_16, 0}, NULL }, // 0x02 { ARC_ldi, 0, {fB16, U7_16|O_IDX, 0}, NULL }, // 0x03 }; // indexed by bit 10 (maj = 0x0B) static const arcompact_opcode_t arcv2_maj0B[2] = { { ARC_jli, 0, {U10_16|O_IDX, 0, 0}, NULL }, // 0x00 { ARC_ei, 0, {U10_16|O_IDX, 0, 0}, NULL }, // 0x01 }; // indexed by major opcode (bits 15..11) static const arcompact_opcode_t arcv2_major[0x20] = { { SUBTABLE(16, 16, arcompact_maj0) }, // 0x00 { SUBTABLE(16, 16, arcompact_maj1) }, // 0x01 { ARC_ld, DAAZZX_11_6, {fA32, fB_S9, 0}, NULL},// 0x02 { ARC_st, DAAZZ_5_1, {fC32_w6, fB_S9, 0}, NULL},// 0x03 { SUBTABLE(21, 16, arcompact_maj4) }, // 0x04 { SUBTABLE(21, 16, arcv2_maj5) }, // 0x05 { SUBTABLE(21, 16, arcv2_maj6) }, // 0x06 { 0 }, // 0x07 { SUBTABLE( 2, 2, arcv2_maj8) }, // 0x08 { SUBTABLE( 4, 3, arcv2_maj9) }, // 0x09 { SUBTABLE( 4, 3, arcv2_maj0A) }, // 0x0A { SUBTABLE(10, 10, arcv2_maj0B) }, // 0x0B { SUBTABLE( 4, 3, arcompact_maj0C) }, // 0x0C { SUBTABLE( 4, 3, arcompact_maj0D) }, // 0x0D { SUBTABLE( 4, 2, arcv2_maj0E) }, // 0x0E { SUBTABLE( 4, 0, arcv2_maj0F) }, // 0x0F { ARC_ld, 0, { fC16, fB_U7, 0}, NULL }, // 0x10 { ARC_ld, AUX_B, { fC16, fB_U5, 0}, NULL }, // 0x11 { ARC_ld, AUX_W, { fC16, fB_U6, 0}, NULL }, // 0x12 { ARC_ld, AUX_W|AUX_X, { fC16, fB_U6, 0}, NULL }, // 0x13 { ARC_st, 0, { fC16, fB_U7, 0}, NULL }, // 0x14 { ARC_st, AUX_B, { fC16, fB_U5, 0}, NULL }, // 0x15 { ARC_st, AUX_W, { fC16, fB_U6, 0}, NULL }, // 0x16 { SUBTABLE( 7, 5, arcompact_maj17) }, // 0x17 { SUBTABLE( 7, 5, arcompact_maj18) }, // 0x18 { SUBTABLE(10, 9, arcompact_maj19) }, // 0x19 { ARC_ld, 0, { fB16, PCL_U10, 0}, NULL }, // 0x1A { ARC_mov, 0, { fB16, U8, 0}, NULL }, // 0x1B { SUBTABLE( 7, 7, arcompact_maj1C) }, // 0x1C { SUBTABLE( 7, 7, arcompact_maj1D) }, // 0x1D { SUBTABLE(10, 9, arcompact_maj1E) }, // 0x1E { ARC_bl, 0, { S13, 0, 0}, NULL }, // 0x1F }; // extract bit numbers high..low from val (inclusive, start from 0) #define BITS(val, high, low) ( ((val)>>low) & ( (1<<(high-low+1))-1) ) // sign extend b low bits in x // from "Bit Twiddling Hacks" static sval_t SIGNEXT(sval_t x, int b) { uint32 m = 1 << (b - 1); x &= ((sval_t(1) << b) - 1); return (x ^ m) - m; } // extract bitfield with sign extension #define SBITS(val, high, low) SIGNEXT(BITS(val, high, low), high-low+1) //---------------------------------------------------------------------- int arc_t::get_limm(insn_t &insn) { if ( !got_limm ) { g_limm = (insn.get_next_word() << 16); g_limm |= insn.get_next_word(); got_limm = true; } return g_limm; } //---------------------------------------------------------------------- // register, or a reference to long immediate (r62) inline void arc_t::opreg(insn_t &insn, op_t &x, int rgnum, int limm) { if ( rgnum != limm ) { x.reg = uint16(rgnum); x.type = o_reg; } else { x.type = o_imm; // limm as destination is not used // so check for instructions where first operand is source if ( x.n == 0 && (insn.get_canon_feature(ph) & CF_CHG1) != 0 ) x.value = 0; else x.value = get_limm(insn); } x.dtype = dt_dword; } //---------------------------------------------------------------------- inline void opimm(op_t &x, uval_t val) { x.value = val; x.type = o_imm; x.dtype = dt_dword; } //---------------------------------------------------------------------- inline void arc_t::opdisp(insn_t &insn, op_t &x, int rgnum, ea_t disp) { if ( rgnum != LIMM ) { x.type = o_displ; x.addr = disp; x.reg = rgnum; } else { x.type = o_mem; x.immdisp = disp; x.addr = get_limm(insn) + disp * get_scale_factor(insn); } x.dtype = dt_dword; } //---------------------------------------------------------------------- inline int reg16(int rgnum) { // 0..3 r0-r3 // 4..7 r12-r15 return ( rgnum > 3 ) ? (rgnum + 8) : rgnum; } //---------------------------------------------------------------------- inline void opbranch(const insn_t &insn, op_t &x, sval_t delta) { // cPC <- (cPCL+delta) // PCL is current instruction address with 2 low bits set to 0 ea_t pcl = insn.ip & ~3ul; x.type = o_near; x.dtype = dt_code; x.addr = pcl + delta; } //---------------------------------------------------------------------- void arc_t::decode_operand( insn_t &insn, uint32 code, int &op_pos, uint32 opkind) { op_t &x = insn.ops[op_pos]; ++op_pos; if ( opkind == 0 ) { x.type = o_void; return; } int reg, p; sval_t displ; switch ( opkind & ~O_FLAGS ) { case fA16: opreg(insn, x, reg16(BITS(code, 2, 0))); break; case fB16: opreg(insn, x, reg16(BITS(code, 10, 8))); break; case fC16: opreg(insn, x, reg16(BITS(code, 7, 5))); break; case fA32: // 5..0 a register operand (6 bits, r0-r63) opreg(insn, x, BITS(code, 5, 0)); break; case fB32: // 14..12 & 26..24 b register operand (6 bits) opreg(insn, x, (BITS(code, 14, 12)<<3) | BITS(code, 26, 24)); break; case fC32: // 11..6 c register operand (6 bits) opreg(insn, x, BITS(code, 11, 6)); break; case fC32_w6: // 11..6 & 0 c/w6 register/immediate operand (6 bits) if ( BITS(code, 0, 0) != 0 ) opimm(x, SBITS(code, 11, 6)); else opreg(insn, x, BITS(code, 11, 6)); break; case fH16: // 2..0 & 7..5 h register operand (6 bits) reg = (BITS(code, 2, 0) << 3) | BITS(code, 7, 5); opreg(insn, x, reg); break; case fH16v2: // 1..0 & 7..5 h register operand (5 bits) reg = (BITS(code, 1, 0) << 3) | BITS(code, 7, 5); opreg(insn, x, reg, LIMM5); break; case fH16v2_U5: // 1..0 & 7..5, 10&4..3 [h, u5] (u5=u3*4) displ = ((BITS(code, 10, 10) << 2) | BITS(code, 4, 3)) * 4; reg = (BITS(code, 1, 0) << 3) | BITS(code, 7, 5); opdisp(insn, x, reg, displ); break; case fG16: // 4..3 & 10..8 g register operand (5 bits) reg = (BITS(code, 4, 3) << 3) | BITS(code, 10, 8); opreg(insn, x, reg, LIMM5); break; case fR16_2: // 9..8 R register operand (2 bits) opreg(insn, x, BITS(code, 9, 8)); break; case fR16_1: // 7 R register operand (1 bits) opreg(insn, x, BITS(code, 7, 7)); break; case S25L: // 15..6 & 26..18 & 0..3 s25 signed branch displacement for branch and link case S21L: // 15..6 & 26..18 s21 signed branch displacement for branch and link case S25: // 15..6 & 26..17 & 3..0 s25 signed branch displacement case S21: // 15..6 & 26..17 s21 signed branch displacement displ = (BITS(code, 15, 6) << 10) | BITS(code, 26, 17); if ( opkind == S25 || opkind == S25L ) { displ |= BITS(code, 3, 0) << 20; if ( displ & (1ul<<23) ) displ -= (1ul<<24); } else { if ( displ & (1ul<<19) ) displ -= (1ul<<20); } if ( opkind == S25L || opkind == S21L ) { // branch-and-link uses 32-bit aligned target displ &= ~1ul; } opbranch(insn, x, displ * 2); break; case S9: // 15&23..17 s9 signed branch displacement (16-bit aligned) displ = BITS(code, 23, 17); if ( BITS(code, 15, 15) ) // sign bit displ -= (1ul<<7); opbranch(insn, x, displ * 2); break; case S7: // 5..0 s7 signed branch displacement (16-bit aligned) displ = SBITS(code, 5, 0); opbranch(insn, x, displ * 2); break; case S8: // 6..0 s8 signed branch displacement (16-bit aligned) displ = SBITS(code, 6, 0); opbranch(insn, x, displ * 2); break; case S10: // 8..0 s10 signed branch displacement (16-bit aligned) displ = SBITS(code, 8, 0); opbranch(insn, x, displ * 2); break; case S13: // 10..0 s13 signed branch displacement (32-bit aligned) displ = SBITS(code, 10, 0); opbranch(insn, x, displ * 4); break; case PCL_U10: displ = BITS(code, 7, 0); opdisp(insn, x, PCL, displ*4); break; case SP_U7: // 4..0 [SP, u7] stack + offset (u7 = u5*4) displ = BITS(code, 4, 0); opdisp(insn, x, SP, displ*4); break; case S3: // 10..8 s3 signed immediate p = BITS(code, 10, 8); opimm(x, p == 7 ? -1 : p); break; case U3: // 2..0 u2 unsigned immediate opimm(x, BITS(code, 2, 0)); break; case U7: opimm(x, BITS(code, 6, 0)); break; case U6: opimm(x, BITS(code, 11, 6)); break; case U6_SWI: opimm(x, BITS(code, 10, 5)); break; case U5: case U7L: displ = BITS(code, 4, 0); if ( opkind == U7L ) displ *= 4; opimm(x, displ); break; case U8: opimm(x, BITS(code, 7, 0)); break; case U6_16: // 6..4 & 2..0 u6 unsigned immediate opimm(x, (BITS(code, 6, 4) << 3) | BITS(code, 2, 0)); break; case U7_16: // 7..4 & 2..0 u7 unsigned immediate opimm(x, (BITS(code, 7, 4) << 3) | BITS(code, 2, 0)); break; case U10_16: opimm(x, BITS(code, 9, 0)); break; case fB_U5: // 10..8 & 4..0 [b, u5] case fB_U6: // 10..8 & 4..0 [b, u6] (u6=u5*2) case fB_U7: // 10..8 & 4..0 [b, u7] (u6=u5*4) displ = BITS(code, 4, 0); if ( opkind == fB_U6 ) displ *= 2; else if ( opkind == fB_U7 ) displ *= 4; reg = reg16(BITS(code, 10, 8)); opdisp(insn, x, reg, displ); break; case fB_S9: // 14..12&26..26, 15&23..16 [b, s9] displ = BITS(code, 23, 16); if ( BITS(code, 15, 15) ) // sign bit displ -= (1ul<<8); reg = (BITS(code, 14, 12)<<3) | BITS(code, 26, 24); opdisp(insn, x, reg, displ); break; // handing of the "gen" format: // P M // REG_REG 00 N/A Destination and both sources are registers // REG_U6IMM 01 N/A Source 2 is a 6-bit unsigned immediate // REG_S12IMM 10 N/A Source 2 is a 12-bit signed immediate // COND_REG 11 0 Conditional instruction. Destination (if any) is source 1. Source 2 is a register // COND_REG_U6IMM 11 1 Conditional instruction. Destination (if any) is source 1. Source 2 is a 6-bit unsigned immediate // P=23..22, M=5 // 0x04, [0x00 - 0x3F] // 00100 bbb 00 iiiiii F BBB CCCCCC AAAAAA reg-reg op<.f> a,b,c // 00100 bbb 01 iiiiii F BBB UUUUUU AAAAAA reg-u6imm op<.f> a,b,u6 // 00100 bbb 10 iiiiii F BBB ssssss SSSSSS reg-s12imm op<.f> b,b,s12 // 00100 bbb 11 iiiiii F BBB CCCCCC 0 QQQQQ cond reg-reg op<.cc><.f> b,b,c // 00100 bbb 11 iiiiii F BBB UUUUUU 1 QQQQQ cond reg-u6 op<.cc><.f> b,b,u6 // 0x04, [0x30 - 0x37] // 00100 bbb aa 110 ZZ X D BBB CCCCCC AAAAAA LD<.x><.aa><.di> a,[b,c] case GENA: // 5..0 p = BITS(code, 23, 22); if ( p <= 1 ) reg = BITS(code, 5, 0); else reg = (BITS(code, 14, 12)<<3) | BITS(code, 26, 24); opreg(insn, x, reg); break; case GENB: // 14..12 & 26..24 reg = (BITS(code, 14, 12)<<3) | BITS(code, 26, 24); opreg(insn, x, reg); break; case GENC: // 11..6 reg/u6 or 0..5&11..6 s12 case GENC_PCREL: // 11..6 u6 or 0..5&11..6 s12 pc-relative displacement p = BITS(code, 23, 22); if ( p != 2 ) { reg = BITS(code, 11, 6); if ( p == 0 || (p == 3 && BITS(code, 5, 5) == 0) ) opreg(insn, x, reg); else opimm(x, reg); } else { // s12 reg = (BITS(code, 5, 0) << 6) | BITS(code, 11, 6); reg = SIGNEXT(reg, 12); opimm(x, reg); } if ( (opkind & ~O_IND) == GENC_PCREL && x.type == o_imm ) opbranch(insn, x, reg * 2); break; case fBC_IND: { int b = (BITS(code, 14, 12)<<3) | BITS(code, 26, 24); int c = BITS(code, 11, 6); int li = 0; if ( b == LIMM || c == LIMM ) li = get_limm(insn); doIndirectOperand(insn, b, c, x, 0, li, false); } break; case fBC16_IND: { int b = BITS(code, 10, 8); int c = BITS(code, 7, 5); doIndirectOperand(insn, reg16(b), reg16(c), x, 0, 0, false); } break; case O_ZERO: opimm(x, 0); break; case R_SP: // implicit SP opreg(insn, x, SP); break; case R_BLINK: // implicit BLINK opreg(insn, x, BLINK); break; case R_R0: // implicit R0 opreg(insn, x, R0); break; case R_R1: // implicit R1 opreg(insn, x, R1); break; case R_GP: // implicit GP opreg(insn, x, GP); break; case GP_S9: // 8..0 [GP, s9] GP + offset case GP_S10: // 8..0 [GP, s10] GP + offset (s10 = s9*2) case GP_S11: // 8..0 [GP, s11] GP + offset (s11 = s9*4) case S11: // 8..0 s11 signed immediate (s11 = s9*4) displ = SBITS(code, 8, 0); if ( opkind == GP_S10 ) displ *= 2; else if ( opkind != GP_S9 ) displ *= 4; if ( opkind == S11 ) opimm(x, displ); else opdisp(insn, x, GP, displ); break; case GP_S11_16: displ = (SBITS(code, 10, 5) << 5) | (BITS(code, 2, 0) << 2); opdisp(insn, x, GP, displ); break; case EL: // 4..1 & 10..8 enter / leave register set x.type = o_reglist; x.reglist = BITS(code, 4, 1) | (BITS(code, 10, 8) << 4); x.dtype = dt_dword; break; default: msg("%a: cannot decode operand %d (opkind=%u)\n", insn.ea, x.n, opkind); return; } if ( opkind & O_IND ) { // indirect access if ( x.type == o_reg ) { x.type = o_displ; x.addr = 0; } else if ( x.type == o_imm && insn.itype != ARC_lr && insn.itype != ARC_sr ) { if ( insn.itype == ARC_j || insn.itype == ARC_jl ) x.type = o_near; else x.type = o_mem; x.addr = x.value; x.immdisp = 0; } } if ( opkind & O_WIDE ) { // register pair for 64-bit values op_t &y = insn.ops[op_pos]; ++op_pos; if ( x.type == o_reg && (x.reg & 1) == 0 && x.reg <= R58 ) { y.type = o_reg; y.reg = x.reg + 1; y.regpair = true; } else { y.type = o_void; } } if ( opkind & O_IDX ) { int base; switch ( insn.itype ) { case ARC_bi: case ARC_bih: base = NEXT_PC; break; case ARC_ldi: base = LDI_BASE; break; case ARC_jli: base = JLI_BASE; break; case ARC_ei: base = EI_BASE; break; default: msg("%a: unknown implicit base for indexed access\n", insn.ea); return; } if ( x.type == o_reg ) { x.type = o_phrase; x.secreg = x.reg; x.reg = base; } else if ( x.type == o_imm ) { x.type = o_displ; x.addr = x.value; x.reg = base; } else { msg("%a: unknown operand type for indexed access\n", insn.ea); } } } //---------------------------------------------------------------------- // decode non-operand bits of the instruction static void decode_aux(insn_t &insn, uint32 code, uint32 aux) { aux &= ~AUX_V2 & ~AUX_F; if ( aux & AUX_CND ) { // condition in low bits of 'aux' insn.auxpref = (insn.auxpref & ~aux_cmask) | (aux & aux_cmask); aux &= ~(AUX_CND | aux_cmask); } if ( aux & Q_4_0 ) { // condition in low bits of instruction insn.auxpref = (insn.auxpref & ~aux_cmask) | (code & aux_cmask); aux &= ~Q_4_0; } if ( aux & Q_5_0 ) { // condition in low bits of instruction if the next higer bit is 1 if ( BITS(code, 5, 5) == 1 ) insn.auxpref = (insn.auxpref & ~aux_cmask) | (code & aux_cmask); aux &= ~Q_5_0; } if ( aux & AUX_GEN3 ) { // bit 15 = F/Di, 4..0 = Q if 23..22=0x3 if ( BITS(code, 15, 15) ) { if ( (aux & AUX_GEN3) == AUX_GEN ) insn.auxpref |= aux_f; else if ( (aux & AUX_GEN3) == AUX_GEN3 ) insn.auxpref |= aux_di; } if ( BITS(code, 23, 22) == 3 ) insn.auxpref = (insn.auxpref & ~aux_cmask) | (code & aux_cmask); aux &= ~AUX_GEN3; } if ( aux & N_5 ) { insn.auxpref = (insn.auxpref & ~aux_d) | (code & aux_d); aux &= ~N_5; } if ( aux & AUX_W ) { insn.auxpref = (insn.auxpref & ~aux_zmask) | aux_w; aux &= ~AUX_W; } if ( aux & AUX_B ) { insn.auxpref = (insn.auxpref & ~aux_zmask) | aux_b; aux &= ~AUX_B; } if ( aux & AUX_X ) { insn.auxpref |= aux_x; aux &= ~AUX_X; } if ( aux & AUX_D ) { insn.auxpref = (insn.auxpref & ~aux_nmask) | aux_d; aux &= ~AUX_D; } if ( aux & DAAZZX_11_6 ) // 11..6 Di, aa, ZZ, X flags (load) { insn.auxpref = (insn.auxpref & ~0x3F) | (BITS(code, 11, 6)); aux &= ~DAAZZX_11_6; } if ( aux & DAAZZ_5_1 ) // 5..1 Di, aa, ZZ (store) { insn.auxpref = (insn.auxpref & ~0x3F) | (BITS(code, 5, 1) << 1); aux &= ~DAAZZ_5_1; } if ( aux & AAZZXD_23_15 ) // 23..22,18..15 aa, ZZ, X, D flags (load reg+reg) { // load instructions flags: Di.AA.ZZ.X insn.auxpref &= ~0x3F; insn.auxpref |= BITS(code, 15, 15) << 5; // Di insn.auxpref |= BITS(code, 23, 22) << 3; // aa insn.auxpref |= BITS(code, 18, 17) << 1; // ZZ insn.auxpref |= BITS(code, 16, 16) << 0; // X aux &= ~AAZZXD_23_15; } if ( aux & AUX_AS ) { insn.auxpref |= aux_as; aux &= ~AUX_AS; } if ( aux & Y_3 ) { // static prediction bit Y is bit 3 // in default case (no hint specified) it's 0 for BRcc and 1 for BBITn if ( (BITS(code, 3, 3) == 0) != (insn.itype == ARC_br) ) { insn.auxpref |= aux_bhint; } aux &= ~Y_3; } if ( aux != 0 ) msg("%a: unhandled aux bits: %08X\n", insn.ea, aux); } //---------------------------------------------------------------------- int arc_t::analyze_compact(insn_t &insn, uint32 code, int idx, const arcompact_opcode_t *table) { const arcompact_opcode_t *line = &table[idx]; while ( (line->mnem & 0x80000000) != 0 ) { // it's a pointer into subtable // indexed by some of the instruction's bits int high1 = (line->mnem >> 24) & 0x1F; int low1 = (line->mnem >> 16) & 0x1F; int high2 = (line->mnem >> 8) & 0x1F; int low2 = (line->mnem >> 0) & 0x1F; idx = BITS(code, high2, low2); if ( high1 != 0 && low1 != 0 ) idx |= BITS(code, high1, low1) << (high2-low2+1); line = &(line->subtable[idx]); } if ( line->aux & AUX_F && BITS(code, 15, 15) ) line += 0x40; if ( (line->mnem == 0 && line->aux == 0) || !is_arcv2() && line->aux & AUX_V2 ) { return 0; } insn.itype = line->mnem; decode_aux(insn, code, line->aux); if ( is_arcv2() && insn.itype == ARC_flag && BITS(code, 15, 15) ) insn.itype = ARC_kflag; int j = 0; for ( int i = 0; i < 3; i++ ) decode_operand(insn, code, j, line->ops[i]); for ( ; j < PROC_MAXOP; ++j ) insn.ops[j].type = o_void; if ( insn.itype == ARC_swi && insn.Op1.type == o_imm && insn.Op1.value == 0x3f ) { insn.itype = ARC_brk; insn.Op1.type = o_void; } return insn.size; } //---------------------------------------------------------------------- // analyze ARCompact instruction int arc_t::ana_compact(insn_t &insn) { // must be 16-bit aligned if ( insn.ea & 1 ) return 0; uint32 code = insn.get_next_word(); got_limm = false; // first 5 bits is the major opcode int i = (code >> 11) & 0x1F; if ( i < 0x8 ) { // this is a 32-bit instruction // get the full word code = (code << 16) | insn.get_next_word(); } else { insn.auxpref |= aux_s; } return analyze_compact(insn, code, i, is_arcv2() ? arcv2_major : arcompact_major); } //---------------------------------------------------------------------- static void simplify(insn_t &insn) { for ( int i = 0; i < PROC_MAXOP; ++i ) { if ( insn.ops[i].type == o_mem ) insn.ops[i].immdisp = 0; } switch ( insn.itype ) { case ARC_st: case ARC_ld: // ld.as r1, [r2, delta] -> ld r1, [r2, delta*size] if ( insn.Op2.type == o_displ && insn.Op2.membase == 0 && (insn.auxpref & aux_amask) == aux_as ) { insn.Op2.addr *= get_scale_factor(insn); insn.auxpref &= ~aux_amask; } else if ( insn.Op2.type == o_mem && (insn.auxpref & aux_amask) == aux_as ) { insn.Op2.immdisp = 0; insn.auxpref &= ~aux_amask; } break; case ARC_add1: case ARC_add2: case ARC_add3: case ARC_sub1: case ARC_sub2: case ARC_sub3: // addN a, b, c -> add a, b, c< cmp a, b if ( insn.Op1.is_imm(0) && (insn.auxpref & aux_f) != 0 ) { insn.auxpref &= ~aux_f; insn.itype = ARC_cmp; insn.Op1 = insn.Op2; insn.Op2 = insn.Op3; insn.Op3.type = o_void; } break; } } //---------------------------------------------------------------------- // fix operand size for byte or word loads/stores inline void fix_ldst(insn_t &insn) { if ( insn.itype == ARC_ld || insn.itype == ARC_st ) { switch ( insn.auxpref & aux_zmask ) { case aux_b: insn.Op2.dtype = dt_byte; break; case aux_w: insn.Op2.dtype = dt_word; break; } } } //---------------------------------------------------------------------- // convert pc-relative loads // ld r1, [pc,#delta] -> ld r1, [memaddr] static void inline_const(insn_t &insn) { if ( insn.itype == ARC_ld && insn.Op2.type == o_displ && insn.Op2.reg == PCL && (insn.auxpref & (aux_a|aux_zmask)) == 0 ) // no .a and 32-bit access { ea_t val_ea = (insn.ea & ~3ul) + insn.Op2.addr; if ( is_mapped(val_ea) ) { insn.Op2.type = o_mem; insn.Op2.addr = val_ea; insn.Op2.immdisp = 0; insn.auxpref |= aux_pcload; } } } //---------------------------------------------------------------------- // analyze an instruction int arc_t::ana(insn_t *_insn) { insn_t &insn = *_insn; int sz = is_a4() ? ana_old(insn) : ana_compact(insn); if ( sz != 0 ) { fix_ldst(insn); if ( (idpflags & ARC_SIMPLIFY) != 0 ) simplify(insn); if ( (idpflags & ARC_INLINECONST) != 0 ) inline_const(insn); } return insn.size; }