| // Copyright (c) 2010,2017 ARM Limited |
| // All rights reserved |
| // |
| // The license below extends only to copyright in the software and shall |
| // not be construed as granting a license to any other intellectual |
| // property including but not limited to intellectual property relating |
| // to a hardware implementation of the functionality of the software |
| // licensed hereunder. You may use the software subject to the license |
| // terms below provided that you ensure that this notice is replicated |
| // unmodified and in its entirety in all distributions of the software, |
| // modified or unmodified, in source code or in binary form. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer; |
| // redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution; |
| // neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| // |
| // Authors: Gabe Black |
| |
| def format ArmMiscMedia() {{ |
| decode_block = ''' |
| { |
| const uint32_t op1 = bits(machInst, 22, 20); |
| const uint32_t op2 = bits(machInst, 7, 5); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const IntRegIndex ra = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| if (op1 == 0 && op2 == 0) { |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| if (ra == 0xf) { |
| return new Usad8(machInst, rd, rn, rm); |
| } else { |
| return new Usada8(machInst, rd, rn, rm, ra); |
| } |
| } else if (bits(op2, 1, 0) == 0x2) { |
| const uint32_t lsb = bits(machInst, 11, 7); |
| const uint32_t msb = lsb + bits(machInst, 20, 16); |
| if (bits(op1, 2, 1) == 0x3) { |
| return new Ubfx(machInst, ra, rn, lsb, msb); |
| } else if (bits(op1, 2, 1) == 0x1) { |
| return new Sbfx(machInst, ra, rn, lsb, msb); |
| } |
| } else if (bits(op2, 1, 0) == 0x0 && bits(op1, 2, 1) == 0x2) { |
| const uint32_t lsb = bits(machInst, 11, 7); |
| const uint32_t msb = bits(machInst, 20, 16); |
| if (rn == 0xf) { |
| return new Bfc(machInst, ra, ra, lsb, msb); |
| } else { |
| return new Bfi(machInst, ra, rn, lsb, msb); |
| } |
| } |
| return new Unknown(machInst); |
| } |
| ''' |
| }}; |
| |
| def format ArmDataProcReg() {{ |
| pclr = ''' |
| return new %(className)ssRegPclr(machInst, %(dest)s, |
| %(op1)s, rm, imm5, |
| type); |
| ''' |
| instDecode = ''' |
| case %(opcode)#x: |
| if (immShift) { |
| if (setCc) { |
| if (%(dest)s == INTREG_PC) { |
| %(pclr)s |
| } else { |
| return new %(className)sRegCc(machInst, %(dest)s, |
| %(op1)s, rm, imm5, type); |
| } |
| } else { |
| return new %(className)sReg(machInst, %(dest)s, %(op1)s, |
| rm, imm5, type); |
| } |
| } else { |
| if (setCc) { |
| return new %(className)sRegRegCc(machInst, %(dest)s, |
| %(op1)s, rm, rs, type); |
| } else { |
| return new %(className)sRegReg(machInst, %(dest)s, |
| %(op1)s, rm, rs, type); |
| } |
| } |
| break; |
| ''' |
| |
| def instCode(opcode, mnem, useDest = True, useOp1 = True): |
| global pclr |
| if useDest: |
| dest = "rd" |
| else: |
| dest = "INTREG_ZERO" |
| if useOp1: |
| op1 = "rn" |
| else: |
| op1 = "INTREG_ZERO" |
| global instDecode, pclrCode |
| substDict = { "className": mnem.capitalize(), |
| "opcode": opcode, |
| "dest": dest, |
| "op1": op1 } |
| if useDest: |
| substDict["pclr"] = pclr % substDict |
| else: |
| substDict["pclr"] = "" |
| return instDecode % substDict |
| |
| decode_block = ''' |
| { |
| const bool immShift = (bits(machInst, 4) == 0); |
| const bool setCc = (bits(machInst, 20) == 1); |
| const uint32_t imm5 = bits(machInst, 11, 7); |
| const ArmShiftType type = (ArmShiftType)(uint32_t)bits(machInst, 6, 5); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)RD; |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)RN; |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)RM; |
| const IntRegIndex rs = (IntRegIndex)(uint32_t)RS; |
| switch (OPCODE) { |
| ''' |
| decode_block += instCode(0x0, "and") |
| decode_block += instCode(0x1, "eor") |
| decode_block += instCode(0x2, "sub") |
| decode_block += instCode(0x3, "rsb") |
| decode_block += instCode(0x4, "add") |
| decode_block += instCode(0x5, "adc") |
| decode_block += instCode(0x6, "sbc") |
| decode_block += instCode(0x7, "rsc") |
| decode_block += instCode(0x8, "tst", useDest = False) |
| decode_block += instCode(0x9, "teq", useDest = False) |
| decode_block += instCode(0xa, "cmp", useDest = False) |
| decode_block += instCode(0xb, "cmn", useDest = False) |
| decode_block += instCode(0xc, "orr") |
| decode_block += instCode(0xd, "mov", useOp1 = False) |
| decode_block += instCode(0xe, "bic") |
| decode_block += instCode(0xf, "mvn", useOp1 = False) |
| decode_block += ''' |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format ArmPackUnpackSatReverse() {{ |
| decode_block = ''' |
| { |
| const uint32_t op1 = bits(machInst, 22, 20); |
| const uint32_t a = bits(machInst, 19, 16); |
| const uint32_t op2 = bits(machInst, 7, 5); |
| if (bits(op2, 0) == 0) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const uint32_t satImm = bits(machInst, 20, 16); |
| const uint32_t imm = bits(machInst, 11, 7); |
| const ArmShiftType type = |
| (ArmShiftType)(uint32_t)bits(machInst, 6, 5); |
| if (op1 == 0) { |
| if (type) { |
| return new PkhtbReg(machInst, rd, (IntRegIndex)a, |
| rn, imm, type); |
| } else { |
| return new PkhbtReg(machInst, rd, (IntRegIndex)a, |
| rn, imm, type); |
| } |
| } else if (bits(op1, 2, 1) == 1) { |
| return new Ssat(machInst, rd, satImm + 1, rn, imm, type); |
| } else if (bits(op1, 2, 1) == 3) { |
| return new Usat(machInst, rd, satImm, rn, imm, type); |
| } |
| return new Unknown(machInst); |
| } |
| switch (op1) { |
| case 0x0: |
| { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| if (op2 == 0x3) { |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 11, 10) << 3; |
| if (a == 0xf) { |
| return new Sxtb16(machInst, rd, rotation, rm); |
| } else { |
| return new Sxtab16(machInst, rd, rn, rm, rotation); |
| } |
| } else if (op2 == 0x5) { |
| return new Sel(machInst, rd, rn, rm); |
| } |
| } |
| break; |
| case 0x2: |
| if (op2 == 0x1) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const uint32_t satImm = bits(machInst, 20, 16); |
| return new Ssat16(machInst, rd, satImm + 1, rn); |
| } else if (op2 == 0x3) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 11, 10) << 3; |
| if (a == 0xf) { |
| return new Sxtb(machInst, rd, rotation, rm); |
| } else { |
| return new Sxtab(machInst, rd, rn, rm, rotation); |
| } |
| } |
| break; |
| case 0x3: |
| if (op2 == 0x1) { |
| IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| return new Rev(machInst, rd, rm); |
| } else if (op2 == 0x3) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 11, 10) << 3; |
| if (a == 0xf) { |
| return new Sxth(machInst, rd, rotation, rm); |
| } else { |
| return new Sxtah(machInst, rd, rn, rm, rotation); |
| } |
| } else if (op2 == 0x5) { |
| IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| return new Rev16(machInst, rd, rm); |
| } |
| break; |
| case 0x4: |
| if (op2 == 0x3) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 11, 10) << 3; |
| if (a == 0xf) { |
| return new Uxtb16(machInst, rd, rotation, rm); |
| } else { |
| return new Uxtab16(machInst, rd, rn, rm, rotation); |
| } |
| } |
| break; |
| case 0x6: |
| if (op2 == 0x1) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const uint32_t satImm = bits(machInst, 20, 16); |
| return new Usat16(machInst, rd, satImm, rn); |
| } else if (op2 == 0x3) { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 11, 10) << 3; |
| if (a == 0xf) { |
| return new Uxtb(machInst, rd, rotation, rm); |
| } else { |
| return new Uxtab(machInst, rd, rn, rm, rotation); |
| } |
| } |
| break; |
| case 0x7: |
| { |
| const IntRegIndex rn = |
| (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| if (op2 == 0x1) { |
| return new Rbit(machInst, rd, rm); |
| } else if (op2 == 0x3) { |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 11, 10) << 3; |
| if (a == 0xf) { |
| return new Uxth(machInst, rd, rotation, rm); |
| } else { |
| return new Uxtah(machInst, rd, rn, rm, rotation); |
| } |
| } else if (op2 == 0x5) { |
| return new Revsh(machInst, rd, rm); |
| } |
| } |
| break; |
| } |
| return new Unknown(machInst); |
| } |
| ''' |
| }}; |
| |
| def format ArmParallelAddSubtract() {{ |
| decode_block=''' |
| { |
| const uint32_t op1 = bits(machInst, 21, 20); |
| const uint32_t op2 = bits(machInst, 7, 5); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| if (bits(machInst, 22) == 0) { |
| switch (op1) { |
| case 0x1: |
| switch (op2) { |
| case 0x0: |
| return new Sadd16RegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x1: |
| return new SasxRegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new SsaxRegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x3: |
| return new Ssub16RegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Sadd8RegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x7: |
| return new Ssub8RegCc(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| case 0x2: |
| switch (op2) { |
| case 0x0: |
| return new Qadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x1: |
| return new QasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new QsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x3: |
| return new Qsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Qadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x7: |
| return new Qsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| case 0x3: |
| switch (op2) { |
| case 0x0: |
| return new Shadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x1: |
| return new ShasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new ShsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x3: |
| return new Shsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Shadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x7: |
| return new Shsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| } |
| } else { |
| switch (op1) { |
| case 0x1: |
| switch (op2) { |
| case 0x0: |
| return new Uadd16RegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x1: |
| return new UasxRegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new UsaxRegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x3: |
| return new Usub16RegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Uadd8RegCc(machInst, rd, rn, rm, 0, LSL); |
| case 0x7: |
| return new Usub8RegCc(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| case 0x2: |
| switch (op2) { |
| case 0x0: |
| return new Uqadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x1: |
| return new UqasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new UqsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x3: |
| return new Uqsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Uqadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x7: |
| return new Uqsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| case 0x3: |
| switch (op2) { |
| case 0x0: |
| return new Uhadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x1: |
| return new UhasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new UhsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x3: |
| return new Uhsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Uhadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x7: |
| return new Uhsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| } |
| } |
| return new Unknown(machInst); |
| } |
| ''' |
| }}; |
| |
| def format ArmDataProcImm() {{ |
| pclr = ''' |
| return new %(className)ssImmPclr(machInst, %(dest)s, |
| %(op1)s, imm, false); |
| ''' |
| adr = ''' |
| return new AdrImm(machInst, %(dest)s, %(add)s, |
| imm, false); |
| ''' |
| instDecode = ''' |
| case %(opcode)#x: |
| if (setCc) { |
| if (%(pclrInst)s && %(dest)s == INTREG_PC) { |
| %(pclr)s |
| } else { |
| return new %(className)sImmCc(machInst, %(dest)s, %(op1)s, |
| imm, rotC); |
| } |
| } else { |
| if (%(adrInst)s && %(op1)s == INTREG_PC) { |
| %(adr)s |
| } else { |
| return new %(className)sImm(machInst, %(dest)s, %(op1)s, |
| imm, rotC); |
| } |
| } |
| break; |
| ''' |
| |
| def instCode(opcode, mnem, useDest = True, useOp1 = True): |
| global instDecode, pclr, adr |
| if useDest: |
| dest = "rd" |
| else: |
| dest = "INTREG_ZERO" |
| if useOp1: |
| op1 = "rn" |
| else: |
| op1 = "INTREG_ZERO" |
| substDict = { "className": mnem.capitalize(), |
| "opcode": opcode, |
| "dest": dest, |
| "op1": op1, |
| "adr": "", |
| "adrInst": "false" } |
| if useDest: |
| substDict["pclrInst"] = "true" |
| substDict["pclr"] = pclr % substDict |
| else: |
| substDict["pclrInst"] = "false" |
| substDict["pclr"] = "" |
| return instDecode % substDict |
| |
| def adrCode(opcode, mnem, add="1"): |
| global instDecode, pclr, adr |
| substDict = { "className": mnem.capitalize(), |
| "opcode": opcode, |
| "dest": "rd", |
| "op1": "rn", |
| "add": add, |
| "pclrInst": "true", |
| "adrInst": "true" } |
| substDict["pclr"] = pclr % substDict |
| substDict["adr"] = adr % substDict |
| return instDecode % substDict |
| |
| decode_block = ''' |
| { |
| const bool setCc = (bits(machInst, 20) == 1); |
| const uint32_t unrotated = bits(machInst, 7, 0); |
| const uint32_t rotation = (bits(machInst, 11, 8) << 1); |
| const bool rotC = (rotation != 0); |
| const uint32_t imm = rotate_imm(unrotated, rotation); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)RD; |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)RN; |
| switch (OPCODE) { |
| ''' |
| decode_block += instCode(0x0, "and") |
| decode_block += instCode(0x1, "eor") |
| decode_block += adrCode(0x2, "sub", add="(IntRegIndex)0") |
| decode_block += instCode(0x3, "rsb") |
| decode_block += adrCode(0x4, "add", add="(IntRegIndex)1") |
| decode_block += instCode(0x5, "adc") |
| decode_block += instCode(0x6, "sbc") |
| decode_block += instCode(0x7, "rsc") |
| decode_block += instCode(0x8, "tst", useDest = False) |
| decode_block += instCode(0x9, "teq", useDest = False) |
| decode_block += instCode(0xa, "cmp", useDest = False) |
| decode_block += instCode(0xb, "cmn", useDest = False) |
| decode_block += instCode(0xc, "orr") |
| decode_block += instCode(0xd, "mov", useOp1 = False) |
| decode_block += instCode(0xe, "bic") |
| decode_block += instCode(0xf, "mvn", useOp1 = False) |
| decode_block += ''' |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format ArmSatAddSub() {{ |
| decode_block = ''' |
| { |
| IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| switch (OPCODE) { |
| case 0x8: |
| return new QaddRegCc(machInst, rd, rm, rn, 0, LSL); |
| case 0x9: |
| return new QsubRegCc(machInst, rd, rm, rn, 0, LSL); |
| case 0xa: |
| return new QdaddRegCc(machInst, rd, rm, rn, 0, LSL); |
| case 0xb: |
| return new QdsubRegCc(machInst, rd, rm, rn, 0, LSL); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb32DataProcReg() {{ |
| decode_block = ''' |
| { |
| const uint32_t op1 = bits(machInst, 23, 20); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const uint32_t op2 = bits(machInst, 7, 4); |
| if (bits(machInst, 15, 12) != 0xf) { |
| return new Unknown(machInst); |
| } |
| if (bits(op1, 3) != 1) { |
| if (op2 == 0) { |
| IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| switch (bits(op1, 2, 0)) { |
| case 0x0: |
| return new MovRegReg(machInst, rd, |
| INTREG_ZERO, rn, rm, LSL); |
| case 0x1: |
| return new MovRegRegCc(machInst, rd, |
| INTREG_ZERO, rn, rm, LSL); |
| case 0x2: |
| return new MovRegReg(machInst, rd, |
| INTREG_ZERO, rn, rm, LSR); |
| case 0x3: |
| return new MovRegRegCc(machInst, rd, |
| INTREG_ZERO, rn, rm, LSR); |
| case 0x4: |
| return new MovRegReg(machInst, rd, |
| INTREG_ZERO, rn, rm, ASR); |
| case 0x5: |
| return new MovRegRegCc(machInst, rd, |
| INTREG_ZERO, rn, rm, ASR); |
| case 0x6: |
| return new MovRegReg(machInst, rd, |
| INTREG_ZERO, rn, rm, ROR); |
| case 0x7: |
| return new MovRegRegCc(machInst, rd, |
| INTREG_ZERO, rn, rm, ROR); |
| } |
| } else if (bits(op2, 3) == 0) { |
| return new Unknown(machInst); |
| } else { |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const uint32_t rotation = |
| (uint32_t)bits(machInst, 5, 4) << 3; |
| switch (bits(op1, 2, 0)) { |
| case 0x0: |
| if (rn == 0xf) { |
| return new Sxth(machInst, rd, rotation, rm); |
| } else { |
| return new Sxtah(machInst, rd, rn, rm, rotation); |
| } |
| case 0x1: |
| if (rn == 0xf) { |
| return new Uxth(machInst, rd, rotation, rm); |
| } else { |
| return new Uxtah(machInst, rd, rn, rm, rotation); |
| } |
| case 0x2: |
| if (rn == 0xf) { |
| return new Sxtb16(machInst, rd, rotation, rm); |
| } else { |
| return new Sxtab16(machInst, rd, rn, rm, rotation); |
| } |
| case 0x3: |
| if (rn == 0xf) { |
| return new Uxtb16(machInst, rd, rotation, rm); |
| } else { |
| return new Uxtab16(machInst, rd, rn, rm, rotation); |
| } |
| case 0x4: |
| if (rn == 0xf) { |
| return new Sxtb(machInst, rd, rotation, rm); |
| } else { |
| return new Sxtab(machInst, rd, rn, rm, rotation); |
| } |
| case 0x5: |
| if (rn == 0xf) { |
| return new Uxtb(machInst, rd, rotation, rm); |
| } else { |
| return new Uxtab(machInst, rd, rn, rm, rotation); |
| } |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } else { |
| if (bits(op2, 3) == 0) { |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| if (bits(op2, 2) == 0x0) { |
| const uint32_t op1 = bits(machInst, 22, 20); |
| const uint32_t op2 = bits(machInst, 5, 4); |
| switch (op2) { |
| case 0x0: |
| switch (op1) { |
| case 0x1: |
| return new Sadd16RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x2: |
| return new SasxRegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x6: |
| return new SsaxRegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x5: |
| return new Ssub16RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x0: |
| return new Sadd8RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x4: |
| return new Ssub8RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| } |
| break; |
| case 0x1: |
| switch (op1) { |
| case 0x1: |
| return new Qadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new QasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x6: |
| return new QsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x5: |
| return new Qsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x0: |
| return new Qadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Qsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| case 0x2: |
| switch (op1) { |
| case 0x1: |
| return new Shadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new ShasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x6: |
| return new ShsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x5: |
| return new Shsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x0: |
| return new Shadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Shsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| } |
| } else { |
| const uint32_t op1 = bits(machInst, 22, 20); |
| const uint32_t op2 = bits(machInst, 5, 4); |
| switch (op2) { |
| case 0x0: |
| switch (op1) { |
| case 0x1: |
| return new Uadd16RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x2: |
| return new UasxRegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x6: |
| return new UsaxRegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x5: |
| return new Usub16RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x0: |
| return new Uadd8RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| case 0x4: |
| return new Usub8RegCc(machInst, rd, |
| rn, rm, 0, LSL); |
| } |
| break; |
| case 0x1: |
| switch (op1) { |
| case 0x1: |
| return new Uqadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new UqasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x6: |
| return new UqsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x5: |
| return new Uqsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x0: |
| return new Uqadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Uqsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| case 0x2: |
| switch (op1) { |
| case 0x1: |
| return new Uhadd16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x2: |
| return new UhasxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x6: |
| return new UhsaxReg(machInst, rd, rn, rm, 0, LSL); |
| case 0x5: |
| return new Uhsub16Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x0: |
| return new Uhadd8Reg(machInst, rd, rn, rm, 0, LSL); |
| case 0x4: |
| return new Uhsub8Reg(machInst, rd, rn, rm, 0, LSL); |
| } |
| break; |
| } |
| } |
| } else if (bits(op1, 3, 2) == 0x2 && bits(op2, 3, 2) == 0x2) { |
| const uint32_t op1 = bits(machInst, 22, 20); |
| const uint32_t op2 = bits(machInst, 5, 4); |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| switch (op1) { |
| case 0x0: |
| switch (op2) { |
| case 0x0: |
| return new QaddRegCc(machInst, rd, |
| rm, rn, 0, LSL); |
| case 0x1: |
| return new QdaddRegCc(machInst, rd, |
| rm, rn, 0, LSL); |
| case 0x2: |
| return new QsubRegCc(machInst, rd, |
| rm, rn, 0, LSL); |
| case 0x3: |
| return new QdsubRegCc(machInst, rd, |
| rm, rn, 0, LSL); |
| } |
| break; |
| case 0x1: |
| switch (op2) { |
| case 0x0: |
| return new Rev(machInst, rd, rn); |
| case 0x1: |
| return new Rev16(machInst, rd, rn); |
| case 0x2: |
| return new Rbit(machInst, rd, rm); |
| case 0x3: |
| return new Revsh(machInst, rd, rn); |
| } |
| break; |
| case 0x2: |
| if (op2 == 0) { |
| return new Sel(machInst, rd, rn, rm); |
| } |
| break; |
| case 0x3: |
| if (op2 == 0) { |
| return new Clz(machInst, rd, rm); |
| } |
| break; |
| case 0x4: |
| switch (op2) { |
| case 0x0: |
| return new Crc32b(machInst, rd, rn, rm); |
| case 0x1: |
| return new Crc32h(machInst, rd, rn, rm); |
| case 0x2: |
| return new Crc32w(machInst, rd, rn, rm); |
| } |
| break; |
| case 0x5: |
| switch (op2) { |
| case 0x0: |
| return new Crc32cb(machInst, rd, rn, rm); |
| case 0x1: |
| return new Crc32ch(machInst, rd, rn, rm); |
| case 0x2: |
| return new Crc32cw(machInst, rd, rn, rm); |
| } |
| break; |
| } |
| } |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb16ShiftAddSubMoveCmp() {{ |
| decode_block = ''' |
| { |
| const uint32_t imm5 = bits(machInst, 10, 6); |
| const uint32_t imm3 = bits(machInst, 8, 6); |
| const uint32_t imm8 = bits(machInst, 7, 0); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 2, 0); |
| const IntRegIndex rd8 = (IntRegIndex)(uint32_t)bits(machInst, 10, 8); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 5, 3); |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 8, 6); |
| switch (bits(machInst, 13, 11)) { |
| case 0x0: // lsl |
| if (machInst.itstateMask) { |
| return new MovReg(machInst, rd, INTREG_ZERO, rn, imm5, LSL); |
| } else { |
| return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSL); |
| } |
| case 0x1: // lsr |
| if (machInst.itstateMask) { |
| return new MovReg(machInst, rd, INTREG_ZERO, rn, imm5, LSR); |
| } else { |
| return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSR); |
| } |
| case 0x2: // asr |
| if (machInst.itstateMask) { |
| return new MovReg(machInst, rd, INTREG_ZERO, rn, imm5, ASR); |
| } else { |
| return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, ASR); |
| } |
| case 0x3: |
| switch (bits(machInst, 10, 9)) { |
| case 0x0: |
| if (machInst.itstateMask) { |
| return new AddReg(machInst, rd, rn, rm, 0, LSL); |
| } else { |
| return new AddRegCc(machInst, rd, rn, rm, 0, LSL); |
| } |
| case 0x1: |
| if (machInst.itstateMask) { |
| return new SubReg(machInst, rd, rn, rm, 0, LSL); |
| } else { |
| return new SubRegCc(machInst, rd, rn, rm, 0, LSL); |
| } |
| case 0x2: |
| if (machInst.itstateMask) { |
| return new AddImm(machInst, rd, rn, imm3, true); |
| } else { |
| return new AddImmCc(machInst, rd, rn, imm3, true); |
| } |
| case 0x3: |
| if (machInst.itstateMask) { |
| return new SubImm(machInst, rd, rn, imm3, true); |
| } else { |
| return new SubImmCc(machInst, rd, rn, imm3, true); |
| } |
| } |
| case 0x4: |
| if (machInst.itstateMask) { |
| return new MovImm(machInst, rd8, INTREG_ZERO, imm8, false); |
| } else { |
| return new MovImmCc(machInst, rd8, INTREG_ZERO, imm8, false); |
| } |
| case 0x5: |
| return new CmpImmCc(machInst, INTREG_ZERO, rd8, imm8, true); |
| case 0x6: |
| if (machInst.itstateMask) { |
| return new AddImm(machInst, rd8, rd8, imm8, true); |
| } else { |
| return new AddImmCc(machInst, rd8, rd8, imm8, true); |
| } |
| case 0x7: |
| if (machInst.itstateMask) { |
| return new SubImm(machInst, rd8, rd8, imm8, true); |
| } else { |
| return new SubImmCc(machInst, rd8, rd8, imm8, true); |
| } |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb16DataProcessing() {{ |
| decode_block = ''' |
| { |
| const IntRegIndex rdn = (IntRegIndex)(uint32_t)bits(machInst, 2, 0); |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 5, 3); |
| switch (bits(machInst, 9, 6)) { |
| case 0x0: |
| if (machInst.itstateMask) { |
| return new AndReg(machInst, rdn, rdn, rm, 0, LSL); |
| } else { |
| return new AndRegCc(machInst, rdn, rdn, rm, 0, LSL); |
| } |
| case 0x1: |
| if (machInst.itstateMask) { |
| return new EorReg(machInst, rdn, rdn, rm, 0, LSL); |
| } else { |
| return new EorRegCc(machInst, rdn, rdn, rm, 0, LSL); |
| } |
| case 0x2: //lsl |
| if (machInst.itstateMask) { |
| return new MovRegReg(machInst, rdn, |
| INTREG_ZERO, rdn, rm, LSL); |
| } else { |
| return new MovRegRegCc(machInst, rdn, |
| INTREG_ZERO, rdn, rm, LSL); |
| } |
| case 0x3: //lsr |
| if (machInst.itstateMask) { |
| return new MovRegReg(machInst, rdn, |
| INTREG_ZERO, rdn, rm, LSR); |
| } else { |
| return new MovRegRegCc(machInst, rdn, |
| INTREG_ZERO, rdn, rm, LSR); |
| } |
| case 0x4: //asr |
| if (machInst.itstateMask) { |
| return new MovRegReg(machInst, rdn, |
| INTREG_ZERO, rdn, rm, ASR); |
| } else { |
| return new MovRegRegCc(machInst, rdn, |
| INTREG_ZERO, rdn, rm, ASR); |
| } |
| case 0x5: |
| if (machInst.itstateMask) { |
| return new AdcReg(machInst, rdn, rdn, rm, 0, LSL); |
| } else { |
| return new AdcRegCc(machInst, rdn, rdn, rm, 0, LSL); |
| } |
| case 0x6: |
| if (machInst.itstateMask) { |
| return new SbcReg(machInst, rdn, rdn, rm, 0, LSL); |
| } else { |
| return new SbcRegCc(machInst, rdn, rdn, rm, 0, LSL); |
| } |
| case 0x7: // ror |
| if (machInst.itstateMask) { |
| return new MovRegReg(machInst, rdn, |
| INTREG_ZERO, rdn, rm, ROR); |
| } else { |
| return new MovRegRegCc(machInst, rdn, |
| INTREG_ZERO, rdn, rm, ROR); |
| } |
| case 0x8: |
| return new TstRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); |
| case 0x9: |
| if (machInst.itstateMask) { |
| return new RsbImm(machInst, rdn, rm, 0, true); |
| } else { |
| return new RsbImmCc(machInst, rdn, rm, 0, true); |
| } |
| case 0xa: |
| return new CmpRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); |
| case 0xb: |
| return new CmnRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); |
| case 0xc: |
| if (machInst.itstateMask) { |
| return new OrrReg(machInst, rdn, rdn, rm, 0, LSL); |
| } else { |
| return new OrrRegCc(machInst, rdn, rdn, rm, 0, LSL); |
| } |
| case 0xd: |
| if (machInst.itstateMask) { |
| return new Mul(machInst, rdn, rm, rdn); |
| } else { |
| return new MulCc(machInst, rdn, rm, rdn); |
| } |
| case 0xe: |
| if (machInst.itstateMask) { |
| return new BicReg(machInst, rdn, rdn, rm, 0, LSL); |
| } else { |
| return new BicRegCc(machInst, rdn, rdn, rm, 0, LSL); |
| } |
| case 0xf: |
| if (machInst.itstateMask) { |
| return new MvnReg(machInst, rdn, INTREG_ZERO, rm, 0, LSL); |
| } else { |
| return new MvnRegCc(machInst, rdn, INTREG_ZERO, rm, 0, LSL); |
| } |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb16SpecDataAndBx() {{ |
| decode_block = ''' |
| { |
| const IntRegIndex rdn = |
| (IntRegIndex)(uint32_t)(bits(machInst, 2, 0) | |
| (bits(machInst, 7) << 3)); |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 6, 3); |
| switch (bits(machInst, 9, 8)) { |
| case 0x0: |
| return new AddReg(machInst, rdn, rdn, rm, 0, LSL); |
| case 0x1: |
| return new CmpRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); |
| case 0x2: |
| return new MovReg(machInst, rdn, INTREG_ZERO, rm, 0, LSL); |
| case 0x3: |
| if (bits(machInst, 7) == 0) { |
| return new BxReg(machInst, |
| (IntRegIndex)(uint32_t)bits(machInst, 6, 3), |
| COND_UC); |
| } else { |
| return new BlxReg(machInst, |
| (IntRegIndex)(uint32_t)bits(machInst, 6, 3), |
| COND_UC); |
| } |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb16Adr() {{ |
| decode_block = ''' |
| { |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 10, 8); |
| const uint32_t imm8 = bits(machInst, 7, 0) << 2; |
| return new AdrImm(machInst, rd, (IntRegIndex)1, imm8, false); |
| } |
| ''' |
| }}; |
| |
| def format Thumb16AddSp() {{ |
| decode_block = ''' |
| { |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 10, 8); |
| const uint32_t imm8 = bits(machInst, 7, 0) << 2; |
| return new AddImm(machInst, rd, INTREG_SP, imm8, true); |
| } |
| ''' |
| }}; |
| |
| def format ArmMisc() {{ |
| decode_block = ''' |
| { |
| const uint32_t unrotated = bits(machInst, 7, 0); |
| const uint32_t rotation = (bits(machInst, 11, 8) << 1); |
| const uint32_t imm = rotate_imm(unrotated, rotation); |
| const uint8_t byteMask = bits(machInst, 19, 16); |
| switch (OPCODE) { |
| case 0x8: |
| return new MovImm(machInst, (IntRegIndex)(uint32_t)RD, |
| (IntRegIndex)INTREG_ZERO, |
| bits(machInst, 11, 0) | (bits(machInst, 19, 16) << 12), |
| false); |
| case 0x9: |
| if (RN == 0) { |
| switch (IMM) { |
| case 0x0: |
| return new NopInst(machInst); |
| case 0x1: |
| return new YieldInst(machInst); |
| case 0x2: |
| return new WfeInst(machInst); |
| case 0x3: |
| return new WfiInst(machInst); |
| case 0x4: |
| return new SevInst(machInst); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| return new MsrCpsrImm(machInst, imm, byteMask); |
| } |
| case 0xa: |
| { |
| const uint32_t timm = (bits(machInst, 19, 16) << 12) | |
| bits(machInst, 11, 0); |
| return new MovtImm(machInst, (IntRegIndex)(uint32_t)RD, |
| (IntRegIndex)(uint32_t)RD, timm, true); |
| } |
| case 0xb: |
| return new MsrSpsrImm(machInst, imm, byteMask); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb16Misc() {{ |
| decode_block = ''' |
| { |
| switch (bits(machInst, 11, 8)) { |
| case 0x0: |
| if (bits(machInst, 7)) { |
| return new SubImm(machInst, INTREG_SP, INTREG_SP, |
| bits(machInst, 6, 0) << 2, true); |
| } else { |
| return new AddImm(machInst, INTREG_SP, INTREG_SP, |
| bits(machInst, 6, 0) << 2, true); |
| } |
| case 0x2: |
| { |
| const IntRegIndex rd = |
| (IntRegIndex)(uint32_t)bits(machInst, 2, 0); |
| const IntRegIndex rm = |
| (IntRegIndex)(uint32_t)bits(machInst, 5, 3); |
| switch (bits(machInst, 7, 6)) { |
| case 0x0: |
| return new Sxth(machInst, rd, 0, rm); |
| case 0x1: |
| return new Sxtb(machInst, rd, 0, rm); |
| case 0x2: |
| return new Uxth(machInst, rd, 0, rm); |
| case 0x3: |
| return new Uxtb(machInst, rd, 0, rm); |
| } |
| } |
| case 0x1: |
| case 0x3: |
| return new Cbz(machInst, |
| (bits(machInst, 9) << 6) | |
| (bits(machInst, 7, 3) << 1), |
| (IntRegIndex)(uint32_t)bits(machInst, 2, 0)); |
| case 0x4: |
| case 0x5: |
| { |
| const uint32_t m = bits(machInst, 8); |
| const uint32_t regList = bits(machInst, 7, 0) | (m << 14); |
| return new LdmStm(machInst, INTREG_SP, false, false, false, |
| true, false, regList); |
| } |
| case 0x6: |
| { |
| const uint32_t opBits = bits(machInst, 7, 5); |
| if (opBits == 2) { |
| return new Setend(machInst, bits(machInst, 3)); |
| } else if (opBits == 3) { |
| const bool enable = (bits(machInst, 4) == 0); |
| const uint32_t mods = (bits(machInst, 2, 0) << 5) | |
| ((enable ? 1 : 0) << 9); |
| return new Cps(machInst, mods); |
| } |
| } |
| case 0xa: |
| { |
| IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 2, 0); |
| IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 5, 3); |
| switch (bits(machInst, 7, 6)) { |
| case 0x0: |
| return new Rev(machInst, rd, rm); |
| case 0x1: |
| return new Rev16(machInst, rd, rm); |
| case 0x3: |
| return new Revsh(machInst, rd, rm); |
| default: |
| break; |
| } |
| } |
| break; |
| case 0x9: |
| case 0xb: |
| return new Cbnz(machInst, |
| (bits(machInst, 9) << 6) | |
| (bits(machInst, 7, 3) << 1), |
| (IntRegIndex)(uint32_t)bits(machInst, 2, 0)); |
| case 0xc: |
| case 0xd: |
| { |
| const uint32_t p = bits(machInst, 8); |
| const uint32_t regList = bits(machInst, 7, 0) | (p << 15); |
| return new LdmStm(machInst, INTREG_SP, true, true, false, |
| true, true, regList); |
| } |
| case 0xe: |
| return new BkptInst(machInst); |
| case 0xf: |
| if (bits(machInst, 3, 0) != 0) |
| return new ItInst(machInst); |
| switch (bits(machInst, 7, 4)) { |
| case 0x0: |
| return new NopInst(machInst); |
| case 0x1: |
| return new YieldInst(machInst); |
| case 0x2: |
| return new WfeInst(machInst); |
| case 0x3: |
| return new WfiInst(machInst); |
| case 0x4: |
| return new SevInst(machInst); |
| default: |
| return new WarnUnimplemented("unallocated_hint", machInst); |
| } |
| default: |
| break; |
| } |
| return new Unknown(machInst); |
| } |
| ''' |
| }}; |
| |
| def format Thumb32DataProcModImm() {{ |
| |
| def decInst(mnem, dest="rd", op1="rn"): |
| return ''' |
| if (s) { |
| return new %(mnem)sImmCc(machInst, %(dest)s, |
| %(op1)s, imm, rotC); |
| } else { |
| return new %(mnem)sImm(machInst, %(dest)s, |
| %(op1)s, imm, rotC); |
| } |
| ''' % {"mnem" : mnem, "dest" : dest, "op1" : op1} |
| |
| decode_block = ''' |
| { |
| const uint32_t op = bits(machInst, 24, 21); |
| const bool s = (bits(machInst, 20) == 1); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| const uint32_t ctrlImm = bits(machInst.instBits, 26) << 3 | |
| bits(machInst, 14, 12); |
| const bool rotC = ctrlImm > 3; |
| const uint32_t dataImm = bits(machInst, 7, 0); |
| const uint32_t imm = modified_imm(ctrlImm, dataImm); |
| switch (op) { |
| case 0x0: |
| if (rd == INTREG_PC) { |
| %(tst)s |
| } else { |
| %(and)s |
| } |
| case 0x1: |
| %(bic)s |
| case 0x2: |
| if (rn == INTREG_PC) { |
| %(mov)s |
| } else { |
| %(orr)s |
| } |
| case 0x3: |
| if (rn == INTREG_PC) { |
| %(mvn)s |
| } else { |
| %(orn)s |
| } |
| case 0x4: |
| if (rd == INTREG_PC) { |
| %(teq)s |
| } else { |
| %(eor)s |
| } |
| case 0x8: |
| if (rd == INTREG_PC) { |
| %(cmn)s |
| } else { |
| %(add)s |
| } |
| case 0xa: |
| %(adc)s |
| case 0xb: |
| %(sbc)s |
| case 0xd: |
| if (rd == INTREG_PC) { |
| %(cmp)s |
| } else { |
| %(sub)s |
| } |
| case 0xe: |
| %(rsb)s |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' % { |
| "tst" : decInst("Tst", "INTREG_ZERO"), |
| "and" : decInst("And"), |
| "bic" : decInst("Bic"), |
| "mov" : decInst("Mov", op1="INTREG_ZERO"), |
| "orr" : decInst("Orr"), |
| "mvn" : decInst("Mvn", op1="INTREG_ZERO"), |
| "orn" : decInst("Orn"), |
| "teq" : decInst("Teq", dest="INTREG_ZERO"), |
| "eor" : decInst("Eor"), |
| "cmn" : decInst("Cmn", dest="INTREG_ZERO"), |
| "add" : decInst("Add"), |
| "adc" : decInst("Adc"), |
| "sbc" : decInst("Sbc"), |
| "cmp" : decInst("Cmp", dest="INTREG_ZERO"), |
| "sub" : decInst("Sub"), |
| "rsb" : decInst("Rsb") |
| } |
| }}; |
| |
| def format Thumb32DataProcPlainBin() {{ |
| decode_block = ''' |
| { |
| const uint32_t op = bits(machInst, 24, 20); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| switch (op) { |
| case 0x0: |
| { |
| const uint32_t imm = bits(machInst, 7, 0) | |
| (bits(machInst, 14, 12) << 8) | |
| (bits(machInst, 26) << 11); |
| if (rn == 0xf) { |
| return new AdrImm(machInst, rd, (IntRegIndex)1, |
| imm, false); |
| } else { |
| return new AddImm(machInst, rd, rn, imm, true); |
| } |
| } |
| case 0x4: |
| { |
| const uint32_t imm = bits(machInst, 7, 0) | |
| (bits(machInst, 14, 12) << 8) | |
| (bits(machInst, 26) << 11) | |
| (bits(machInst, 19, 16) << 12); |
| return new MovImm(machInst, rd, INTREG_ZERO, imm, true); |
| } |
| case 0xa: |
| { |
| const uint32_t imm = bits(machInst, 7, 0) | |
| (bits(machInst, 14, 12) << 8) | |
| (bits(machInst, 26) << 11); |
| if (rn == 0xf) { |
| return new AdrImm(machInst, rd, (IntRegIndex)0, |
| imm, false); |
| } else { |
| return new SubImm(machInst, rd, rn, imm, true); |
| } |
| } |
| case 0xc: |
| { |
| const uint32_t imm = bits(machInst, 7, 0) | |
| (bits(machInst, 14, 12) << 8) | |
| (bits(machInst, 26) << 11) | |
| (bits(machInst, 19, 16) << 12); |
| return new MovtImm(machInst, rd, rd, imm, true); |
| } |
| case 0x12: |
| if (!(bits(machInst, 14, 12) || bits(machInst, 7, 6))) { |
| const uint32_t satImm = bits(machInst, 4, 0); |
| return new Ssat16(machInst, rd, satImm + 1, rn); |
| } |
| // Fall through on purpose... |
| case 0x10: |
| { |
| const uint32_t satImm = bits(machInst, 4, 0); |
| const uint32_t imm = bits(machInst, 7, 6) | |
| (bits(machInst, 14, 12) << 2); |
| const ArmShiftType type = |
| (ArmShiftType)(uint32_t)bits(machInst, 21, 20); |
| return new Ssat(machInst, rd, satImm + 1, rn, imm, type); |
| } |
| case 0x14: |
| { |
| const uint32_t lsb = bits(machInst, 7, 6) | |
| (bits(machInst, 14, 12) << 2); |
| const uint32_t msb = lsb + bits(machInst, 4, 0); |
| return new Sbfx(machInst, rd, rn, lsb, msb); |
| } |
| case 0x16: |
| { |
| const uint32_t lsb = bits(machInst, 7, 6) | |
| (bits(machInst, 14, 12) << 2); |
| const uint32_t msb = bits(machInst, 4, 0); |
| if (rn == 0xf) { |
| return new Bfc(machInst, rd, rd, lsb, msb); |
| } else { |
| return new Bfi(machInst, rd, rn, lsb, msb); |
| } |
| } |
| case 0x1a: |
| if (!(bits(machInst, 14, 12) || bits(machInst, 7, 6))) { |
| const uint32_t satImm = bits(machInst, 4, 0); |
| return new Usat16(machInst, rd, satImm, rn); |
| } |
| // Fall through on purpose... |
| case 0x18: |
| { |
| const uint32_t satImm = bits(machInst, 4, 0); |
| const uint32_t imm = bits(machInst, 7, 6) | |
| (bits(machInst, 14, 12) << 2); |
| const ArmShiftType type = |
| (ArmShiftType)(uint32_t)bits(machInst, 21, 20); |
| return new Usat(machInst, rd, satImm, rn, imm, type); |
| } |
| case 0x1c: |
| { |
| const uint32_t lsb = bits(machInst, 7, 6) | |
| (bits(machInst, 14, 12) << 2); |
| const uint32_t msb = lsb + bits(machInst, 4, 0); |
| return new Ubfx(machInst, rd, rn, lsb, msb); |
| } |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format Thumb32DataProcShiftReg() {{ |
| |
| def decInst(mnem, dest="rd", op1="rn"): |
| return ''' |
| if (s) { |
| return new %(mnem)sRegCc(machInst, %(dest)s, |
| %(op1)s, rm, amt, type); |
| } else { |
| return new %(mnem)sReg(machInst, %(dest)s, |
| %(op1)s, rm, amt, type); |
| } |
| ''' % {"mnem" : mnem, "dest" : dest, "op1" : op1} |
| |
| decode_block = ''' |
| { |
| const uint32_t op = bits(machInst, 24, 21); |
| const bool s = (bits(machInst, 20) == 1); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8); |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const uint32_t amt = (bits(machInst, 14, 12) << 2) | |
| bits(machInst, 7, 6); |
| const ArmShiftType type = (ArmShiftType)(uint32_t)bits(machInst, 5, 4); |
| switch (op) { |
| case 0x0: |
| if (rd == INTREG_PC) { |
| %(tst)s |
| } else { |
| %(and)s |
| } |
| case 0x1: |
| %(bic)s |
| case 0x2: |
| if (rn == INTREG_PC) { |
| %(mov)s |
| } else { |
| %(orr)s |
| } |
| case 0x3: |
| if (rn == INTREG_PC) { |
| %(mvn)s |
| } else { |
| %(orn)s |
| } |
| case 0x4: |
| if (rd == INTREG_PC) { |
| %(teq)s |
| } else { |
| %(eor)s |
| } |
| case 0x6: |
| if (type) { |
| return new PkhtbReg(machInst, rd, rn, rm, amt, type); |
| } else { |
| return new PkhbtReg(machInst, rd, rn, rm, amt, type); |
| } |
| case 0x8: |
| if (rd == INTREG_PC) { |
| %(cmn)s |
| } else { |
| %(add)s |
| } |
| case 0xa: |
| %(adc)s |
| case 0xb: |
| %(sbc)s |
| case 0xd: |
| if (rd == INTREG_PC) { |
| %(cmp)s |
| } else { |
| %(sub)s |
| } |
| case 0xe: |
| %(rsb)s |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' % { |
| "tst" : decInst("Tst", "INTREG_ZERO"), |
| "and" : decInst("And"), |
| "bic" : decInst("Bic"), |
| "mov" : decInst("Mov", op1="INTREG_ZERO"), |
| "orr" : decInst("Orr"), |
| "mvn" : decInst("Mvn", op1="INTREG_ZERO"), |
| "orn" : decInst("Orn"), |
| "teq" : decInst("Teq", "INTREG_ZERO"), |
| "eor" : decInst("Eor"), |
| "cmn" : decInst("Cmn", "INTREG_ZERO"), |
| "add" : decInst("Add"), |
| "adc" : decInst("Adc"), |
| "sbc" : decInst("Sbc"), |
| "cmp" : decInst("Cmp", "INTREG_ZERO"), |
| "sub" : decInst("Sub"), |
| "rsb" : decInst("Rsb") |
| } |
| }}; |