| /* |
| * MIPS32 emulation for qemu: main translation routines. |
| * |
| * Copyright (c) 2004-2005 Jocelyn Mayer |
| * Copyright (c) 2006 Marius Groeger (FPU operations) |
| * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) |
| * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) |
| * Copyright (c) 2012 Jia Liu & Dongxue Zhang (MIPS ASE DSP support) |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "cpu.h" |
| #include "disas/disas.h" |
| #include "tcg-op.h" |
| #include "exec/cpu_ldst.h" |
| |
| #include "exec/helper-proto.h" |
| #include "exec/helper-gen.h" |
| #include "sysemu/kvm.h" |
| |
| #include "trace-tcg.h" |
| |
| |
| #define MIPS_DEBUG_DISAS 0 |
| //#define MIPS_DEBUG_SIGN_EXTENSIONS |
| |
| /* MIPS major opcodes */ |
| #define MASK_OP_MAJOR(op) (op & (0x3F << 26)) |
| |
| enum { |
| /* indirect opcode tables */ |
| OPC_SPECIAL = (0x00 << 26), |
| OPC_REGIMM = (0x01 << 26), |
| OPC_CP0 = (0x10 << 26), |
| OPC_CP1 = (0x11 << 26), |
| OPC_CP2 = (0x12 << 26), |
| OPC_CP3 = (0x13 << 26), |
| OPC_SPECIAL2 = (0x1C << 26), |
| OPC_SPECIAL3 = (0x1F << 26), |
| /* arithmetic with immediate */ |
| OPC_ADDI = (0x08 << 26), |
| OPC_ADDIU = (0x09 << 26), |
| OPC_SLTI = (0x0A << 26), |
| OPC_SLTIU = (0x0B << 26), |
| /* logic with immediate */ |
| OPC_ANDI = (0x0C << 26), |
| OPC_ORI = (0x0D << 26), |
| OPC_XORI = (0x0E << 26), |
| OPC_LUI = (0x0F << 26), |
| /* arithmetic with immediate */ |
| OPC_DADDI = (0x18 << 26), |
| OPC_DADDIU = (0x19 << 26), |
| /* Jump and branches */ |
| OPC_J = (0x02 << 26), |
| OPC_JAL = (0x03 << 26), |
| OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ |
| OPC_BEQL = (0x14 << 26), |
| OPC_BNE = (0x05 << 26), |
| OPC_BNEL = (0x15 << 26), |
| OPC_BLEZ = (0x06 << 26), |
| OPC_BLEZL = (0x16 << 26), |
| OPC_BGTZ = (0x07 << 26), |
| OPC_BGTZL = (0x17 << 26), |
| OPC_JALX = (0x1D << 26), |
| OPC_DAUI = (0x1D << 26), |
| /* Load and stores */ |
| OPC_LDL = (0x1A << 26), |
| OPC_LDR = (0x1B << 26), |
| OPC_LB = (0x20 << 26), |
| OPC_LH = (0x21 << 26), |
| OPC_LWL = (0x22 << 26), |
| OPC_LW = (0x23 << 26), |
| OPC_LWPC = OPC_LW | 0x5, |
| OPC_LBU = (0x24 << 26), |
| OPC_LHU = (0x25 << 26), |
| OPC_LWR = (0x26 << 26), |
| OPC_LWU = (0x27 << 26), |
| OPC_SB = (0x28 << 26), |
| OPC_SH = (0x29 << 26), |
| OPC_SWL = (0x2A << 26), |
| OPC_SW = (0x2B << 26), |
| OPC_SDL = (0x2C << 26), |
| OPC_SDR = (0x2D << 26), |
| OPC_SWR = (0x2E << 26), |
| OPC_LL = (0x30 << 26), |
| OPC_LLD = (0x34 << 26), |
| OPC_LD = (0x37 << 26), |
| OPC_LDPC = OPC_LD | 0x5, |
| OPC_SC = (0x38 << 26), |
| OPC_SCD = (0x3C << 26), |
| OPC_SD = (0x3F << 26), |
| /* Floating point load/store */ |
| OPC_LWC1 = (0x31 << 26), |
| OPC_LWC2 = (0x32 << 26), |
| OPC_LDC1 = (0x35 << 26), |
| OPC_LDC2 = (0x36 << 26), |
| OPC_SWC1 = (0x39 << 26), |
| OPC_SWC2 = (0x3A << 26), |
| OPC_SDC1 = (0x3D << 26), |
| OPC_SDC2 = (0x3E << 26), |
| /* Compact Branches */ |
| OPC_BLEZALC = (0x06 << 26), |
| OPC_BGEZALC = (0x06 << 26), |
| OPC_BGEUC = (0x06 << 26), |
| OPC_BGTZALC = (0x07 << 26), |
| OPC_BLTZALC = (0x07 << 26), |
| OPC_BLTUC = (0x07 << 26), |
| OPC_BOVC = (0x08 << 26), |
| OPC_BEQZALC = (0x08 << 26), |
| OPC_BEQC = (0x08 << 26), |
| OPC_BLEZC = (0x16 << 26), |
| OPC_BGEZC = (0x16 << 26), |
| OPC_BGEC = (0x16 << 26), |
| OPC_BGTZC = (0x17 << 26), |
| OPC_BLTZC = (0x17 << 26), |
| OPC_BLTC = (0x17 << 26), |
| OPC_BNVC = (0x18 << 26), |
| OPC_BNEZALC = (0x18 << 26), |
| OPC_BNEC = (0x18 << 26), |
| OPC_BC = (0x32 << 26), |
| OPC_BEQZC = (0x36 << 26), |
| OPC_JIC = (0x36 << 26), |
| OPC_BALC = (0x3A << 26), |
| OPC_BNEZC = (0x3E << 26), |
| OPC_JIALC = (0x3E << 26), |
| /* MDMX ASE specific */ |
| OPC_MDMX = (0x1E << 26), |
| /* MSA ASE, same as MDMX */ |
| OPC_MSA = OPC_MDMX, |
| /* Cache and prefetch */ |
| OPC_CACHE = (0x2F << 26), |
| OPC_PREF = (0x33 << 26), |
| /* PC-relative address computation / loads */ |
| OPC_PCREL = (0x3B << 26), |
| }; |
| |
| /* PC-relative address computation / loads */ |
| #define MASK_OPC_PCREL_TOP2BITS(op) (MASK_OP_MAJOR(op) | (op & (3 << 19))) |
| #define MASK_OPC_PCREL_TOP5BITS(op) (MASK_OP_MAJOR(op) | (op & (0x1f << 16))) |
| enum { |
| /* Instructions determined by bits 19 and 20 */ |
| OPC_ADDIUPC = OPC_PCREL | (0 << 19), |
| R6_OPC_LWPC = OPC_PCREL | (1 << 19), |
| OPC_LWUPC = OPC_PCREL | (2 << 19), |
| |
| /* Instructions determined by bits 16 ... 20 */ |
| OPC_AUIPC = OPC_PCREL | (0x1e << 16), |
| OPC_ALUIPC = OPC_PCREL | (0x1f << 16), |
| |
| /* Other */ |
| R6_OPC_LDPC = OPC_PCREL | (6 << 18), |
| }; |
| |
| /* MIPS special opcodes */ |
| #define MASK_SPECIAL(op) MASK_OP_MAJOR(op) | (op & 0x3F) |
| |
| enum { |
| /* Shifts */ |
| OPC_SLL = 0x00 | OPC_SPECIAL, |
| /* NOP is SLL r0, r0, 0 */ |
| /* SSNOP is SLL r0, r0, 1 */ |
| /* EHB is SLL r0, r0, 3 */ |
| OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */ |
| OPC_ROTR = OPC_SRL | (1 << 21), |
| OPC_SRA = 0x03 | OPC_SPECIAL, |
| OPC_SLLV = 0x04 | OPC_SPECIAL, |
| OPC_SRLV = 0x06 | OPC_SPECIAL, /* also ROTRV */ |
| OPC_ROTRV = OPC_SRLV | (1 << 6), |
| OPC_SRAV = 0x07 | OPC_SPECIAL, |
| OPC_DSLLV = 0x14 | OPC_SPECIAL, |
| OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */ |
| OPC_DROTRV = OPC_DSRLV | (1 << 6), |
| OPC_DSRAV = 0x17 | OPC_SPECIAL, |
| OPC_DSLL = 0x38 | OPC_SPECIAL, |
| OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */ |
| OPC_DROTR = OPC_DSRL | (1 << 21), |
| OPC_DSRA = 0x3B | OPC_SPECIAL, |
| OPC_DSLL32 = 0x3C | OPC_SPECIAL, |
| OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */ |
| OPC_DROTR32 = OPC_DSRL32 | (1 << 21), |
| OPC_DSRA32 = 0x3F | OPC_SPECIAL, |
| /* Multiplication / division */ |
| OPC_MULT = 0x18 | OPC_SPECIAL, |
| OPC_MULTU = 0x19 | OPC_SPECIAL, |
| OPC_DIV = 0x1A | OPC_SPECIAL, |
| OPC_DIVU = 0x1B | OPC_SPECIAL, |
| OPC_DMULT = 0x1C | OPC_SPECIAL, |
| OPC_DMULTU = 0x1D | OPC_SPECIAL, |
| OPC_DDIV = 0x1E | OPC_SPECIAL, |
| OPC_DDIVU = 0x1F | OPC_SPECIAL, |
| |
| /* 2 registers arithmetic / logic */ |
| OPC_ADD = 0x20 | OPC_SPECIAL, |
| OPC_ADDU = 0x21 | OPC_SPECIAL, |
| OPC_SUB = 0x22 | OPC_SPECIAL, |
| OPC_SUBU = 0x23 | OPC_SPECIAL, |
| OPC_AND = 0x24 | OPC_SPECIAL, |
| OPC_OR = 0x25 | OPC_SPECIAL, |
| OPC_XOR = 0x26 | OPC_SPECIAL, |
| OPC_NOR = 0x27 | OPC_SPECIAL, |
| OPC_SLT = 0x2A | OPC_SPECIAL, |
| OPC_SLTU = 0x2B | OPC_SPECIAL, |
| OPC_DADD = 0x2C | OPC_SPECIAL, |
| OPC_DADDU = 0x2D | OPC_SPECIAL, |
| OPC_DSUB = 0x2E | OPC_SPECIAL, |
| OPC_DSUBU = 0x2F | OPC_SPECIAL, |
| /* Jumps */ |
| OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ |
| OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ |
| /* Traps */ |
| OPC_TGE = 0x30 | OPC_SPECIAL, |
| OPC_TGEU = 0x31 | OPC_SPECIAL, |
| OPC_TLT = 0x32 | OPC_SPECIAL, |
| OPC_TLTU = 0x33 | OPC_SPECIAL, |
| OPC_TEQ = 0x34 | OPC_SPECIAL, |
| OPC_TNE = 0x36 | OPC_SPECIAL, |
| /* HI / LO registers load & stores */ |
| OPC_MFHI = 0x10 | OPC_SPECIAL, |
| OPC_MTHI = 0x11 | OPC_SPECIAL, |
| OPC_MFLO = 0x12 | OPC_SPECIAL, |
| OPC_MTLO = 0x13 | OPC_SPECIAL, |
| /* Conditional moves */ |
| OPC_MOVZ = 0x0A | OPC_SPECIAL, |
| OPC_MOVN = 0x0B | OPC_SPECIAL, |
| |
| OPC_SELEQZ = 0x35 | OPC_SPECIAL, |
| OPC_SELNEZ = 0x37 | OPC_SPECIAL, |
| |
| OPC_MOVCI = 0x01 | OPC_SPECIAL, |
| |
| /* Special */ |
| OPC_PMON = 0x05 | OPC_SPECIAL, /* unofficial */ |
| OPC_SYSCALL = 0x0C | OPC_SPECIAL, |
| OPC_BREAK = 0x0D | OPC_SPECIAL, |
| OPC_SPIM = 0x0E | OPC_SPECIAL, /* unofficial */ |
| OPC_SYNC = 0x0F | OPC_SPECIAL, |
| |
| OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL, |
| OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL, |
| OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL, |
| OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL, |
| }; |
| |
| /* R6 Multiply and Divide instructions have the same Opcode |
| and function field as legacy OPC_MULT[U]/OPC_DIV[U] */ |
| #define MASK_R6_MULDIV(op) (MASK_SPECIAL(op) | (op & (0x7ff))) |
| |
| enum { |
| R6_OPC_MUL = OPC_MULT | (2 << 6), |
| R6_OPC_MUH = OPC_MULT | (3 << 6), |
| R6_OPC_MULU = OPC_MULTU | (2 << 6), |
| R6_OPC_MUHU = OPC_MULTU | (3 << 6), |
| R6_OPC_DIV = OPC_DIV | (2 << 6), |
| R6_OPC_MOD = OPC_DIV | (3 << 6), |
| R6_OPC_DIVU = OPC_DIVU | (2 << 6), |
| R6_OPC_MODU = OPC_DIVU | (3 << 6), |
| |
| R6_OPC_DMUL = OPC_DMULT | (2 << 6), |
| R6_OPC_DMUH = OPC_DMULT | (3 << 6), |
| R6_OPC_DMULU = OPC_DMULTU | (2 << 6), |
| R6_OPC_DMUHU = OPC_DMULTU | (3 << 6), |
| R6_OPC_DDIV = OPC_DDIV | (2 << 6), |
| R6_OPC_DMOD = OPC_DDIV | (3 << 6), |
| R6_OPC_DDIVU = OPC_DDIVU | (2 << 6), |
| R6_OPC_DMODU = OPC_DDIVU | (3 << 6), |
| |
| R6_OPC_CLZ = 0x10 | OPC_SPECIAL, |
| R6_OPC_CLO = 0x11 | OPC_SPECIAL, |
| R6_OPC_DCLZ = 0x12 | OPC_SPECIAL, |
| R6_OPC_DCLO = 0x13 | OPC_SPECIAL, |
| R6_OPC_SDBBP = 0x0e | OPC_SPECIAL, |
| |
| OPC_LSA = 0x05 | OPC_SPECIAL, |
| OPC_DLSA = 0x15 | OPC_SPECIAL, |
| }; |
| |
| /* Multiplication variants of the vr54xx. */ |
| #define MASK_MUL_VR54XX(op) MASK_SPECIAL(op) | (op & (0x1F << 6)) |
| |
| enum { |
| OPC_VR54XX_MULS = (0x03 << 6) | OPC_MULT, |
| OPC_VR54XX_MULSU = (0x03 << 6) | OPC_MULTU, |
| OPC_VR54XX_MACC = (0x05 << 6) | OPC_MULT, |
| OPC_VR54XX_MACCU = (0x05 << 6) | OPC_MULTU, |
| OPC_VR54XX_MSAC = (0x07 << 6) | OPC_MULT, |
| OPC_VR54XX_MSACU = (0x07 << 6) | OPC_MULTU, |
| OPC_VR54XX_MULHI = (0x09 << 6) | OPC_MULT, |
| OPC_VR54XX_MULHIU = (0x09 << 6) | OPC_MULTU, |
| OPC_VR54XX_MULSHI = (0x0B << 6) | OPC_MULT, |
| OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU, |
| OPC_VR54XX_MACCHI = (0x0D << 6) | OPC_MULT, |
| OPC_VR54XX_MACCHIU = (0x0D << 6) | OPC_MULTU, |
| OPC_VR54XX_MSACHI = (0x0F << 6) | OPC_MULT, |
| OPC_VR54XX_MSACHIU = (0x0F << 6) | OPC_MULTU, |
| }; |
| |
| /* REGIMM (rt field) opcodes */ |
| #define MASK_REGIMM(op) MASK_OP_MAJOR(op) | (op & (0x1F << 16)) |
| |
| enum { |
| OPC_BLTZ = (0x00 << 16) | OPC_REGIMM, |
| OPC_BLTZL = (0x02 << 16) | OPC_REGIMM, |
| OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, |
| OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, |
| OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, |
| OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, |
| OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, |
| OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, |
| OPC_TGEI = (0x08 << 16) | OPC_REGIMM, |
| OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, |
| OPC_TLTI = (0x0A << 16) | OPC_REGIMM, |
| OPC_TLTIU = (0x0B << 16) | OPC_REGIMM, |
| OPC_TEQI = (0x0C << 16) | OPC_REGIMM, |
| OPC_TNEI = (0x0E << 16) | OPC_REGIMM, |
| OPC_SYNCI = (0x1F << 16) | OPC_REGIMM, |
| |
| OPC_DAHI = (0x06 << 16) | OPC_REGIMM, |
| OPC_DATI = (0x1e << 16) | OPC_REGIMM, |
| }; |
| |
| /* Special2 opcodes */ |
| #define MASK_SPECIAL2(op) MASK_OP_MAJOR(op) | (op & 0x3F) |
| |
| enum { |
| /* Multiply & xxx operations */ |
| OPC_MADD = 0x00 | OPC_SPECIAL2, |
| OPC_MADDU = 0x01 | OPC_SPECIAL2, |
| OPC_MUL = 0x02 | OPC_SPECIAL2, |
| OPC_MSUB = 0x04 | OPC_SPECIAL2, |
| OPC_MSUBU = 0x05 | OPC_SPECIAL2, |
| /* Loongson 2F */ |
| OPC_MULT_G_2F = 0x10 | OPC_SPECIAL2, |
| OPC_DMULT_G_2F = 0x11 | OPC_SPECIAL2, |
| OPC_MULTU_G_2F = 0x12 | OPC_SPECIAL2, |
| OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2, |
| OPC_DIV_G_2F = 0x14 | OPC_SPECIAL2, |
| OPC_DDIV_G_2F = 0x15 | OPC_SPECIAL2, |
| OPC_DIVU_G_2F = 0x16 | OPC_SPECIAL2, |
| OPC_DDIVU_G_2F = 0x17 | OPC_SPECIAL2, |
| OPC_MOD_G_2F = 0x1c | OPC_SPECIAL2, |
| OPC_DMOD_G_2F = 0x1d | OPC_SPECIAL2, |
| OPC_MODU_G_2F = 0x1e | OPC_SPECIAL2, |
| OPC_DMODU_G_2F = 0x1f | OPC_SPECIAL2, |
| /* Misc */ |
| OPC_CLZ = 0x20 | OPC_SPECIAL2, |
| OPC_CLO = 0x21 | OPC_SPECIAL2, |
| OPC_DCLZ = 0x24 | OPC_SPECIAL2, |
| OPC_DCLO = 0x25 | OPC_SPECIAL2, |
| /* Special */ |
| OPC_SDBBP = 0x3F | OPC_SPECIAL2, |
| }; |
| |
| /* Special3 opcodes */ |
| #define MASK_SPECIAL3(op) MASK_OP_MAJOR(op) | (op & 0x3F) |
| |
| enum { |
| OPC_EXT = 0x00 | OPC_SPECIAL3, |
| OPC_DEXTM = 0x01 | OPC_SPECIAL3, |
| OPC_DEXTU = 0x02 | OPC_SPECIAL3, |
| OPC_DEXT = 0x03 | OPC_SPECIAL3, |
| OPC_INS = 0x04 | OPC_SPECIAL3, |
| OPC_DINSM = 0x05 | OPC_SPECIAL3, |
| OPC_DINSU = 0x06 | OPC_SPECIAL3, |
| OPC_DINS = 0x07 | OPC_SPECIAL3, |
| OPC_FORK = 0x08 | OPC_SPECIAL3, |
| OPC_YIELD = 0x09 | OPC_SPECIAL3, |
| OPC_BSHFL = 0x20 | OPC_SPECIAL3, |
| OPC_DBSHFL = 0x24 | OPC_SPECIAL3, |
| OPC_RDHWR = 0x3B | OPC_SPECIAL3, |
| |
| /* Loongson 2E */ |
| OPC_MULT_G_2E = 0x18 | OPC_SPECIAL3, |
| OPC_MULTU_G_2E = 0x19 | OPC_SPECIAL3, |
| OPC_DIV_G_2E = 0x1A | OPC_SPECIAL3, |
| OPC_DIVU_G_2E = 0x1B | OPC_SPECIAL3, |
| OPC_DMULT_G_2E = 0x1C | OPC_SPECIAL3, |
| OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3, |
| OPC_DDIV_G_2E = 0x1E | OPC_SPECIAL3, |
| OPC_DDIVU_G_2E = 0x1F | OPC_SPECIAL3, |
| OPC_MOD_G_2E = 0x22 | OPC_SPECIAL3, |
| OPC_MODU_G_2E = 0x23 | OPC_SPECIAL3, |
| OPC_DMOD_G_2E = 0x26 | OPC_SPECIAL3, |
| OPC_DMODU_G_2E = 0x27 | OPC_SPECIAL3, |
| |
| /* MIPS DSP Load */ |
| OPC_LX_DSP = 0x0A | OPC_SPECIAL3, |
| /* MIPS DSP Arithmetic */ |
| OPC_ADDU_QB_DSP = 0x10 | OPC_SPECIAL3, |
| OPC_ADDU_OB_DSP = 0x14 | OPC_SPECIAL3, |
| OPC_ABSQ_S_PH_DSP = 0x12 | OPC_SPECIAL3, |
| OPC_ABSQ_S_QH_DSP = 0x16 | OPC_SPECIAL3, |
| /* OPC_ADDUH_QB_DSP is same as OPC_MULT_G_2E. */ |
| /* OPC_ADDUH_QB_DSP = 0x18 | OPC_SPECIAL3, */ |
| OPC_CMPU_EQ_QB_DSP = 0x11 | OPC_SPECIAL3, |
| OPC_CMPU_EQ_OB_DSP = 0x15 | OPC_SPECIAL3, |
| /* MIPS DSP GPR-Based Shift Sub-class */ |
| OPC_SHLL_QB_DSP = 0x13 | OPC_SPECIAL3, |
| OPC_SHLL_OB_DSP = 0x17 | OPC_SPECIAL3, |
| /* MIPS DSP Multiply Sub-class insns */ |
| /* OPC_MUL_PH_DSP is same as OPC_ADDUH_QB_DSP. */ |
| /* OPC_MUL_PH_DSP = 0x18 | OPC_SPECIAL3, */ |
| OPC_DPA_W_PH_DSP = 0x30 | OPC_SPECIAL3, |
| OPC_DPAQ_W_QH_DSP = 0x34 | OPC_SPECIAL3, |
| /* DSP Bit/Manipulation Sub-class */ |
| OPC_INSV_DSP = 0x0C | OPC_SPECIAL3, |
| OPC_DINSV_DSP = 0x0D | OPC_SPECIAL3, |
| /* MIPS DSP Append Sub-class */ |
| OPC_APPEND_DSP = 0x31 | OPC_SPECIAL3, |
| OPC_DAPPEND_DSP = 0x35 | OPC_SPECIAL3, |
| /* MIPS DSP Accumulator and DSPControl Access Sub-class */ |
| OPC_EXTR_W_DSP = 0x38 | OPC_SPECIAL3, |
| OPC_DEXTR_W_DSP = 0x3C | OPC_SPECIAL3, |
| |
| /* R6 */ |
| R6_OPC_PREF = 0x35 | OPC_SPECIAL3, |
| R6_OPC_CACHE = 0x25 | OPC_SPECIAL3, |
| R6_OPC_LL = 0x36 | OPC_SPECIAL3, |
| R6_OPC_SC = 0x26 | OPC_SPECIAL3, |
| R6_OPC_LLD = 0x37 | OPC_SPECIAL3, |
| R6_OPC_SCD = 0x27 | OPC_SPECIAL3, |
| }; |
| |
| /* BSHFL opcodes */ |
| #define MASK_BSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6)) |
| |
| enum { |
| OPC_WSBH = (0x02 << 6) | OPC_BSHFL, |
| OPC_SEB = (0x10 << 6) | OPC_BSHFL, |
| OPC_SEH = (0x18 << 6) | OPC_BSHFL, |
| OPC_ALIGN = (0x08 << 6) | OPC_BSHFL, /* 010.bp */ |
| OPC_ALIGN_END = (0x0B << 6) | OPC_BSHFL, /* 010.00 to 010.11 */ |
| OPC_BITSWAP = (0x00 << 6) | OPC_BSHFL /* 00000 */ |
| }; |
| |
| /* DBSHFL opcodes */ |
| #define MASK_DBSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6)) |
| |
| enum { |
| OPC_DSBH = (0x02 << 6) | OPC_DBSHFL, |
| OPC_DSHD = (0x05 << 6) | OPC_DBSHFL, |
| OPC_DALIGN = (0x08 << 6) | OPC_DBSHFL, /* 01.bp */ |
| OPC_DALIGN_END = (0x0F << 6) | OPC_DBSHFL, /* 01.000 to 01.111 */ |
| OPC_DBITSWAP = (0x00 << 6) | OPC_DBSHFL, /* 00000 */ |
| }; |
| |
| /* MIPS DSP REGIMM opcodes */ |
| enum { |
| OPC_BPOSGE32 = (0x1C << 16) | OPC_REGIMM, |
| OPC_BPOSGE64 = (0x1D << 16) | OPC_REGIMM, |
| }; |
| |
| #define MASK_LX(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| /* MIPS DSP Load */ |
| enum { |
| OPC_LBUX = (0x06 << 6) | OPC_LX_DSP, |
| OPC_LHX = (0x04 << 6) | OPC_LX_DSP, |
| OPC_LWX = (0x00 << 6) | OPC_LX_DSP, |
| OPC_LDX = (0x08 << 6) | OPC_LX_DSP, |
| }; |
| |
| #define MASK_ADDU_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_ADDQ_PH = (0x0A << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDQ_S_PH = (0x0E << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDQ_S_W = (0x16 << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDU_QB = (0x00 << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDU_S_QB = (0x04 << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDU_PH = (0x08 << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDU_S_PH = (0x0C << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBQ_PH = (0x0B << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBQ_S_PH = (0x0F << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBQ_S_W = (0x17 << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBU_QB = (0x01 << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBU_S_QB = (0x05 << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBU_PH = (0x09 << 6) | OPC_ADDU_QB_DSP, |
| OPC_SUBU_S_PH = (0x0D << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDSC = (0x10 << 6) | OPC_ADDU_QB_DSP, |
| OPC_ADDWC = (0x11 << 6) | OPC_ADDU_QB_DSP, |
| OPC_MODSUB = (0x12 << 6) | OPC_ADDU_QB_DSP, |
| OPC_RADDU_W_QB = (0x14 << 6) | OPC_ADDU_QB_DSP, |
| /* MIPS DSP Multiply Sub-class insns */ |
| OPC_MULEU_S_PH_QBL = (0x06 << 6) | OPC_ADDU_QB_DSP, |
| OPC_MULEU_S_PH_QBR = (0x07 << 6) | OPC_ADDU_QB_DSP, |
| OPC_MULQ_RS_PH = (0x1F << 6) | OPC_ADDU_QB_DSP, |
| OPC_MULEQ_S_W_PHL = (0x1C << 6) | OPC_ADDU_QB_DSP, |
| OPC_MULEQ_S_W_PHR = (0x1D << 6) | OPC_ADDU_QB_DSP, |
| OPC_MULQ_S_PH = (0x1E << 6) | OPC_ADDU_QB_DSP, |
| }; |
| |
| #define OPC_ADDUH_QB_DSP OPC_MULT_G_2E |
| #define MASK_ADDUH_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_ADDUH_QB = (0x00 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_ADDUH_R_QB = (0x02 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_ADDQH_PH = (0x08 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_ADDQH_R_PH = (0x0A << 6) | OPC_ADDUH_QB_DSP, |
| OPC_ADDQH_W = (0x10 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_ADDQH_R_W = (0x12 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_SUBUH_QB = (0x01 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_SUBUH_R_QB = (0x03 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_SUBQH_PH = (0x09 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_SUBQH_R_PH = (0x0B << 6) | OPC_ADDUH_QB_DSP, |
| OPC_SUBQH_W = (0x11 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_SUBQH_R_W = (0x13 << 6) | OPC_ADDUH_QB_DSP, |
| /* MIPS DSP Multiply Sub-class insns */ |
| OPC_MUL_PH = (0x0C << 6) | OPC_ADDUH_QB_DSP, |
| OPC_MUL_S_PH = (0x0E << 6) | OPC_ADDUH_QB_DSP, |
| OPC_MULQ_S_W = (0x16 << 6) | OPC_ADDUH_QB_DSP, |
| OPC_MULQ_RS_W = (0x17 << 6) | OPC_ADDUH_QB_DSP, |
| }; |
| |
| #define MASK_ABSQ_S_PH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_ABSQ_S_QB = (0x01 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_ABSQ_S_PH = (0x09 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_ABSQ_S_W = (0x11 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEQ_W_PHL = (0x0C << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEQ_W_PHR = (0x0D << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEQU_PH_QBL = (0x04 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEQU_PH_QBR = (0x05 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEQU_PH_QBLA = (0x06 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEQU_PH_QBRA = (0x07 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEU_PH_QBL = (0x1C << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEU_PH_QBR = (0x1D << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEU_PH_QBLA = (0x1E << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_PRECEU_PH_QBRA = (0x1F << 6) | OPC_ABSQ_S_PH_DSP, |
| /* DSP Bit/Manipulation Sub-class */ |
| OPC_BITREV = (0x1B << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_REPL_QB = (0x02 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_REPLV_QB = (0x03 << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_REPL_PH = (0x0A << 6) | OPC_ABSQ_S_PH_DSP, |
| OPC_REPLV_PH = (0x0B << 6) | OPC_ABSQ_S_PH_DSP, |
| }; |
| |
| #define MASK_CMPU_EQ_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_PRECR_QB_PH = (0x0D << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PRECRQ_QB_PH = (0x0C << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PRECR_SRA_PH_W = (0x1E << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PRECR_SRA_R_PH_W = (0x1F << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PRECRQ_PH_W = (0x14 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PRECRQ_RS_PH_W = (0x15 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PRECRQU_S_QB_PH = (0x0F << 6) | OPC_CMPU_EQ_QB_DSP, |
| /* DSP Compare-Pick Sub-class */ |
| OPC_CMPU_EQ_QB = (0x00 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPU_LT_QB = (0x01 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPU_LE_QB = (0x02 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPGU_EQ_QB = (0x04 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPGU_LT_QB = (0x05 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPGU_LE_QB = (0x06 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPGDU_EQ_QB = (0x18 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPGDU_LT_QB = (0x19 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMPGDU_LE_QB = (0x1A << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMP_EQ_PH = (0x08 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMP_LT_PH = (0x09 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_CMP_LE_PH = (0x0A << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PICK_QB = (0x03 << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PICK_PH = (0x0B << 6) | OPC_CMPU_EQ_QB_DSP, |
| OPC_PACKRL_PH = (0x0E << 6) | OPC_CMPU_EQ_QB_DSP, |
| }; |
| |
| #define MASK_SHLL_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP GPR-Based Shift Sub-class */ |
| OPC_SHLL_QB = (0x00 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLLV_QB = (0x02 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLL_PH = (0x08 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLLV_PH = (0x0A << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLL_S_PH = (0x0C << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLLV_S_PH = (0x0E << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLL_S_W = (0x14 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHLLV_S_W = (0x16 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRL_QB = (0x01 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRLV_QB = (0x03 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRL_PH = (0x19 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRLV_PH = (0x1B << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRA_QB = (0x04 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRA_R_QB = (0x05 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRAV_QB = (0x06 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRAV_R_QB = (0x07 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRA_PH = (0x09 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRAV_PH = (0x0B << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRA_R_PH = (0x0D << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRAV_R_PH = (0x0F << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRA_R_W = (0x15 << 6) | OPC_SHLL_QB_DSP, |
| OPC_SHRAV_R_W = (0x17 << 6) | OPC_SHLL_QB_DSP, |
| }; |
| |
| #define MASK_DPA_W_PH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Multiply Sub-class insns */ |
| OPC_DPAU_H_QBL = (0x03 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPAU_H_QBR = (0x07 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSU_H_QBL = (0x0B << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSU_H_QBR = (0x0F << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPA_W_PH = (0x00 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPAX_W_PH = (0x08 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPAQ_S_W_PH = (0x04 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPAQX_S_W_PH = (0x18 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPAQX_SA_W_PH = (0x1A << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPS_W_PH = (0x01 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSX_W_PH = (0x09 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSQ_S_W_PH = (0x05 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSQX_S_W_PH = (0x19 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSQX_SA_W_PH = (0x1B << 6) | OPC_DPA_W_PH_DSP, |
| OPC_MULSAQ_S_W_PH = (0x06 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPAQ_SA_L_W = (0x0C << 6) | OPC_DPA_W_PH_DSP, |
| OPC_DPSQ_SA_L_W = (0x0D << 6) | OPC_DPA_W_PH_DSP, |
| OPC_MAQ_S_W_PHL = (0x14 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_MAQ_S_W_PHR = (0x16 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_MAQ_SA_W_PHL = (0x10 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_MAQ_SA_W_PHR = (0x12 << 6) | OPC_DPA_W_PH_DSP, |
| OPC_MULSA_W_PH = (0x02 << 6) | OPC_DPA_W_PH_DSP, |
| }; |
| |
| #define MASK_INSV(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* DSP Bit/Manipulation Sub-class */ |
| OPC_INSV = (0x00 << 6) | OPC_INSV_DSP, |
| }; |
| |
| #define MASK_APPEND(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Append Sub-class */ |
| OPC_APPEND = (0x00 << 6) | OPC_APPEND_DSP, |
| OPC_PREPEND = (0x01 << 6) | OPC_APPEND_DSP, |
| OPC_BALIGN = (0x10 << 6) | OPC_APPEND_DSP, |
| }; |
| |
| #define MASK_EXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Accumulator and DSPControl Access Sub-class */ |
| OPC_EXTR_W = (0x00 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTR_R_W = (0x04 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTR_RS_W = (0x06 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTR_S_H = (0x0E << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTRV_S_H = (0x0F << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTRV_W = (0x01 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTRV_R_W = (0x05 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTRV_RS_W = (0x07 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTP = (0x02 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTPV = (0x03 << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTPDP = (0x0A << 6) | OPC_EXTR_W_DSP, |
| OPC_EXTPDPV = (0x0B << 6) | OPC_EXTR_W_DSP, |
| OPC_SHILO = (0x1A << 6) | OPC_EXTR_W_DSP, |
| OPC_SHILOV = (0x1B << 6) | OPC_EXTR_W_DSP, |
| OPC_MTHLIP = (0x1F << 6) | OPC_EXTR_W_DSP, |
| OPC_WRDSP = (0x13 << 6) | OPC_EXTR_W_DSP, |
| OPC_RDDSP = (0x12 << 6) | OPC_EXTR_W_DSP, |
| }; |
| |
| #define MASK_ABSQ_S_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_PRECEQ_L_PWL = (0x14 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQ_L_PWR = (0x15 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQ_PW_QHL = (0x0C << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQ_PW_QHR = (0x0D << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQ_PW_QHLA = (0x0E << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQ_PW_QHRA = (0x0F << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQU_QH_OBL = (0x04 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQU_QH_OBR = (0x05 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQU_QH_OBLA = (0x06 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEQU_QH_OBRA = (0x07 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEU_QH_OBL = (0x1C << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEU_QH_OBR = (0x1D << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEU_QH_OBLA = (0x1E << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_PRECEU_QH_OBRA = (0x1F << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_ABSQ_S_OB = (0x01 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_ABSQ_S_PW = (0x11 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_ABSQ_S_QH = (0x09 << 6) | OPC_ABSQ_S_QH_DSP, |
| /* DSP Bit/Manipulation Sub-class */ |
| OPC_REPL_OB = (0x02 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_REPL_PW = (0x12 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_REPL_QH = (0x0A << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_REPLV_OB = (0x03 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_REPLV_PW = (0x13 << 6) | OPC_ABSQ_S_QH_DSP, |
| OPC_REPLV_QH = (0x0B << 6) | OPC_ABSQ_S_QH_DSP, |
| }; |
| |
| #define MASK_ADDU_OB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Multiply Sub-class insns */ |
| OPC_MULEQ_S_PW_QHL = (0x1C << 6) | OPC_ADDU_OB_DSP, |
| OPC_MULEQ_S_PW_QHR = (0x1D << 6) | OPC_ADDU_OB_DSP, |
| OPC_MULEU_S_QH_OBL = (0x06 << 6) | OPC_ADDU_OB_DSP, |
| OPC_MULEU_S_QH_OBR = (0x07 << 6) | OPC_ADDU_OB_DSP, |
| OPC_MULQ_RS_QH = (0x1F << 6) | OPC_ADDU_OB_DSP, |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_RADDU_L_OB = (0x14 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBQ_PW = (0x13 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBQ_S_PW = (0x17 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBQ_QH = (0x0B << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBQ_S_QH = (0x0F << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBU_OB = (0x01 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBU_S_OB = (0x05 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBU_QH = (0x09 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBU_S_QH = (0x0D << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBUH_OB = (0x19 << 6) | OPC_ADDU_OB_DSP, |
| OPC_SUBUH_R_OB = (0x1B << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDQ_PW = (0x12 << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDQ_S_PW = (0x16 << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDQ_QH = (0x0A << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDQ_S_QH = (0x0E << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDU_OB = (0x00 << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDU_S_OB = (0x04 << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDU_QH = (0x08 << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDU_S_QH = (0x0C << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDUH_OB = (0x18 << 6) | OPC_ADDU_OB_DSP, |
| OPC_ADDUH_R_OB = (0x1A << 6) | OPC_ADDU_OB_DSP, |
| }; |
| |
| #define MASK_CMPU_EQ_OB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* DSP Compare-Pick Sub-class */ |
| OPC_CMP_EQ_PW = (0x10 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMP_LT_PW = (0x11 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMP_LE_PW = (0x12 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMP_EQ_QH = (0x08 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMP_LT_QH = (0x09 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMP_LE_QH = (0x0A << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPGDU_EQ_OB = (0x18 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPGDU_LT_OB = (0x19 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPGDU_LE_OB = (0x1A << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPGU_EQ_OB = (0x04 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPGU_LT_OB = (0x05 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPGU_LE_OB = (0x06 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPU_EQ_OB = (0x00 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPU_LT_OB = (0x01 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_CMPU_LE_OB = (0x02 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PACKRL_PW = (0x0E << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PICK_OB = (0x03 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PICK_PW = (0x13 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PICK_QH = (0x0B << 6) | OPC_CMPU_EQ_OB_DSP, |
| /* MIPS DSP Arithmetic Sub-class */ |
| OPC_PRECR_OB_QH = (0x0D << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECR_SRA_QH_PW = (0x1E << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECR_SRA_R_QH_PW = (0x1F << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECRQ_OB_QH = (0x0C << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECRQ_PW_L = (0x1C << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECRQ_QH_PW = (0x14 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECRQ_RS_QH_PW = (0x15 << 6) | OPC_CMPU_EQ_OB_DSP, |
| OPC_PRECRQU_S_OB_QH = (0x0F << 6) | OPC_CMPU_EQ_OB_DSP, |
| }; |
| |
| #define MASK_DAPPEND(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* DSP Append Sub-class */ |
| OPC_DAPPEND = (0x00 << 6) | OPC_DAPPEND_DSP, |
| OPC_PREPENDD = (0x03 << 6) | OPC_DAPPEND_DSP, |
| OPC_PREPENDW = (0x01 << 6) | OPC_DAPPEND_DSP, |
| OPC_DBALIGN = (0x10 << 6) | OPC_DAPPEND_DSP, |
| }; |
| |
| #define MASK_DEXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Accumulator and DSPControl Access Sub-class */ |
| OPC_DMTHLIP = (0x1F << 6) | OPC_DEXTR_W_DSP, |
| OPC_DSHILO = (0x1A << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTP = (0x02 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTPDP = (0x0A << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTPDPV = (0x0B << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTPV = (0x03 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_L = (0x10 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_R_L = (0x14 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_RS_L = (0x16 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_W = (0x00 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_R_W = (0x04 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_RS_W = (0x06 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTR_S_H = (0x0E << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_L = (0x11 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_R_L = (0x15 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_RS_L = (0x17 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_S_H = (0x0F << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_W = (0x01 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_R_W = (0x05 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DEXTRV_RS_W = (0x07 << 6) | OPC_DEXTR_W_DSP, |
| OPC_DSHILOV = (0x1B << 6) | OPC_DEXTR_W_DSP, |
| }; |
| |
| #define MASK_DINSV(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* DSP Bit/Manipulation Sub-class */ |
| OPC_DINSV = (0x00 << 6) | OPC_DINSV_DSP, |
| }; |
| |
| #define MASK_DPAQ_W_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP Multiply Sub-class insns */ |
| OPC_DMADD = (0x19 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DMADDU = (0x1D << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DMSUB = (0x1B << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DMSUBU = (0x1F << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPA_W_QH = (0x00 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPAQ_S_W_QH = (0x04 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPAQ_SA_L_PW = (0x0C << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPAU_H_OBL = (0x03 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPAU_H_OBR = (0x07 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPS_W_QH = (0x01 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPSQ_S_W_QH = (0x05 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPSQ_SA_L_PW = (0x0D << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPSU_H_OBL = (0x0B << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_DPSU_H_OBR = (0x0F << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_S_L_PWL = (0x1C << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_S_L_PWR = (0x1E << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_S_W_QHLL = (0x14 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_SA_W_QHLL = (0x10 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_S_W_QHLR = (0x15 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_SA_W_QHLR = (0x11 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_S_W_QHRL = (0x16 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_SA_W_QHRL = (0x12 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_S_W_QHRR = (0x17 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MAQ_SA_W_QHRR = (0x13 << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MULSAQ_S_L_PW = (0x0E << 6) | OPC_DPAQ_W_QH_DSP, |
| OPC_MULSAQ_S_W_QH = (0x06 << 6) | OPC_DPAQ_W_QH_DSP, |
| }; |
| |
| #define MASK_SHLL_OB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) |
| enum { |
| /* MIPS DSP GPR-Based Shift Sub-class */ |
| OPC_SHLL_PW = (0x10 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLL_S_PW = (0x14 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLLV_OB = (0x02 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLLV_PW = (0x12 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLLV_S_PW = (0x16 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLLV_QH = (0x0A << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLLV_S_QH = (0x0E << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRA_PW = (0x11 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRA_R_PW = (0x15 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRAV_OB = (0x06 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRAV_R_OB = (0x07 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRAV_PW = (0x13 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRAV_R_PW = (0x17 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRAV_QH = (0x0B << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRAV_R_QH = (0x0F << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRLV_OB = (0x03 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRLV_QH = (0x1B << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLL_OB = (0x00 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLL_QH = (0x08 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHLL_S_QH = (0x0C << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRA_OB = (0x04 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRA_R_OB = (0x05 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRA_QH = (0x09 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRA_R_QH = (0x0D << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRL_OB = (0x01 << 6) | OPC_SHLL_OB_DSP, |
| OPC_SHRL_QH = (0x19 << 6) | OPC_SHLL_OB_DSP, |
| }; |
| |
| /* Coprocessor 0 (rs field) */ |
| #define MASK_CP0(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) |
| |
| enum { |
| OPC_MFC0 = (0x00 << 21) | OPC_CP0, |
| OPC_DMFC0 = (0x01 << 21) | OPC_CP0, |
| OPC_MTC0 = (0x04 << 21) | OPC_CP0, |
| OPC_DMTC0 = (0x05 << 21) | OPC_CP0, |
| OPC_MFTR = (0x08 << 21) | OPC_CP0, |
| OPC_RDPGPR = (0x0A << 21) | OPC_CP0, |
| OPC_MFMC0 = (0x0B << 21) | OPC_CP0, |
| OPC_MTTR = (0x0C << 21) | OPC_CP0, |
| OPC_WRPGPR = (0x0E << 21) | OPC_CP0, |
| OPC_C0 = (0x10 << 21) | OPC_CP0, |
| OPC_C0_FIRST = (0x10 << 21) | OPC_CP0, |
| OPC_C0_LAST = (0x1F << 21) | OPC_CP0, |
| }; |
| |
| /* MFMC0 opcodes */ |
| #define MASK_MFMC0(op) MASK_CP0(op) | (op & 0xFFFF) |
| |
| enum { |
| OPC_DMT = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, |
| OPC_EMT = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, |
| OPC_DVPE = 0x01 | (0 << 5) | OPC_MFMC0, |
| OPC_EVPE = 0x01 | (1 << 5) | OPC_MFMC0, |
| OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, |
| OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0, |
| }; |
| |
| /* Coprocessor 0 (with rs == C0) */ |
| #define MASK_C0(op) MASK_CP0(op) | (op & 0x3F) |
| |
| enum { |
| OPC_TLBR = 0x01 | OPC_C0, |
| OPC_TLBWI = 0x02 | OPC_C0, |
| OPC_TLBINV = 0x03 | OPC_C0, |
| OPC_TLBINVF = 0x04 | OPC_C0, |
| OPC_TLBWR = 0x06 | OPC_C0, |
| OPC_TLBP = 0x08 | OPC_C0, |
| OPC_RFE = 0x10 | OPC_C0, |
| OPC_ERET = 0x18 | OPC_C0, |
| OPC_DERET = 0x1F | OPC_C0, |
| OPC_WAIT = 0x20 | OPC_C0, |
| }; |
| |
| /* Coprocessor 1 (rs field) */ |
| #define MASK_CP1(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) |
| |
| /* Values for the fmt field in FP instructions */ |
| enum { |
| /* 0 - 15 are reserved */ |
| FMT_S = 16, /* single fp */ |
| FMT_D = 17, /* double fp */ |
| FMT_E = 18, /* extended fp */ |
| FMT_Q = 19, /* quad fp */ |
| FMT_W = 20, /* 32-bit fixed */ |
| FMT_L = 21, /* 64-bit fixed */ |
| FMT_PS = 22, /* paired single fp */ |
| /* 23 - 31 are reserved */ |
| }; |
| |
| enum { |
| OPC_MFC1 = (0x00 << 21) | OPC_CP1, |
| OPC_DMFC1 = (0x01 << 21) | OPC_CP1, |
| OPC_CFC1 = (0x02 << 21) | OPC_CP1, |
| OPC_MFHC1 = (0x03 << 21) | OPC_CP1, |
| OPC_MTC1 = (0x04 << 21) | OPC_CP1, |
| OPC_DMTC1 = (0x05 << 21) | OPC_CP1, |
| OPC_CTC1 = (0x06 << 21) | OPC_CP1, |
| OPC_MTHC1 = (0x07 << 21) | OPC_CP1, |
| OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ |
| OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, |
| OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, |
| OPC_BZ_V = (0x0B << 21) | OPC_CP1, |
| OPC_BNZ_V = (0x0F << 21) | OPC_CP1, |
| OPC_S_FMT = (FMT_S << 21) | OPC_CP1, |
| OPC_D_FMT = (FMT_D << 21) | OPC_CP1, |
| OPC_E_FMT = (FMT_E << 21) | OPC_CP1, |
| OPC_Q_FMT = (FMT_Q << 21) | OPC_CP1, |
| OPC_W_FMT = (FMT_W << 21) | OPC_CP1, |
| OPC_L_FMT = (FMT_L << 21) | OPC_CP1, |
| OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1, |
| OPC_BC1EQZ = (0x09 << 21) | OPC_CP1, |
| OPC_BC1NEZ = (0x0D << 21) | OPC_CP1, |
| OPC_BZ_B = (0x18 << 21) | OPC_CP1, |
| OPC_BZ_H = (0x19 << 21) | OPC_CP1, |
| OPC_BZ_W = (0x1A << 21) | OPC_CP1, |
| OPC_BZ_D = (0x1B << 21) | OPC_CP1, |
| OPC_BNZ_B = (0x1C << 21) | OPC_CP1, |
| OPC_BNZ_H = (0x1D << 21) | OPC_CP1, |
| OPC_BNZ_W = (0x1E << 21) | OPC_CP1, |
| OPC_BNZ_D = (0x1F << 21) | OPC_CP1, |
| }; |
| |
| #define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) |
| #define MASK_BC1(op) MASK_CP1(op) | (op & (0x3 << 16)) |
| |
| enum { |
| OPC_BC1F = (0x00 << 16) | OPC_BC1, |
| OPC_BC1T = (0x01 << 16) | OPC_BC1, |
| OPC_BC1FL = (0x02 << 16) | OPC_BC1, |
| OPC_BC1TL = (0x03 << 16) | OPC_BC1, |
| }; |
| |
| enum { |
| OPC_BC1FANY2 = (0x00 << 16) | OPC_BC1ANY2, |
| OPC_BC1TANY2 = (0x01 << 16) | OPC_BC1ANY2, |
| }; |
| |
| enum { |
| OPC_BC1FANY4 = (0x00 << 16) | OPC_BC1ANY4, |
| OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4, |
| }; |
| |
| #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) |
| |
| enum { |
| OPC_MFC2 = (0x00 << 21) | OPC_CP2, |
| OPC_DMFC2 = (0x01 << 21) | OPC_CP2, |
| OPC_CFC2 = (0x02 << 21) | OPC_CP2, |
| OPC_MFHC2 = (0x03 << 21) | OPC_CP2, |
| OPC_MTC2 = (0x04 << 21) | OPC_CP2, |
| OPC_DMTC2 = (0x05 << 21) | OPC_CP2, |
| OPC_CTC2 = (0x06 << 21) | OPC_CP2, |
| OPC_MTHC2 = (0x07 << 21) | OPC_CP2, |
| OPC_BC2 = (0x08 << 21) | OPC_CP2, |
| OPC_BC2EQZ = (0x09 << 21) | OPC_CP2, |
| OPC_BC2NEZ = (0x0D << 21) | OPC_CP2, |
| }; |
| |
| #define MASK_LMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F)) |
| |
| enum { |
| OPC_PADDSH = (24 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDUSH = (25 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDH = (26 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDW = (27 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDSB = (28 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDUSB = (29 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDB = (30 << 21) | (0x00) | OPC_CP2, |
| OPC_PADDD = (31 << 21) | (0x00) | OPC_CP2, |
| |
| OPC_PSUBSH = (24 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBUSH = (25 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBH = (26 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBW = (27 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBSB = (28 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBUSB = (29 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBB = (30 << 21) | (0x01) | OPC_CP2, |
| OPC_PSUBD = (31 << 21) | (0x01) | OPC_CP2, |
| |
| OPC_PSHUFH = (24 << 21) | (0x02) | OPC_CP2, |
| OPC_PACKSSWH = (25 << 21) | (0x02) | OPC_CP2, |
| OPC_PACKSSHB = (26 << 21) | (0x02) | OPC_CP2, |
| OPC_PACKUSHB = (27 << 21) | (0x02) | OPC_CP2, |
| OPC_XOR_CP2 = (28 << 21) | (0x02) | OPC_CP2, |
| OPC_NOR_CP2 = (29 << 21) | (0x02) | OPC_CP2, |
| OPC_AND_CP2 = (30 << 21) | (0x02) | OPC_CP2, |
| OPC_PANDN = (31 << 21) | (0x02) | OPC_CP2, |
| |
| OPC_PUNPCKLHW = (24 << 21) | (0x03) | OPC_CP2, |
| OPC_PUNPCKHHW = (25 << 21) | (0x03) | OPC_CP2, |
| OPC_PUNPCKLBH = (26 << 21) | (0x03) | OPC_CP2, |
| OPC_PUNPCKHBH = (27 << 21) | (0x03) | OPC_CP2, |
| OPC_PINSRH_0 = (28 << 21) | (0x03) | OPC_CP2, |
| OPC_PINSRH_1 = (29 << 21) | (0x03) | OPC_CP2, |
| OPC_PINSRH_2 = (30 << 21) | (0x03) | OPC_CP2, |
| OPC_PINSRH_3 = (31 << 21) | (0x03) | OPC_CP2, |
| |
| OPC_PAVGH = (24 << 21) | (0x08) | OPC_CP2, |
| OPC_PAVGB = (25 << 21) | (0x08) | OPC_CP2, |
| OPC_PMAXSH = (26 << 21) | (0x08) | OPC_CP2, |
| OPC_PMINSH = (27 << 21) | (0x08) | OPC_CP2, |
| OPC_PMAXUB = (28 << 21) | (0x08) | OPC_CP2, |
| OPC_PMINUB = (29 << 21) | (0x08) | OPC_CP2, |
| |
| OPC_PCMPEQW = (24 << 21) | (0x09) | OPC_CP2, |
| OPC_PCMPGTW = (25 << 21) | (0x09) | OPC_CP2, |
| OPC_PCMPEQH = (26 << 21) | (0x09) | OPC_CP2, |
| OPC_PCMPGTH = (27 << 21) | (0x09) | OPC_CP2, |
| OPC_PCMPEQB = (28 << 21) | (0x09) | OPC_CP2, |
| OPC_PCMPGTB = (29 << 21) | (0x09) | OPC_CP2, |
| |
| OPC_PSLLW = (24 << 21) | (0x0A) | OPC_CP2, |
| OPC_PSLLH = (25 << 21) | (0x0A) | OPC_CP2, |
| OPC_PMULLH = (26 << 21) | (0x0A) | OPC_CP2, |
| OPC_PMULHH = (27 << 21) | (0x0A) | OPC_CP2, |
| OPC_PMULUW = (28 << 21) | (0x0A) | OPC_CP2, |
| OPC_PMULHUH = (29 << 21) | (0x0A) | OPC_CP2, |
| |
| OPC_PSRLW = (24 << 21) | (0x0B) | OPC_CP2, |
| OPC_PSRLH = (25 << 21) | (0x0B) | OPC_CP2, |
| OPC_PSRAW = (26 << 21) | (0x0B) | OPC_CP2, |
| OPC_PSRAH = (27 << 21) | (0x0B) | OPC_CP2, |
| OPC_PUNPCKLWD = (28 << 21) | (0x0B) | OPC_CP2, |
| OPC_PUNPCKHWD = (29 << 21) | (0x0B) | OPC_CP2, |
| |
| OPC_ADDU_CP2 = (24 << 21) | (0x0C) | OPC_CP2, |
| OPC_OR_CP2 = (25 << 21) | (0x0C) | OPC_CP2, |
| OPC_ADD_CP2 = (26 << 21) | (0x0C) | OPC_CP2, |
| OPC_DADD_CP2 = (27 << 21) | (0x0C) | OPC_CP2, |
| OPC_SEQU_CP2 = (28 << 21) | (0x0C) | OPC_CP2, |
| OPC_SEQ_CP2 = (29 << 21) | (0x0C) | OPC_CP2, |
| |
| OPC_SUBU_CP2 = (24 << 21) | (0x0D) | OPC_CP2, |
| OPC_PASUBUB = (25 << 21) | (0x0D) | OPC_CP2, |
| OPC_SUB_CP2 = (26 << 21) | (0x0D) | OPC_CP2, |
| OPC_DSUB_CP2 = (27 << 21) | (0x0D) | OPC_CP2, |
| OPC_SLTU_CP2 = (28 << 21) | (0x0D) | OPC_CP2, |
| OPC_SLT_CP2 = (29 << 21) | (0x0D) | OPC_CP2, |
| |
| OPC_SLL_CP2 = (24 << 21) | (0x0E) | OPC_CP2, |
| OPC_DSLL_CP2 = (25 << 21) | (0x0E) | OPC_CP2, |
| OPC_PEXTRH = (26 << 21) | (0x0E) | OPC_CP2, |
| OPC_PMADDHW = (27 << 21) | (0x0E) | OPC_CP2, |
| OPC_SLEU_CP2 = (28 << 21) | (0x0E) | OPC_CP2, |
| OPC_SLE_CP2 = (29 << 21) | (0x0E) | OPC_CP2, |
| |
| OPC_SRL_CP2 = (24 << 21) | (0x0F) | OPC_CP2, |
| OPC_DSRL_CP2 = (25 << 21) | (0x0F) | OPC_CP2, |
| OPC_SRA_CP2 = (26 << 21) | (0x0F) | OPC_CP2, |
| OPC_DSRA_CP2 = (27 << 21) | (0x0F) | OPC_CP2, |
| OPC_BIADD = (28 << 21) | (0x0F) | OPC_CP2, |
| OPC_PMOVMSKB = (29 << 21) | (0x0F) | OPC_CP2, |
| }; |
| |
| |
| #define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & 0x3F) |
| |
| enum { |
| OPC_LWXC1 = 0x00 | OPC_CP3, |
| OPC_LDXC1 = 0x01 | OPC_CP3, |
| OPC_LUXC1 = 0x05 | OPC_CP3, |
| OPC_SWXC1 = 0x08 | OPC_CP3, |
| OPC_SDXC1 = 0x09 | OPC_CP3, |
| OPC_SUXC1 = 0x0D | OPC_CP3, |
| OPC_PREFX = 0x0F | OPC_CP3, |
| OPC_ALNV_PS = 0x1E | OPC_CP3, |
| OPC_MADD_S = 0x20 | OPC_CP3, |
| OPC_MADD_D = 0x21 | OPC_CP3, |
| OPC_MADD_PS = 0x26 | OPC_CP3, |
| OPC_MSUB_S = 0x28 | OPC_CP3, |
| OPC_MSUB_D = 0x29 | OPC_CP3, |
| OPC_MSUB_PS = 0x2E | OPC_CP3, |
| OPC_NMADD_S = 0x30 | OPC_CP3, |
| OPC_NMADD_D = 0x31 | OPC_CP3, |
| OPC_NMADD_PS= 0x36 | OPC_CP3, |
| OPC_NMSUB_S = 0x38 | OPC_CP3, |
| OPC_NMSUB_D = 0x39 | OPC_CP3, |
| OPC_NMSUB_PS= 0x3E | OPC_CP3, |
| }; |
| |
| /* MSA Opcodes */ |
| #define MASK_MSA_MINOR(op) (MASK_OP_MAJOR(op) | (op & 0x3F)) |
| enum { |
| OPC_MSA_I8_00 = 0x00 | OPC_MSA, |
| OPC_MSA_I8_01 = 0x01 | OPC_MSA, |
| OPC_MSA_I8_02 = 0x02 | OPC_MSA, |
| OPC_MSA_I5_06 = 0x06 | OPC_MSA, |
| OPC_MSA_I5_07 = 0x07 | OPC_MSA, |
| OPC_MSA_BIT_09 = 0x09 | OPC_MSA, |
| OPC_MSA_BIT_0A = 0x0A | OPC_MSA, |
| OPC_MSA_3R_0D = 0x0D | OPC_MSA, |
| OPC_MSA_3R_0E = 0x0E | OPC_MSA, |
| OPC_MSA_3R_0F = 0x0F | OPC_MSA, |
| OPC_MSA_3R_10 = 0x10 | OPC_MSA, |
| OPC_MSA_3R_11 = 0x11 | OPC_MSA, |
| OPC_MSA_3R_12 = 0x12 | OPC_MSA, |
| OPC_MSA_3R_13 = 0x13 | OPC_MSA, |
| OPC_MSA_3R_14 = 0x14 | OPC_MSA, |
| OPC_MSA_3R_15 = 0x15 | OPC_MSA, |
| OPC_MSA_ELM = 0x19 | OPC_MSA, |
| OPC_MSA_3RF_1A = 0x1A | OPC_MSA, |
| OPC_MSA_3RF_1B = 0x1B | OPC_MSA, |
| OPC_MSA_3RF_1C = 0x1C | OPC_MSA, |
| OPC_MSA_VEC = 0x1E | OPC_MSA, |
| |
| /* MI10 instruction */ |
| OPC_LD_B = (0x20) | OPC_MSA, |
| OPC_LD_H = (0x21) | OPC_MSA, |
| OPC_LD_W = (0x22) | OPC_MSA, |
| OPC_LD_D = (0x23) | OPC_MSA, |
| OPC_ST_B = (0x24) | OPC_MSA, |
| OPC_ST_H = (0x25) | OPC_MSA, |
| OPC_ST_W = (0x26) | OPC_MSA, |
| OPC_ST_D = (0x27) | OPC_MSA, |
| }; |
| |
| enum { |
| /* I5 instruction df(bits 22..21) = _b, _h, _w, _d */ |
| OPC_ADDVI_df = (0x0 << 23) | OPC_MSA_I5_06, |
| OPC_CEQI_df = (0x0 << 23) | OPC_MSA_I5_07, |
| OPC_SUBVI_df = (0x1 << 23) | OPC_MSA_I5_06, |
| OPC_MAXI_S_df = (0x2 << 23) | OPC_MSA_I5_06, |
| OPC_CLTI_S_df = (0x2 << 23) | OPC_MSA_I5_07, |
| OPC_MAXI_U_df = (0x3 << 23) | OPC_MSA_I5_06, |
| OPC_CLTI_U_df = (0x3 << 23) | OPC_MSA_I5_07, |
| OPC_MINI_S_df = (0x4 << 23) | OPC_MSA_I5_06, |
| OPC_CLEI_S_df = (0x4 << 23) | OPC_MSA_I5_07, |
| OPC_MINI_U_df = (0x5 << 23) | OPC_MSA_I5_06, |
| OPC_CLEI_U_df = (0x5 << 23) | OPC_MSA_I5_07, |
| OPC_LDI_df = (0x6 << 23) | OPC_MSA_I5_07, |
| |
| /* I8 instruction */ |
| OPC_ANDI_B = (0x0 << 24) | OPC_MSA_I8_00, |
| OPC_BMNZI_B = (0x0 << 24) | OPC_MSA_I8_01, |
| OPC_SHF_B = (0x0 << 24) | OPC_MSA_I8_02, |
| OPC_ORI_B = (0x1 << 24) | OPC_MSA_I8_00, |
| OPC_BMZI_B = (0x1 << 24) | OPC_MSA_I8_01, |
| OPC_SHF_H = (0x1 << 24) | OPC_MSA_I8_02, |
| OPC_NORI_B = (0x2 << 24) | OPC_MSA_I8_00, |
| OPC_BSELI_B = (0x2 << 24) | OPC_MSA_I8_01, |
| OPC_SHF_W = (0x2 << 24) | OPC_MSA_I8_02, |
| OPC_XORI_B = (0x3 << 24) | OPC_MSA_I8_00, |
| |
| /* VEC/2R/2RF instruction */ |
| OPC_AND_V = (0x00 << 21) | OPC_MSA_VEC, |
| OPC_OR_V = (0x01 << 21) | OPC_MSA_VEC, |
| OPC_NOR_V = (0x02 << 21) | OPC_MSA_VEC, |
| OPC_XOR_V = (0x03 << 21) | OPC_MSA_VEC, |
| OPC_BMNZ_V = (0x04 << 21) | OPC_MSA_VEC, |
| OPC_BMZ_V = (0x05 << 21) | OPC_MSA_VEC, |
| OPC_BSEL_V = (0x06 << 21) | OPC_MSA_VEC, |
| |
| OPC_MSA_2R = (0x18 << 21) | OPC_MSA_VEC, |
| OPC_MSA_2RF = (0x19 << 21) | OPC_MSA_VEC, |
| |
| /* 2R instruction df(bits 17..16) = _b, _h, _w, _d */ |
| OPC_FILL_df = (0x00 << 18) | OPC_MSA_2R, |
| OPC_PCNT_df = (0x01 << 18) | OPC_MSA_2R, |
| OPC_NLOC_df = (0x02 << 18) | OPC_MSA_2R, |
| OPC_NLZC_df = (0x03 << 18) | OPC_MSA_2R, |
| |
| /* 2RF instruction df(bit 16) = _w, _d */ |
| OPC_FCLASS_df = (0x00 << 17) | OPC_MSA_2RF, |
| OPC_FTRUNC_S_df = (0x01 << 17) | OPC_MSA_2RF, |
| OPC_FTRUNC_U_df = (0x02 << 17) | OPC_MSA_2RF, |
| OPC_FSQRT_df = (0x03 << 17) | OPC_MSA_2RF, |
| OPC_FRSQRT_df = (0x04 << 17) | OPC_MSA_2RF, |
| OPC_FRCP_df = (0x05 << 17) | OPC_MSA_2RF, |
| OPC_FRINT_df = (0x06 << 17) | OPC_MSA_2RF, |
| OPC_FLOG2_df = (0x07 << 17) | OPC_MSA_2RF, |
| OPC_FEXUPL_df = (0x08 << 17) | OPC_MSA_2RF, |
| OPC_FEXUPR_df = (0x09 << 17) | OPC_MSA_2RF, |
| OPC_FFQL_df = (0x0A << 17) | OPC_MSA_2RF, |
| OPC_FFQR_df = (0x0B << 17) | OPC_MSA_2RF, |
| OPC_FTINT_S_df = (0x0C << 17) | OPC_MSA_2RF, |
| OPC_FTINT_U_df = (0x0D << 17) | OPC_MSA_2RF, |
| OPC_FFINT_S_df = (0x0E << 17) | OPC_MSA_2RF, |
| OPC_FFINT_U_df = (0x0F << 17) | OPC_MSA_2RF, |
| |
| /* 3R instruction df(bits 22..21) = _b, _h, _w, d */ |
| OPC_SLL_df = (0x0 << 23) | OPC_MSA_3R_0D, |
| OPC_ADDV_df = (0x0 << 23) | OPC_MSA_3R_0E, |
| OPC_CEQ_df = (0x0 << 23) | OPC_MSA_3R_0F, |
| OPC_ADD_A_df = (0x0 << 23) | OPC_MSA_3R_10, |
| OPC_SUBS_S_df = (0x0 << 23) | OPC_MSA_3R_11, |
| OPC_MULV_df = (0x0 << 23) | OPC_MSA_3R_12, |
| OPC_DOTP_S_df = (0x0 << 23) | OPC_MSA_3R_13, |
| OPC_SLD_df = (0x0 << 23) | OPC_MSA_3R_14, |
| OPC_VSHF_df = (0x0 << 23) | OPC_MSA_3R_15, |
| OPC_SRA_df = (0x1 << 23) | OPC_MSA_3R_0D, |
| OPC_SUBV_df = (0x1 << 23) | OPC_MSA_3R_0E, |
| OPC_ADDS_A_df = (0x1 << 23) | OPC_MSA_3R_10, |
| OPC_SUBS_U_df = (0x1 << 23) | OPC_MSA_3R_11, |
| OPC_MADDV_df = (0x1 << 23) | OPC_MSA_3R_12, |
| OPC_DOTP_U_df = (0x1 << 23) | OPC_MSA_3R_13, |
| OPC_SPLAT_df = (0x1 << 23) | OPC_MSA_3R_14, |
| OPC_SRAR_df = (0x1 << 23) | OPC_MSA_3R_15, |
| OPC_SRL_df = (0x2 << 23) | OPC_MSA_3R_0D, |
| OPC_MAX_S_df = (0x2 << 23) | OPC_MSA_3R_0E, |
| OPC_CLT_S_df = (0x2 << 23) | OPC_MSA_3R_0F, |
| OPC_ADDS_S_df = (0x2 << 23) | OPC_MSA_3R_10, |
| OPC_SUBSUS_U_df = (0x2 << 23) | OPC_MSA_3R_11, |
| OPC_MSUBV_df = (0x2 << 23) | OPC_MSA_3R_12, |
| OPC_DPADD_S_df = (0x2 << 23) | OPC_MSA_3R_13, |
| OPC_PCKEV_df = (0x2 << 23) | OPC_MSA_3R_14, |
| OPC_SRLR_df = (0x2 << 23) | OPC_MSA_3R_15, |
| OPC_BCLR_df = (0x3 << 23) | OPC_MSA_3R_0D, |
| OPC_MAX_U_df = (0x3 << 23) | OPC_MSA_3R_0E, |
| OPC_CLT_U_df = (0x3 << 23) | OPC_MSA_3R_0F, |
| OPC_ADDS_U_df = (0x3 << 23) | OPC_MSA_3R_10, |
| OPC_SUBSUU_S_df = (0x3 << 23) | OPC_MSA_3R_11, |
| OPC_DPADD_U_df = (0x3 << 23) | OPC_MSA_3R_13, |
| OPC_PCKOD_df = (0x3 << 23) | OPC_MSA_3R_14, |
| OPC_BSET_df = (0x4 << 23) | OPC_MSA_3R_0D, |
| OPC_MIN_S_df = (0x4 << 23) | OPC_MSA_3R_0E, |
| OPC_CLE_S_df = (0x4 << 23) | OPC_MSA_3R_0F, |
| OPC_AVE_S_df = (0x4 << 23) | OPC_MSA_3R_10, |
| OPC_ASUB_S_df = (0x4 << 23) | OPC_MSA_3R_11, |
| OPC_DIV_S_df = (0x4 << 23) | OPC_MSA_3R_12, |
| OPC_DPSUB_S_df = (0x4 << 23) | OPC_MSA_3R_13, |
| OPC_ILVL_df = (0x4 << 23) | OPC_MSA_3R_14, |
| OPC_HADD_S_df = (0x4 << 23) | OPC_MSA_3R_15, |
| OPC_BNEG_df = (0x5 << 23) | OPC_MSA_3R_0D, |
| OPC_MIN_U_df = (0x5 << 23) | OPC_MSA_3R_0E, |
| OPC_CLE_U_df = (0x5 << 23) | OPC_MSA_3R_0F, |
| OPC_AVE_U_df = (0x5 << 23) | OPC_MSA_3R_10, |
| OPC_ASUB_U_df = (0x5 << 23) | OPC_MSA_3R_11, |
| OPC_DIV_U_df = (0x5 << 23) | OPC_MSA_3R_12, |
| OPC_DPSUB_U_df = (0x5 << 23) | OPC_MSA_3R_13, |
| OPC_ILVR_df = (0x5 << 23) | OPC_MSA_3R_14, |
| OPC_HADD_U_df = (0x5 << 23) | OPC_MSA_3R_15, |
| OPC_BINSL_df = (0x6 << 23) | OPC_MSA_3R_0D, |
| OPC_MAX_A_df = (0x6 << 23) | OPC_MSA_3R_0E, |
| OPC_AVER_S_df = (0x6 << 23) | OPC_MSA_3R_10, |
| OPC_MOD_S_df = (0x6 << 23) | OPC_MSA_3R_12, |
| OPC_ILVEV_df = (0x6 << 23) | OPC_MSA_3R_14, |
| OPC_HSUB_S_df = (0x6 << 23) | OPC_MSA_3R_15, |
| OPC_BINSR_df = (0x7 << 23) | OPC_MSA_3R_0D, |
| OPC_MIN_A_df = (0x7 << 23) | OPC_MSA_3R_0E, |
| OPC_AVER_U_df = (0x7 << 23) | OPC_MSA_3R_10, |
| OPC_MOD_U_df = (0x7 << 23) | OPC_MSA_3R_12, |
| OPC_ILVOD_df = (0x7 << 23) | OPC_MSA_3R_14, |
| OPC_HSUB_U_df = (0x7 << 23) | OPC_MSA_3R_15, |
| |
| /* ELM instructions df(bits 21..16) = _b, _h, _w, _d */ |
| OPC_SLDI_df = (0x0 << 22) | (0x00 << 16) | OPC_MSA_ELM, |
| OPC_CTCMSA = (0x0 << 22) | (0x3E << 16) | OPC_MSA_ELM, |
| OPC_SPLATI_df = (0x1 << 22) | (0x00 << 16) | OPC_MSA_ELM, |
| OPC_CFCMSA = (0x1 << 22) | (0x3E << 16) | OPC_MSA_ELM, |
| OPC_COPY_S_df = (0x2 << 22) | (0x00 << 16) | OPC_MSA_ELM, |
| OPC_MOVE_V = (0x2 << 22) | (0x3E << 16) | OPC_MSA_ELM, |
| OPC_COPY_U_df = (0x3 << 22) | (0x00 << 16) | OPC_MSA_ELM, |
| OPC_INSERT_df = (0x4 << 22) | (0x00 << 16) | OPC_MSA_ELM, |
| OPC_INSVE_df = (0x5 << 22) | (0x00 << 16) | OPC_MSA_ELM, |
| |
| /* 3RF instruction _df(bit 21) = _w, _d */ |
| OPC_FCAF_df = (0x0 << 22) | OPC_MSA_3RF_1A, |
| OPC_FADD_df = (0x0 << 22) | OPC_MSA_3RF_1B, |
| OPC_FCUN_df = (0x1 << 22) | OPC_MSA_3RF_1A, |
| OPC_FSUB_df = (0x1 << 22) | OPC_MSA_3RF_1B, |
| OPC_FCOR_df = (0x1 << 22) | OPC_MSA_3RF_1C, |
| OPC_FCEQ_df = (0x2 << 22) | OPC_MSA_3RF_1A, |
| OPC_FMUL_df = (0x2 << 22) | OPC_MSA_3RF_1B, |
| OPC_FCUNE_df = (0x2 << 22) | OPC_MSA_3RF_1C, |
| OPC_FCUEQ_df = (0x3 << 22) | OPC_MSA_3RF_1A, |
| OPC_FDIV_df = (0x3 << 22) | OPC_MSA_3RF_1B, |
| OPC_FCNE_df = (0x3 << 22) | OPC_MSA_3RF_1C, |
| OPC_FCLT_df = (0x4 << 22) | OPC_MSA_3RF_1A, |
| OPC_FMADD_df = (0x4 << 22) | OPC_MSA_3RF_1B, |
| OPC_MUL_Q_df = (0x4 << 22) | OPC_MSA_3RF_1C, |
| OPC_FCULT_df = (0x5 << 22) | OPC_MSA_3RF_1A, |
| OPC_FMSUB_df = (0x5 << 22) | OPC_MSA_3RF_1B, |
| OPC_MADD_Q_df = (0x5 << 22) | OPC_MSA_3RF_1C, |
| OPC_FCLE_df = (0x6 << 22) | OPC_MSA_3RF_1A, |
| OPC_MSUB_Q_df = (0x6 << 22) | OPC_MSA_3RF_1C, |
| OPC_FCULE_df = (0x7 << 22) | OPC_MSA_3RF_1A, |
| OPC_FEXP2_df = (0x7 << 22) | OPC_MSA_3RF_1B, |
| OPC_FSAF_df = (0x8 << 22) | OPC_MSA_3RF_1A, |
| OPC_FEXDO_df = (0x8 << 22) | OPC_MSA_3RF_1B, |
| OPC_FSUN_df = (0x9 << 22) | OPC_MSA_3RF_1A, |
| OPC_FSOR_df = (0x9 << 22) | OPC_MSA_3RF_1C, |
| OPC_FSEQ_df = (0xA << 22) | OPC_MSA_3RF_1A, |
| OPC_FTQ_df = (0xA << 22) | OPC_MSA_3RF_1B, |
| OPC_FSUNE_df = (0xA << 22) | OPC_MSA_3RF_1C, |
| OPC_FSUEQ_df = (0xB << 22) | OPC_MSA_3RF_1A, |
| OPC_FSNE_df = (0xB << 22) | OPC_MSA_3RF_1C, |
| OPC_FSLT_df = (0xC << 22) | OPC_MSA_3RF_1A, |
| OPC_FMIN_df = (0xC << 22) | OPC_MSA_3RF_1B, |
| OPC_MULR_Q_df = (0xC << 22) | OPC_MSA_3RF_1C, |
| OPC_FSULT_df = (0xD << 22) | OPC_MSA_3RF_1A, |
| OPC_FMIN_A_df = (0xD << 22) | OPC_MSA_3RF_1B, |
| OPC_MADDR_Q_df = (0xD << 22) | OPC_MSA_3RF_1C, |
| OPC_FSLE_df = (0xE << 22) | OPC_MSA_3RF_1A, |
| OPC_FMAX_df = (0xE << 22) | OPC_MSA_3RF_1B, |
| OPC_MSUBR_Q_df = (0xE << 22) | OPC_MSA_3RF_1C, |
| OPC_FSULE_df = (0xF << 22) | OPC_MSA_3RF_1A, |
| OPC_FMAX_A_df = (0xF << 22) | OPC_MSA_3RF_1B, |
| |
| /* BIT instruction df(bits 22..16) = _B _H _W _D */ |
| OPC_SLLI_df = (0x0 << 23) | OPC_MSA_BIT_09, |
| OPC_SAT_S_df = (0x0 << 23) | OPC_MSA_BIT_0A, |
| OPC_SRAI_df = (0x1 << 23) | OPC_MSA_BIT_09, |
| OPC_SAT_U_df = (0x1 << 23) | OPC_MSA_BIT_0A, |
| OPC_SRLI_df = (0x2 << 23) | OPC_MSA_BIT_09, |
| OPC_SRARI_df = (0x2 << 23) | OPC_MSA_BIT_0A, |
| OPC_BCLRI_df = (0x3 << 23) | OPC_MSA_BIT_09, |
| OPC_SRLRI_df = (0x3 << 23) | OPC_MSA_BIT_0A, |
| OPC_BSETI_df = (0x4 << 23) | OPC_MSA_BIT_09, |
| OPC_BNEGI_df = (0x5 << 23) | OPC_MSA_BIT_09, |
| OPC_BINSLI_df = (0x6 << 23) | OPC_MSA_BIT_09, |
| OPC_BINSRI_df = (0x7 << 23) | OPC_MSA_BIT_09, |
| }; |
| |
| /* global register indices */ |
| static TCGv_ptr cpu_env; |
| static TCGv cpu_gpr[32], cpu_PC; |
| static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC]; |
| static TCGv cpu_dspctrl, btarget, bcond; |
| static TCGv_i32 hflags; |
| static TCGv_i32 fpu_fcr0, fpu_fcr31; |
| static TCGv_i64 fpu_f64[32]; |
| static TCGv_i64 msa_wr_d[64]; |
| |
| static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; |
| static target_ulong gen_opc_btarget[OPC_BUF_SIZE]; |
| |
| #include "exec/gen-icount.h" |
| |
| #define gen_helper_0e0i(name, arg) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg); \ |
| gen_helper_##name(cpu_env, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| #define gen_helper_0e1i(name, arg1, arg2) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ |
| gen_helper_##name(cpu_env, arg1, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| #define gen_helper_1e0i(name, ret, arg1) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg1); \ |
| gen_helper_##name(ret, cpu_env, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| #define gen_helper_1e1i(name, ret, arg1, arg2) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ |
| gen_helper_##name(ret, cpu_env, arg1, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| #define gen_helper_0e2i(name, arg1, arg2, arg3) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ |
| gen_helper_##name(cpu_env, arg1, arg2, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| #define gen_helper_1e2i(name, ret, arg1, arg2, arg3) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ |
| gen_helper_##name(ret, cpu_env, arg1, arg2, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| #define gen_helper_0e3i(name, arg1, arg2, arg3, arg4) do { \ |
| TCGv_i32 helper_tmp = tcg_const_i32(arg4); \ |
| gen_helper_##name(cpu_env, arg1, arg2, arg3, helper_tmp); \ |
| tcg_temp_free_i32(helper_tmp); \ |
| } while(0) |
| |
| typedef struct DisasContext { |
| struct TranslationBlock *tb; |
| target_ulong pc, saved_pc; |
| uint32_t opcode; |
| int singlestep_enabled; |
| int insn_flags; |
| int32_t CP0_Config1; |
| /* Routine used to access memory */ |
| int mem_idx; |
| uint32_t hflags, saved_hflags; |
| int bstate; |
| target_ulong btarget; |
| bool ulri; |
| int kscrexist; |
| bool rxi; |
| int ie; |
| bool bi; |
| bool bp; |
| } DisasContext; |
| |
| enum { |
| BS_NONE = 0, /* We go out of the TB without reaching a branch or an |
| * exception condition */ |
| BS_STOP = 1, /* We want to stop translation for any reason */ |
| BS_BRANCH = 2, /* We reached a branch condition */ |
| BS_EXCP = 3, /* We reached an exception condition */ |
| }; |
| |
| static const char * const regnames[] = { |
| "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
| "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", |
| "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
| "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", |
| }; |
| |
| static const char * const regnames_HI[] = { |
| "HI0", "HI1", "HI2", "HI3", |
| }; |
| |
| static const char * const regnames_LO[] = { |
| "LO0", "LO1", "LO2", "LO3", |
| }; |
| |
| static const char * const fregnames[] = { |
| "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
| "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
| "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
| "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
| }; |
| |
| static const char * const msaregnames[] = { |
| "w0.d0", "w0.d1", "w1.d0", "w1.d1", |
| "w2.d0", "w2.d1", "w3.d0", "w3.d1", |
| "w4.d0", "w4.d1", "w5.d0", "w5.d1", |
| "w6.d0", "w6.d1", "w7.d0", "w7.d1", |
| "w8.d0", "w8.d1", "w9.d0", "w9.d1", |
| "w10.d0", "w10.d1", "w11.d0", "w11.d1", |
| "w12.d0", "w12.d1", "w13.d0", "w13.d1", |
| "w14.d0", "w14.d1", "w15.d0", "w15.d1", |
| "w16.d0", "w16.d1", "w17.d0", "w17.d1", |
| "w18.d0", "w18.d1", "w19.d0", "w19.d1", |
| "w20.d0", "w20.d1", "w21.d0", "w21.d1", |
| "w22.d0", "w22.d1", "w23.d0", "w23.d1", |
| "w24.d0", "w24.d1", "w25.d0", "w25.d1", |
| "w26.d0", "w26.d1", "w27.d0", "w27.d1", |
| "w28.d0", "w28.d1", "w29.d0", "w29.d1", |
| "w30.d0", "w30.d1", "w31.d0", "w31.d1", |
| }; |
| |
| #define MIPS_DEBUG(fmt, ...) \ |
| do { \ |
| if (MIPS_DEBUG_DISAS) { \ |
| qemu_log_mask(CPU_LOG_TB_IN_ASM, \ |
| TARGET_FMT_lx ": %08x " fmt "\n", \ |
| ctx->pc, ctx->opcode , ## __VA_ARGS__); \ |
| } \ |
| } while (0) |
| |
| #define LOG_DISAS(...) \ |
| do { \ |
| if (MIPS_DEBUG_DISAS) { \ |
| qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ |
| } \ |
| } while (0) |
| |
| #define MIPS_INVAL(op) \ |
| MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \ |
| ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)) |
| |
| /* General purpose registers moves. */ |
| static inline void gen_load_gpr (TCGv t, int reg) |
| { |
| if (reg == 0) |
| tcg_gen_movi_tl(t, 0); |
| else |
| tcg_gen_mov_tl(t, cpu_gpr[reg]); |
| } |
| |
| static inline void gen_store_gpr (TCGv t, int reg) |
| { |
| if (reg != 0) |
| tcg_gen_mov_tl(cpu_gpr[reg], t); |
| } |
| |
| /* Moves to/from shadow registers. */ |
| static inline void gen_load_srsgpr (int from, int to) |
| { |
| TCGv t0 = tcg_temp_new(); |
| |
| if (from == 0) |
| tcg_gen_movi_tl(t0, 0); |
| else { |
| TCGv_i32 t2 = tcg_temp_new_i32(); |
| TCGv_ptr addr = tcg_temp_new_ptr(); |
| |
| tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUMIPSState, CP0_SRSCtl)); |
| tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS); |
| tcg_gen_andi_i32(t2, t2, 0xf); |
| tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32); |
| tcg_gen_ext_i32_ptr(addr, t2); |
| tcg_gen_add_ptr(addr, cpu_env, addr); |
| |
| tcg_gen_ld_tl(t0, addr, sizeof(target_ulong) * from); |
| tcg_temp_free_ptr(addr); |
| tcg_temp_free_i32(t2); |
| } |
| gen_store_gpr(t0, to); |
| tcg_temp_free(t0); |
| } |
| |
| static inline void gen_store_srsgpr (int from, int to) |
| { |
| if (to != 0) { |
| TCGv t0 = tcg_temp_new(); |
| TCGv_i32 t2 = tcg_temp_new_i32(); |
| TCGv_ptr addr = tcg_temp_new_ptr(); |
| |
| gen_load_gpr(t0, from); |
| tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUMIPSState, CP0_SRSCtl)); |
| tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS); |
| tcg_gen_andi_i32(t2, t2, 0xf); |
| tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32); |
| tcg_gen_ext_i32_ptr(addr, t2); |
| tcg_gen_add_ptr(addr, cpu_env, addr); |
| |
| tcg_gen_st_tl(t0, addr, sizeof(target_ulong) * to); |
| tcg_temp_free_ptr(addr); |
| tcg_temp_free_i32(t2); |
| tcg_temp_free(t0); |
| } |
| } |
| |
| /* Floating point register moves. */ |
| static void gen_load_fpr32(TCGv_i32 t, int reg) |
| { |
| tcg_gen_trunc_i64_i32(t, fpu_f64[reg]); |
| } |
| |
| static void gen_store_fpr32(TCGv_i32 t, int reg) |
| { |
| TCGv_i64 t64 = tcg_temp_new_i64(); |
| tcg_gen_extu_i32_i64(t64, t); |
| tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); |
| tcg_temp_free_i64(t64); |
| } |
| |
| static void gen_load_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) |
| { |
| if (ctx->hflags & MIPS_HFLAG_F64) { |
| TCGv_i64 t64 = tcg_temp_new_i64(); |
| tcg_gen_shri_i64(t64, fpu_f64[reg], 32); |
| tcg_gen_trunc_i64_i32(t, t64); |
| tcg_temp_free_i64(t64); |
| } else { |
| gen_load_fpr32(t, reg | 1); |
| } |
| } |
| |
| static void gen_store_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) |
| { |
| if (ctx->hflags & MIPS_HFLAG_F64) { |
| TCGv_i64 t64 = tcg_temp_new_i64(); |
| tcg_gen_extu_i32_i64(t64, t); |
| tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); |
| tcg_temp_free_i64(t64); |
| } else { |
| gen_store_fpr32(t, reg | 1); |
| } |
| } |
| |
| static void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) |
| { |
| if (ctx->hflags & MIPS_HFLAG_F64) { |
| tcg_gen_mov_i64(t, fpu_f64[reg]); |
| } else { |
| tcg_gen_concat32_i64(t, fpu_f64[reg & ~1], fpu_f64[reg | 1]); |
| } |
| } |
| |
| static void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) |
| { |
| if (ctx->hflags & MIPS_HFLAG_F64) { |
| tcg_gen_mov_i64(fpu_f64[reg], t); |
| } else { |
| TCGv_i64 t0; |
| tcg_gen_deposit_i64(fpu_f64[reg & ~1], fpu_f64[reg & ~1], t, 0, 32); |
| t0 = tcg_temp_new_i64(); |
| tcg_gen_shri_i64(t0, t, 32); |
| tcg_gen_deposit_i64(fpu_f64[reg | 1], fpu_f64[reg | 1], t0, 0, 32); |
| tcg_temp_free_i64(t0); |
| } |
| } |
| |
| static inline int get_fp_bit (int cc) |
| { |
| if (cc) |
| return 24 + cc; |
| else |
| return 23; |
| } |
| |
| /* Tests */ |
| static inline void gen_save_pc(target_ulong pc) |
| { |
| tcg_gen_movi_tl(cpu_PC, pc); |
| } |
| |
| static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) |
| { |
| LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); |
| if (do_save_pc && ctx->pc != ctx->saved_pc) { |
| gen_save_pc(ctx->pc); |
| ctx->saved_pc = ctx->pc; |
| } |
| if (ctx->hflags != ctx->saved_hflags) { |
| tcg_gen_movi_i32(hflags, ctx->hflags); |
| ctx->saved_hflags = ctx->hflags; |
| switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { |
| case MIPS_HFLAG_BR: |
| break; |
| case MIPS_HFLAG_BC: |
| case MIPS_HFLAG_BL: |
| case MIPS_HFLAG_B: |
| tcg_gen_movi_tl(btarget, ctx->btarget); |
| break; |
| } |
| } |
| } |
| |
| static inline void restore_cpu_state (CPUMIPSState *env, DisasContext *ctx) |
| { |
| ctx->saved_hflags = ctx->hflags; |
| switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { |
| case MIPS_HFLAG_BR: |
| break; |
| case MIPS_HFLAG_BC: |
| case MIPS_HFLAG_BL: |
| case MIPS_HFLAG_B: |
| ctx->btarget = env->btarget; |
| break; |
| } |
| } |
| |
| static inline void |
| generate_exception_err (DisasContext *ctx, int excp, int err) |
| { |
| TCGv_i32 texcp = tcg_const_i32(excp); |
| TCGv_i32 terr = tcg_const_i32(err); |
| save_cpu_state(ctx, 1); |
| gen_helper_raise_exception_err(cpu_env, texcp, terr); |
| tcg_temp_free_i32(terr); |
| tcg_temp_free_i32(texcp); |
| } |
| |
| static inline void |
| generate_exception (DisasContext *ctx, int excp) |
| { |
| save_cpu_state(ctx, 1); |
| gen_helper_0e0i(raise_exception, excp); |
| } |
| |
| /* Addresses computation */ |
| static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1) |
| { |
| tcg_gen_add_tl(ret, arg0, arg1); |
| |
| #if defined(TARGET_MIPS64) |
| if (ctx->hflags & MIPS_HFLAG_AWRAP) { |
| tcg_gen_ext32s_i64(ret, ret); |
| } |
| #endif |
| } |
| |
| /* Addresses computation (translation time) */ |
| static target_long addr_add(DisasContext *ctx, target_long base, |
| target_long offset) |
| { |
| target_long sum = base + offset; |
| |
| #if defined(TARGET_MIPS64) |
| if (ctx->hflags & MIPS_HFLAG_AWRAP) { |
| sum = (int32_t)sum; |
| } |
| #endif |
| return sum; |
| } |
| |
| static inline void check_cp0_enabled(DisasContext *ctx) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) |
| generate_exception_err(ctx, EXCP_CpU, 0); |
| } |
| |
| static inline void check_cp1_enabled(DisasContext *ctx) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) |
| generate_exception_err(ctx, EXCP_CpU, 1); |
| } |
| |
| /* Verify that the processor is running with COP1X instructions enabled. |
| This is associated with the nabla symbol in the MIPS32 and MIPS64 |
| opcode tables. */ |
| |
| static inline void check_cop1x(DisasContext *ctx) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) |
| generate_exception(ctx, EXCP_RI); |
| } |
| |
| /* Verify that the processor is running with 64-bit floating-point |
| operations enabled. */ |
| |
| static inline void check_cp1_64bitmode(DisasContext *ctx) |
| { |
| if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) |
| generate_exception(ctx, EXCP_RI); |
| } |
| |
| /* |
| * Verify if floating point register is valid; an operation is not defined |
| * if bit 0 of any register specification is set and the FR bit in the |
| * Status register equals zero, since the register numbers specify an |
| * even-odd pair of adjacent coprocessor general registers. When the FR bit |
| * in the Status register equals one, both even and odd register numbers |
| * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. |
| * |
| * Multiple 64 bit wide registers can be checked by calling |
| * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); |
| */ |
| static inline void check_cp1_registers(DisasContext *ctx, int regs) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) |
| generate_exception(ctx, EXCP_RI); |
| } |
| |
| /* Verify that the processor is running with DSP instructions enabled. |
| This is enabled by CP0 Status register MX(24) bit. |
| */ |
| |
| static inline void check_dsp(DisasContext *ctx) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSP))) { |
| if (ctx->insn_flags & ASE_DSP) { |
| generate_exception(ctx, EXCP_DSPDIS); |
| } else { |
| generate_exception(ctx, EXCP_RI); |
| } |
| } |
| } |
| |
| static inline void check_dspr2(DisasContext *ctx) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSPR2))) { |
| if (ctx->insn_flags & ASE_DSP) { |
| generate_exception(ctx, EXCP_DSPDIS); |
| } else { |
| generate_exception(ctx, EXCP_RI); |
| } |
| } |
| } |
| |
| /* This code generates a "reserved instruction" exception if the |
| CPU does not support the instruction set corresponding to flags. */ |
| static inline void check_insn(DisasContext *ctx, int flags) |
| { |
| if (unlikely(!(ctx->insn_flags & flags))) { |
| generate_exception(ctx, EXCP_RI); |
| } |
| } |
| |
| /* This code generates a "reserved instruction" exception if the |
| CPU has corresponding flag set which indicates that the instruction |
| has been removed. */ |
| static inline void check_insn_opc_removed(DisasContext *ctx, int flags) |
| { |
| if (unlikely(ctx->insn_flags & flags)) { |
| generate_exception(ctx, EXCP_RI); |
| } |
| } |
| |
| #ifdef TARGET_MIPS64 |
| /* This code generates a "reserved instruction" exception if 64-bit |
| instructions are not enabled. */ |
| static inline void check_mips_64(DisasContext *ctx) |
| { |
| if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) |
| generate_exception(ctx, EXCP_RI); |
| } |
| #endif |
| |
| /* Define small wrappers for gen_load_fpr* so that we have a uniform |
| calling interface for 32 and 64-bit FPRs. No sense in changing |
| all callers for gen_load_fpr32 when we need the CTX parameter for |
| this one use. */ |
| #define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y) |
| #define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y) |
| #define FOP_CONDS(type, abs, fmt, ifmt, bits) \ |
| static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \ |
| int ft, int fs, int cc) \ |
| { \ |
| TCGv_i##bits fp0 = tcg_temp_new_i##bits (); \ |
| TCGv_i##bits fp1 = tcg_temp_new_i##bits (); \ |
| switch (ifmt) { \ |
| case FMT_PS: \ |
| check_cp1_64bitmode(ctx); \ |
| break; \ |
| case FMT_D: \ |
| if (abs) { \ |
| check_cop1x(ctx); \ |
| } \ |
| check_cp1_registers(ctx, fs | ft); \ |
| break; \ |
| case FMT_S: \ |
| if (abs) { \ |
| check_cop1x(ctx); \ |
| } \ |
| break; \ |
| } \ |
| gen_ldcmp_fpr##bits (ctx, fp0, fs); \ |
| gen_ldcmp_fpr##bits (ctx, fp1, ft); \ |
| switch (n) { \ |
| case 0: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); break;\ |
| case 1: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); break;\ |
| case 2: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); break;\ |
| case 3: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); break;\ |
| case 4: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); break;\ |
| case 5: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); break;\ |
| case 6: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); break;\ |
| case 7: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); break;\ |
| case 8: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); break;\ |
| case 9: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\ |
| case 10: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); break;\ |
| case 11: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); break;\ |
| case 12: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); break;\ |
| case 13: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); break;\ |
| case 14: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); break;\ |
| case 15: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); break;\ |
| default: abort(); \ |
| } \ |
| tcg_temp_free_i##bits (fp0); \ |
| tcg_temp_free_i##bits (fp1); \ |
| } |
| |
| FOP_CONDS(, 0, d, FMT_D, 64) |
| FOP_CONDS(abs, 1, d, FMT_D, 64) |
| FOP_CONDS(, 0, s, FMT_S, 32) |
| FOP_CONDS(abs, 1, s, FMT_S, 32) |
| FOP_CONDS(, 0, ps, FMT_PS, 64) |
| FOP_CONDS(abs, 1, ps, FMT_PS, 64) |
| #undef FOP_CONDS |
| |
| #define FOP_CONDNS(fmt, ifmt, bits, STORE) \ |
| static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n, \ |
| int ft, int fs, int fd) \ |
| { \ |
| TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ |
| TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ |
| switch (ifmt) { \ |
| case FMT_D: \ |
| check_cp1_registers(ctx, fs | ft | fd); \ |
| break; \ |
| } \ |
| gen_ldcmp_fpr ## bits(ctx, fp0, fs); \ |
| gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ |
| switch (n) { \ |
| case 0: \ |
| gen_helper_r6_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 1: \ |
| gen_helper_r6_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 2: \ |
| gen_helper_r6_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 3: \ |
| gen_helper_r6_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 4: \ |
| gen_helper_r6_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 5: \ |
| gen_helper_r6_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 6: \ |
| gen_helper_r6_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 7: \ |
| gen_helper_r6_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 8: \ |
| gen_helper_r6_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 9: \ |
| gen_helper_r6_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 10: \ |
| gen_helper_r6_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 11: \ |
| gen_helper_r6_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 12: \ |
| gen_helper_r6_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 13: \ |
| gen_helper_r6_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 14: \ |
| gen_helper_r6_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 15: \ |
| gen_helper_r6_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 17: \ |
| gen_helper_r6_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 18: \ |
| gen_helper_r6_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 19: \ |
| gen_helper_r6_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 25: \ |
| gen_helper_r6_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 26: \ |
| gen_helper_r6_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| case 27: \ |
| gen_helper_r6_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1); \ |
| break; \ |
| default: \ |
| abort(); \ |
| } \ |
| STORE; \ |
| tcg_temp_free_i ## bits (fp0); \ |
| tcg_temp_free_i ## bits (fp1); \ |
| } |
| |
| FOP_CONDNS(d, FMT_D, 64, gen_store_fpr64(ctx, fp0, fd)) |
| FOP_CONDNS(s, FMT_S, 32, gen_store_fpr32(fp0, fd)) |
| #undef FOP_CONDNS |
| #undef gen_ldcmp_fpr32 |
| #undef gen_ldcmp_fpr64 |
| |
| /* load/store instructions. */ |
| #ifdef CONFIG_USER_ONLY |
| #define OP_LD_ATOMIC(insn,fname) \ |
| static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ |
| { \ |
| TCGv t0 = tcg_temp_new(); \ |
| tcg_gen_mov_tl(t0, arg1); \ |
| tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ |
| tcg_gen_st_tl(t0, cpu_env, offsetof(CPUMIPSState, lladdr)); \ |
| tcg_gen_st_tl(ret, cpu_env, offsetof(CPUMIPSState, llval)); \ |
| tcg_temp_free(t0); \ |
| } |
| #else |
| #define OP_LD_ATOMIC(insn,fname) \ |
| static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ |
| { \ |
| gen_helper_1e1i(insn, ret, arg1, ctx->mem_idx); \ |
| } |
| #endif |
| OP_LD_ATOMIC(ll,ld32s); |
| #if defined(TARGET_MIPS64) |
| OP_LD_ATOMIC(lld,ld64); |
| #endif |
| #undef OP_LD_ATOMIC |
| |
| #ifdef CONFIG_USER_ONLY |
| #define OP_ST_ATOMIC(insn,fname,ldname,almask) \ |
| static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ |
| { \ |
| TCGv t0 = tcg_temp_new(); \ |
| int l1 = gen_new_label(); \ |
| int l2 = gen_new_label(); \ |
| \ |
| tcg_gen_andi_tl(t0, arg2, almask); \ |
| tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \ |
| tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); \ |
| generate_exception(ctx, EXCP_AdES); \ |
| gen_set_label(l1); \ |
| tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUMIPSState, lladdr)); \ |
| tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ |
| tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \ |
| tcg_gen_st_tl(t0, cpu_env, offsetof(CPUMIPSState, llreg)); \ |
| tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUMIPSState, llnewval)); \ |
| gen_helper_0e0i(raise_exception, EXCP_SC); \ |
| gen_set_label(l2); \ |
| tcg_gen_movi_tl(t0, 0); \ |
| gen_store_gpr(t0, rt); \ |
| tcg_temp_free(t0); \ |
| } |
| #else |
| #define OP_ST_ATOMIC(insn,fname,ldname,almask) \ |
| static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ |
| { \ |
| TCGv t0 = tcg_temp_new(); \ |
| gen_helper_1e2i(insn, t0, arg1, arg2, ctx->mem_idx); \ |
| gen_store_gpr(t0, rt); \ |
| tcg_temp_free(t0); \ |
| } |
| #endif |
| OP_ST_ATOMIC(sc,st32,ld32s,0x3); |
| #if defined(TARGET_MIPS64) |
| OP_ST_ATOMIC(scd,st64,ld64,0x7); |
| #endif |
| #undef OP_ST_ATOMIC |
| |
| static void gen_base_offset_addr (DisasContext *ctx, TCGv addr, |
| int base, int16_t offset) |
| { |
| if (base == 0) { |
| tcg_gen_movi_tl(addr, offset); |
| } else if (offset == 0) { |
| gen_load_gpr(addr, base); |
| } else { |
| tcg_gen_movi_tl(addr, offset); |
| gen_op_addr_add(ctx, addr, cpu_gpr[base], addr); |
| } |
| } |
| |
| static target_ulong pc_relative_pc (DisasContext *ctx) |
| { |
| target_ulong pc = ctx->pc; |
| |
| if (ctx->hflags & MIPS_HFLAG_BMASK) { |
| int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4; |
| |
| pc -= branch_bytes; |
| } |
| |
| pc &= ~(target_ulong)3; |
| return pc; |
| } |
| |
| /* Load */ |
| static void gen_ld(DisasContext *ctx, uint32_t opc, |
| int rt, int base, int16_t offset) |
| { |
| const char *opn = "ld"; |
| TCGv t0, t1, t2; |
| |
| if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) { |
| /* Loongson CPU uses a load to zero register for prefetch. |
| We emulate it as a NOP. On other CPU we must perform the |
| actual memory access. */ |
| MIPS_DEBUG("NOP"); |
| return; |
| } |
| |
| t0 = tcg_temp_new(); |
| gen_base_offset_addr(ctx, t0, base, offset); |
| |
| switch (opc) { |
| #if defined(TARGET_MIPS64) |
| case OPC_LWU: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); |
| gen_store_gpr(t0, rt); |
| opn = "lwu"; |
| break; |
| case OPC_LD: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); |
| gen_store_gpr(t0, rt); |
| opn = "ld"; |
| break; |
| case OPC_LLD: |
| case R6_OPC_LLD: |
| save_cpu_state(ctx, 1); |
| op_ld_lld(t0, t0, ctx); |
| gen_store_gpr(t0, rt); |
| opn = "lld"; |
| break; |
| case OPC_LDL: |
| t1 = tcg_temp_new(); |
| tcg_gen_andi_tl(t1, t0, 7); |
| #ifndef TARGET_WORDS_BIGENDIAN |
| tcg_gen_xori_tl(t1, t1, 7); |
| #endif |
| tcg_gen_shli_tl(t1, t1, 3); |
| tcg_gen_andi_tl(t0, t0, ~7); |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); |
| tcg_gen_shl_tl(t0, t0, t1); |
| tcg_gen_xori_tl(t1, t1, 63); |
| t2 = tcg_const_tl(0x7fffffffffffffffull); |
| tcg_gen_shr_tl(t2, t2, t1); |
| gen_load_gpr(t1, rt); |
| tcg_gen_and_tl(t1, t1, t2); |
| tcg_temp_free(t2); |
| tcg_gen_or_tl(t0, t0, t1); |
| tcg_temp_free(t1); |
| gen_store_gpr(t0, rt); |
| opn = "ldl"; |
| break; |
| case OPC_LDR: |
| t1 = tcg_temp_new(); |
| tcg_gen_andi_tl(t1, t0, 7); |
| #ifdef TARGET_WORDS_BIGENDIAN |
| tcg_gen_xori_tl(t1, t1, 7); |
| #endif |
| tcg_gen_shli_tl(t1, t1, 3); |
| tcg_gen_andi_tl(t0, t0, ~7); |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); |
| tcg_gen_shr_tl(t0, t0, t1); |
| tcg_gen_xori_tl(t1, t1, 63); |
| t2 = tcg_const_tl(0xfffffffffffffffeull); |
| tcg_gen_shl_tl(t2, t2, t1); |
| gen_load_gpr(t1, rt); |
| tcg_gen_and_tl(t1, t1, t2); |
| tcg_temp_free(t2); |
| tcg_gen_or_tl(t0, t0, t1); |
| tcg_temp_free(t1); |
| gen_store_gpr(t0, rt); |
| opn = "ldr"; |
| break; |
| case OPC_LDPC: |
| t1 = tcg_const_tl(pc_relative_pc(ctx)); |
| gen_op_addr_add(ctx, t0, t0, t1); |
| tcg_temp_free(t1); |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); |
| gen_store_gpr(t0, rt); |
| opn = "ldpc"; |
| break; |
| #endif |
| case OPC_LWPC: |
| t1 = tcg_const_tl(pc_relative_pc(ctx)); |
| gen_op_addr_add(ctx, t0, t0, t1); |
| tcg_temp_free(t1); |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); |
| gen_store_gpr(t0, rt); |
| opn = "lwpc"; |
| break; |
| case OPC_LW: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); |
| gen_store_gpr(t0, rt); |
| opn = "lw"; |
| break; |
| case OPC_LH: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW); |
| gen_store_gpr(t0, rt); |
| opn = "lh"; |
| break; |
| case OPC_LHU: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUW); |
| gen_store_gpr(t0, rt); |
| opn = "lhu"; |
| break; |
| case OPC_LB: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB); |
| gen_store_gpr(t0, rt); |
| opn = "lb"; |
| break; |
| case OPC_LBU: |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_UB); |
| gen_store_gpr(t0, rt); |
| opn = "lbu"; |
| break; |
| case OPC_LWL: |
| t1 = tcg_temp_new(); |
| tcg_gen_andi_tl(t1, t0, 3); |
| #ifndef TARGET_WORDS_BIGENDIAN |
| tcg_gen_xori_tl(t1, t1, 3); |
| #endif |
| tcg_gen_shli_tl(t1, t1, 3); |
| tcg_gen_andi_tl(t0, t0, ~3); |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); |
| tcg_gen_shl_tl(t0, t0, t1); |
| tcg_gen_xori_tl(t1, t1, 31); |
| t2 = tcg_const_tl(0x7fffffffull); |
| tcg_gen_shr_tl(t2, t2, t1); |
| gen_load_gpr(t1, rt); |
| tcg_gen_and_tl(t1, t1, t2); |
| tcg_temp_free(t2); |
| tcg_gen_or_tl(t0, t0, t1); |
| tcg_temp_free(t1); |
| tcg_gen_ext32s_tl(t0, t0); |
| gen_store_gpr(t0, rt); |
| opn = "lwl"; |
| break; |
| case OPC_LWR: |
| t1 = tcg_temp_new(); |
| tcg_gen_andi_tl(t1, t0, 3); |
| #ifdef TARGET_WORDS_BIGENDIAN |
| tcg_gen_xori_tl(t1, t1, 3); |
| #endif |
| tcg_gen_shli_tl(t1, t1, 3); |
| tcg_gen_andi_tl(t0, t0, ~3); |
| tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); |
| tcg_gen_shr_tl(t0, t0, t1); |
| tcg_gen_xori_tl(t1, t1, 31); |
| t2 = tcg_const_tl(0xfffffffeull); |
| tcg_gen_shl_tl(t2, t2, t1); |
| gen_load_gpr(t1, rt); |
| tcg_gen_and_tl(t1, t1, t2); |
| tcg_temp_free(t2); |
| tcg_gen_or_tl(t0, t0, t1); |
| tcg_temp_free(t1); |
| tcg_gen_ext32s_tl(t0, t0); |
| gen_store_gpr(t0, rt); |
| opn = "lwr"; |
| break; |
| case OPC_LL: |
| case R6_OPC_LL: |
| save_cpu_state(ctx, 1); |
| op_ld_ll(t0, t0, ctx); |
| gen_store_gpr(t0, rt); |
| opn = "ll"; |
| break; |
| } |
| (void)opn; /* avoid a compiler warning */ |
| MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); |
| tcg_temp_free(t0); |
| } |
| |
| /* Store */ |
| static void gen_st (DisasContext *ctx, uint32_t opc, int rt, |
| int base, int16_t offset) |
| { |
| const char *opn = "st"; |
| TCGv t0 = tcg_temp_new(); |
| TCGv t1 = tcg_temp_new(); |
| |
| gen_base_offset_addr(ctx, t0, base, offset); |
| gen_load_gpr(t1, rt); |
| switch (opc) { |
| #if defined(TARGET_MIPS64) |
| case OPC_SD: |
| tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); |
| opn = "sd"; |
| break; |
| case OPC_SDL: |
| save_cpu_state(ctx, 1); |
| gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx); |
| opn = "sdl"; |
| break; |
| case OPC_SDR: |
| save_cpu_state(ctx, 1); |
| gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx); |
| opn = "sdr"; |
| break; |
| #endif |
| case OPC_SW: |
| tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); |
| opn = "sw"; |
| break; |
| case OPC_SH: |
| tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW); |
| opn = "sh"; |
| break; |
| case OPC_SB: |
| tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_8); |
| opn = "sb"; |
| break; |
| case OPC_SWL: |
| save_cpu_state(ctx, 1); |
| gen_helper_0e2i(swl, t1, t0, ctx->mem_idx); |
| opn = "swl"; |
| break; |
| case OPC_SWR: |
| save_cpu_state(ctx, 1); |
| gen_helper_0e2i(swr, t1, t0, ctx->mem_idx); |
| opn = "swr"; |
| break; |
| } |
| (void)opn; /* avoid a compiler warning */ |
| MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); |
| tcg_temp_free(t0); |
| tcg_temp_free(t1); |
| } |
| |
| |
| /* Store conditional */ |
| static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, |
| int base, int16_t offset) |
| { |
| const char *opn = "st_cond"; |
| TCGv t0, t1; |
| |
| #ifdef CONFIG_USER_ONLY |
| t0 = tcg_temp_local_new(); |
| t1 = tcg_temp_local_new(); |
| #else |
| t0 = tcg_temp_new(); |
| t1 = tcg_temp_new(); |
| #endif |
| gen_base_offset_addr(ctx, t0, base, offset); |
| gen_load_gpr(t1, rt); |
| switch (opc) { |
| #if defined(TARGET_MIPS64) |
| case OPC_SCD: |
| case R6_OPC_SCD: |
| save_cpu_state(ctx, 1); |
| op_st_scd(t1, t0, rt, ctx); |
| opn = "scd"; |
| break; |
| #endif |
| case OPC_SC: |
| case R6_OPC_SC: |
| save_cpu_state(ctx, 1); |
| op_st_sc(t1, t0, rt, ctx); |
| opn = "sc"; |
| break; |
| } |
| (void)opn; /* avoid a compiler warning */ |
| MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); |
| tcg_temp_free(t1); |
| tcg_temp_free(t0); |
| } |
| |
| /* Load and store */ |
| static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, |
| int base, int16_t offset) |
| { |
| const char *opn = "flt_ldst"; |
| TCGv t0 = tcg_temp_new(); |
| |
| gen_base_offset_addr(ctx, t0, base, offset); |
| /* Don't do NOP if destination is zero: we must perform the actual |
| memory access. */ |
| switch (opc) { |
| case OPC_LWC1: |
| { |
| TCGv_i32 fp0 = tcg_temp_new_i32(); |
| tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL); |
| gen_store_fpr32(fp0, ft); |
| tcg_temp_free_i32(fp0); |
| } |
| opn = "lwc1"; |
| break; |
| case OPC_SWC1: |
| { |
| TCGv_i32 fp0 = tcg_temp_new_i32(); |
| gen_load_fpr32(fp0, ft); |
| tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); |
| tcg_temp_free_i32(fp0); |