// Copyright (c) 2010 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 ArmDataProcReg() {{ instDecode = ''' case %(opcode)#x: if (immShift) { if (setCc) { 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, dest="rd", op1="rn"): global instDecode return instDecode % { "className": mnem.capitalize(), "opcode": opcode, "dest": dest, "op1": op1 } 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", dest="INTREG_ZERO") decode_block += instCode(0x9, "teq", dest="INTREG_ZERO") decode_block += instCode(0xa, "cmp", dest="INTREG_ZERO") decode_block += instCode(0xb, "cmn", dest="INTREG_ZERO") decode_block += instCode(0xc, "orr") decode_block += instCode(0xd, "mov", op1="INTREG_ZERO") decode_block += instCode(0xe, "bic") decode_block += instCode(0xf, "mvn", op1="INTREG_ZERO") decode_block += ''' default: return new Unknown(machInst); } } ''' }}; def format ArmDataProcImm() {{ instDecode = ''' if (setCc) { return new %(className)sImmCc(machInst, %(dest)s, %(op1)s, imm, rotC); } else { return new %(className)sImm(machInst, %(dest)s, %(op1)s, imm, rotC); } break; ''' def instCode(opcode, mnem, dest="rd", op1="rn"): global instDecode code = ''' case %(opcode)#x: ''' + instDecode return code % { "className": mnem.capitalize(), "opcode": opcode, "dest": dest, "op1": op1 } def adrCode(opcode, mnem, dest="rd", op1="rn", add="1"): global instDecode code = ''' case %(opcode)#x: if (rn == 0xf) { return new AdrImm(machInst, %(dest)s, %(add)s, imm, false); } else { ''' + instDecode + ''' } ''' return code % { "className": mnem.capitalize(), "opcode": opcode, "dest": dest, "add": add, "op1": op1 } 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", dest="INTREG_ZERO") decode_block += instCode(0x9, "teq", dest="INTREG_ZERO") decode_block += instCode(0xa, "cmp", dest="INTREG_ZERO") decode_block += instCode(0xb, "cmn", dest="INTREG_ZERO") decode_block += instCode(0xc, "orr") decode_block += instCode(0xd, "mov", op1="INTREG_ZERO") decode_block += instCode(0xe, "bic") decode_block += instCode(0xf, "mvn", op1="INTREG_ZERO") decode_block += ''' default: 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 return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSL); case 0x1: // lsr return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSR); case 0x2: // asr return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, ASR); case 0x3: switch (bits(machInst, 10, 9)) { case 0x0: return new AddRegCc(machInst, rd, rn, rm, 0, LSL); case 0x1: return new SubRegCc(machInst, rd, rn, rm, 0, LSL); case 0x2: return new AddImmCc(machInst, rd, rn, imm3, true); case 0x3: return new SubImmCc(machInst, rd, rn, imm3, true); } case 0x4: return new MovImmCc(machInst, rd8, INTREG_ZERO, imm8, false); case 0x5: return new CmpImmCc(machInst, INTREG_ZERO, rd8, imm8, true); case 0x6: return new AddImmCc(machInst, rd8, rd8, imm8, true); case 0x7: 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: return new AndRegCc(machInst, rdn, rdn, rm, 0, LSL); case 0x1: return new EorRegCc(machInst, rdn, rdn, rm, 0, LSL); case 0x2: //lsl return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, LSL); case 0x3: //lsr return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, LSR); case 0x4: //asr return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, ASR); case 0x5: return new AdcRegCc(machInst, rdn, rdn, rm, 0, LSL); case 0x6: return new SbcRegCc(machInst, rdn, rdn, rm, 0, LSL); case 0x7: // ror return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, ROR); case 0x8: return new TstRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); case 0x9: 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: return new OrrRegCc(machInst, rdn, rdn, rm, 0, LSL); case 0xd: return new MulCc(machInst, rdn, rm, rdn); case 0xe: return new BicRegCc(machInst, rdn, rdn, rm, 0, LSL); case 0xf: 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 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 0x1: return new Cbz(machInst, (bits(machInst, 9) << 6) | (bits(machInst, 7, 3) << 1), (IntRegIndex)(uint32_t)bits(machInst, 2, 0)); case 0x2: switch (bits(machInst, 7, 6)) { case 0x0: return new WarnUnimplemented("sxth", machInst); case 0x1: return new WarnUnimplemented("sxtb", machInst); case 0x2: return new WarnUnimplemented("uxth", machInst); case 0x3: return new WarnUnimplemented("uxtb", machInst); } 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: return new WarnUnimplemented("push", machInst); case 0x6: { const uint32_t opBits = bits(machInst, 7, 5); if (opBits == 2) { return new WarnUnimplemented("setend", machInst); } else if (opBits == 3) { return new WarnUnimplemented("cps", machInst); } } case 0x9: return new Cbnz(machInst, (bits(machInst, 9) << 6) | (bits(machInst, 7, 3) << 1), (IntRegIndex)(uint32_t)bits(machInst, 2, 0)); case 0xa: switch (bits(machInst, 7, 5)) { case 0x0: return new WarnUnimplemented("rev", machInst); case 0x1: return new WarnUnimplemented("rev16", machInst); case 0x3: return new WarnUnimplemented("revsh", machInst); default: break; } break; 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: return new WarnUnimplemented("pop", machInst); case 0xe: return new WarnUnimplemented("bkpt", machInst); case 0xf: if (bits(machInst, 3, 0) != 0) return new WarnUnimplemented("it", machInst); switch (bits(machInst, 7, 4)) { case 0x0: return new WarnUnimplemented("nop", machInst); case 0x1: return new WarnUnimplemented("yield", machInst); case 0x2: return new WarnUnimplemented("wfe", machInst); case 0x3: return new WarnUnimplemented("wfi", machInst); case 0x4: return new WarnUnimplemented("sev", 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))) { return new WarnUnimplemented("ssat16", machInst); } // Fall through on purpose... case 0x10: return new WarnUnimplemented("ssat", machInst); case 0x14: return new WarnUnimplemented("sbfx", machInst); case 0x16: if (rn == 0xf) { return new WarnUnimplemented("bfc", machInst); } else { return new WarnUnimplemented("bfi", machInst); } case 0x1a: if (!(bits(machInst, 14, 12) || bits(machInst, 7, 6))) { return new WarnUnimplemented("usat16", machInst); } // Fall through on purpose... case 0x18: return new WarnUnimplemented("usat", machInst); case 0x1c: return new WarnUnimplemented("ubfx", machInst); 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: return new WarnUnimplemented("pkh", machInst); 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") } }};