// -*- mode:c++ -*- // 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. // // Copyright (c) 2007-2008 The Florida State University // All rights reserved. // // 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: Stephen Hines //////////////////////////////////////////////////////////////////// // // Floating Point operate instructions // let {{ header_output = ''' StaticInstPtr decodeNeonMem(ExtMachInst machInst); StaticInstPtr decodeNeonData(ExtMachInst machInst); ''' decoder_output = ''' StaticInstPtr decodeNeonMem(ExtMachInst machInst) { const uint32_t b = bits(machInst, 11, 8); const bool a = bits(machInst, 23); const bool l = bits(machInst, 21); if (l) { // Load instructions. if (a) { if (bits(b, 3, 2) != 3) { switch (bits(b, 1, 0)) { case 0x0: return new WarnUnimplemented("vld1 single", machInst); case 0x1: return new WarnUnimplemented("vld2 single", machInst); case 0x2: return new WarnUnimplemented("vld3 single", machInst); case 0x3: return new WarnUnimplemented("vld4 single", machInst); } } else { switch (bits(b, 1, 0)) { case 0x0: return new WarnUnimplemented("vld1 single all", machInst); case 0x1: return new WarnUnimplemented("vld2 single all", machInst); case 0x2: return new WarnUnimplemented("vld3 single all", machInst); case 0x3: return new WarnUnimplemented("vld4 single all", machInst); } } } else { switch (bits(b, 3, 1)) { case 0x0: return new WarnUnimplemented("vld4 multiple", machInst); case 0x2: return new WarnUnimplemented("vld3 multiple", machInst); case 0x3: return new WarnUnimplemented("vld1 multiple", machInst); case 0x4: return new WarnUnimplemented("vld2 multiple", machInst); case 0x1: if (b & 0x1) { return new WarnUnimplemented("vld2 multiple", machInst); } else { return new WarnUnimplemented("vld1 multiple", machInst); } case 0x5: if ((b & 0x1) == 0) { return new WarnUnimplemented("vld1 multiple", machInst); } else { break; } } } } else { // Store instructions. if (a) { if (bits(b, 3, 2) != 3) { switch (bits(b, 1, 0)) { case 0x0: return new WarnUnimplemented("vst1 single", machInst); case 0x1: return new WarnUnimplemented("vst2 single", machInst); case 0x2: return new WarnUnimplemented("vst3 single", machInst); case 0x3: return new WarnUnimplemented("vst4 single", machInst); } } else { switch (bits(b, 1, 0)) { case 0x0: return new WarnUnimplemented("vst1 single all", machInst); case 0x1: return new WarnUnimplemented("vst2 single all", machInst); case 0x2: return new WarnUnimplemented("vst3 single all", machInst); case 0x3: return new WarnUnimplemented("vst4 single all", machInst); } } } else { switch (bits(b, 3, 1)) { case 0x0: return new WarnUnimplemented("vst4 multiple", machInst); case 0x2: return new WarnUnimplemented("vst3 multiple", machInst); case 0x3: return new WarnUnimplemented("vst1 multiple", machInst); case 0x4: return new WarnUnimplemented("vst2 multiple", machInst); case 0x1: if (b & 0x1) { return new WarnUnimplemented("vst2 multiple", machInst); } else { return new WarnUnimplemented("vst1 multiple", machInst); } case 0x5: if ((b & 0x1) == 0) { return new WarnUnimplemented("vst1 multiple", machInst); } else { break; } } } } return new Unknown(machInst); } ''' decoder_output += ''' static StaticInstPtr decodeNeonThreeRegistersSameLength(ExtMachInst machInst) { const bool u = THUMB ? bits(machInst, 28) : bits(machInst, 24); const uint32_t a = bits(machInst, 11, 8); const bool b = bits(machInst, 4); const uint32_t c = bits(machInst, 21, 20); switch (a) { case 0x0: if (b) { if (bits(machInst, 9) == 0) { return new WarnUnimplemented("vhadd", machInst); } else { return new WarnUnimplemented("vhsub", machInst); } } else { return new WarnUnimplemented("vqadd", machInst); } case 0x1: if (!b) { return new WarnUnimplemented("vrhadd", machInst); } else { if (u) { switch (c) { case 0: return new WarnUnimplemented("veor", machInst); case 1: return new WarnUnimplemented("vbsl", machInst); case 2: return new WarnUnimplemented("vbit", machInst); case 3: return new WarnUnimplemented("vbif", machInst); } } else { switch (c) { case 0: return new WarnUnimplemented("vand (reg)", machInst); case 1: return new WarnUnimplemented("vbic (reg)", machInst); case 2: { const IntRegIndex n = (IntRegIndex)( (uint32_t)bits(machInst, 19, 16) | (uint32_t)(bits(machInst, 7) << 4)); const IntRegIndex m = (IntRegIndex)( (uint32_t)bits(machInst, 3, 0) | (uint32_t)(bits(machInst, 5) << 4)); if (n == m) { return new WarnUnimplemented("vmov (reg)", machInst); } else { return new WarnUnimplemented("vorr (reg)", machInst); } } case 3: return new WarnUnimplemented("vorn (reg)", machInst); } } } case 0x2: if (b) { return new WarnUnimplemented("vqsub", machInst); } else { if (bits(machInst, 9) == 0) { return new WarnUnimplemented("vhadd", machInst); } else { return new WarnUnimplemented("vhsub", machInst); } } case 0x3: if (b) { return new WarnUnimplemented("vcge (reg)", machInst); } else { return new WarnUnimplemented("vcgt (reg)", machInst); } case 0x4: if (b) { return new WarnUnimplemented("vqshl (reg)", machInst); } else { return new WarnUnimplemented("vshl (reg)", machInst); } case 0x5: if (b) { return new WarnUnimplemented("vqrshl", machInst); } else { return new WarnUnimplemented("vrshl", machInst); } case 0x6: if (b) { return new WarnUnimplemented("vmin (int)", machInst); } else { return new WarnUnimplemented("vmax (int)", machInst); } case 0x7: if (b) { return new WarnUnimplemented("vaba", machInst); } else { if (bits(machInst, 23) == 1) { if (bits(machInst, 6) == 1) { return new Unknown(machInst); } else { return new WarnUnimplemented("vabdl (int)", machInst); } } else { return new WarnUnimplemented("vabd (int)", machInst); } } case 0x8: if (b) { if (u) { return new WarnUnimplemented("vceq (reg)", machInst); } else { return new WarnUnimplemented("vtst", machInst); } } else { if (u) { return new WarnUnimplemented("vsub (int)", machInst); } else { return new WarnUnimplemented("vadd (int)", machInst); } } case 0x9: if (b) { if (u) { return new WarnUnimplemented("vmul (poly)", machInst); } else { return new WarnUnimplemented("vmul (int)", machInst); } } else { if (u) { return new WarnUnimplemented("vmls (int)", machInst); } else { return new WarnUnimplemented("vmla (int)", machInst); } } case 0xa: if (b) { return new WarnUnimplemented("vpmin (int)", machInst); } else { return new WarnUnimplemented("vpmax (int)", machInst); } case 0xb: if (b) { if (u) { return new Unknown(machInst); } else { return new WarnUnimplemented("vpadd (int)", machInst); } } else { if (u) { return new WarnUnimplemented("vqrdmulh", machInst); } else { return new WarnUnimplemented("vqdmulh", machInst); } } case 0xc: return new Unknown(machInst); case 0xd: if (b) { if (u) { if (bits(c, 1) == 0) { return new WarnUnimplemented("vmul (fp)", machInst); } else { return new Unknown(machInst); } } else { if (bits(c, 1) == 0) { return new WarnUnimplemented("vmla (fp)", machInst); } else { return new WarnUnimplemented("vmls (fp)", machInst); } } } else { if (u) { if (bits(c, 1) == 0) { return new WarnUnimplemented("vpadd (fp)", machInst); } else { return new WarnUnimplemented("vabd (fp)", machInst); } } else { if (bits(c, 1) == 0) { return new WarnUnimplemented("vadd (fp)", machInst); } else { return new WarnUnimplemented("vsub (fp)", machInst); } } } case 0xe: if (b) { if (u) { if (bits(c, 1) == 0) { return new WarnUnimplemented("vacge", machInst); } else { return new WarnUnimplemented("vacgt", machInst); } } else { return new Unknown(machInst); } } else { if (u) { if (bits(c, 1) == 0) { return new WarnUnimplemented("vcge (reg)", machInst); } else { return new WarnUnimplemented("vcgt (reg)", machInst); } } else { if (bits(c, 1) == 0) { return new WarnUnimplemented("vceq (reg)", machInst); } else { return new Unknown(machInst); } } } case 0xf: if (b) { if (u) { return new Unknown(machInst); } else { if (bits(c, 1) == 0) { return new WarnUnimplemented("vrecps", machInst); } else { return new WarnUnimplemented("vrsqrts", machInst); } } } else { if (u) { if (bits(c, 1) == 0) { return new WarnUnimplemented("vpmax (fp)", machInst); } else { return new WarnUnimplemented("vpmin (fp)", machInst); } } else { if (bits(c, 1) == 0) { return new WarnUnimplemented("vmax (fp)", machInst); } else { return new WarnUnimplemented("vmin (fp)", machInst); } } } } return new Unknown(machInst); } static StaticInstPtr decodeNeonOneRegModImm(ExtMachInst machInst) { const bool op = bits(machInst, 5); const uint32_t cmode = bits(machInst, 11, 8); if (op) { if (bits(cmode, 3) == 0) { if (bits(cmode, 0) == 0) { return new WarnUnimplemented("vmov (imm)", machInst); } else { return new WarnUnimplemented("vorr (imm)", machInst); } } else { if (bits(cmode, 2) == 1) { return new WarnUnimplemented("vmov (imm)", machInst); } else { if (bits(cmode, 0) == 0) { return new WarnUnimplemented("vmov (imm)", machInst); } else { return new WarnUnimplemented("vorr (imm)", machInst); } } } } else { if (bits(cmode, 3) == 0) { if (bits(cmode, 0) == 0) { return new WarnUnimplemented("vmvn (imm)", machInst); } else { return new WarnUnimplemented("vbic (imm)", machInst); } } else { if (bits(cmode, 2) == 1) { switch (bits(cmode, 1, 0)) { case 0: case 1: return new WarnUnimplemented("vmvn (imm)", machInst); case 2: return new WarnUnimplemented("vmov (imm)", machInst); case 3: return new Unknown(machInst); } return new WarnUnimplemented("vmov (imm)", machInst); } else { if (bits(cmode, 0) == 0) { return new WarnUnimplemented("vmvn (imm)", machInst); } else { return new WarnUnimplemented("vbic (imm)", machInst); } } } } return new Unknown(machInst); } static StaticInstPtr decodeNeonTwoRegAndShift(ExtMachInst machInst) { const uint32_t a = bits(machInst, 11, 8); const bool u = THUMB ? bits(machInst, 28) : bits(machInst, 24); const bool b = bits(machInst, 6); const bool l = bits(machInst, 7); switch (a) { case 0x0: return new WarnUnimplemented("vshr", machInst); case 0x1: return new WarnUnimplemented("vsra", machInst); case 0x2: return new WarnUnimplemented("vrshr", machInst); case 0x3: return new WarnUnimplemented("vrsra", machInst); case 0x4: if (u) { return new WarnUnimplemented("vsri", machInst); } else { return new Unknown(machInst); } case 0x5: if (u) { return new WarnUnimplemented("vsli", machInst); } else { return new WarnUnimplemented("vshl (imm)", machInst); } case 0x6: case 0x7: return new WarnUnimplemented("vqshl, vqshlu (imm)", machInst); case 0x8: if (l) { return new Unknown(machInst); } else if (u) { if (b) { return new WarnUnimplemented("vqrshrn, vqrshrun", machInst); } else { return new WarnUnimplemented("vqshrn, vqshrun", machInst); } } else { if (b) { return new WarnUnimplemented("vrshrn", machInst); } else { return new WarnUnimplemented("vshrn", machInst); } } case 0x9: if (l) { return new Unknown(machInst); } else if (b) { return new WarnUnimplemented("vqrshrn, vqrshrun", machInst); } else { return new WarnUnimplemented("vqshrn, vqshrun", machInst); } case 0xa: if (l || b) { return new Unknown(machInst); } else { // If the shift amount is zero, it's vmovl. return new WarnUnimplemented("vshll, vmovl", machInst); } case 0xe: case 0xf: if (l) { return new Unknown(machInst); } else if (a == 0xe) { return new WarnUnimplemented("vcvt (fixed to fp)", machInst); } else if (a == 0xf) { return new WarnUnimplemented("vcvt (fp to fixed)", machInst); } } return new Unknown(machInst); } static StaticInstPtr decodeNeonThreeRegDiffLengths(ExtMachInst machInst) { const bool u = THUMB ? bits(machInst, 28) : bits(machInst, 24); const uint32_t a = bits(machInst, 11, 8); switch (a) { case 0x0: return new WarnUnimplemented("vaddl", machInst); case 0x1: return new WarnUnimplemented("vaddw", machInst); case 0x2: return new WarnUnimplemented("vsubl", machInst); case 0x3: return new WarnUnimplemented("vsubw", machInst); case 0x4: if (u) { return new WarnUnimplemented("vraddhn", machInst); } else { return new WarnUnimplemented("vaddhn", machInst); } case 0x5: return new WarnUnimplemented("vabal", machInst); case 0x6: if (u) { return new WarnUnimplemented("vrsubhn", machInst); } else { return new WarnUnimplemented("vsubhn", machInst); } case 0x7: if (bits(machInst, 23)) { return new WarnUnimplemented("vabdl (int)", machInst); } else { return new WarnUnimplemented("vabd (int)", machInst); } case 0x8: return new WarnUnimplemented("vmlal (int)", machInst); case 0xa: return new WarnUnimplemented("vmlsl (int)", machInst); case 0x9: if (bits(machInst, 23) == 0) { if (bits(machInst, 4) == 0) { if (u) { return new WarnUnimplemented("vmls (int)", machInst); } else { return new WarnUnimplemented("vmla (int)", machInst); } } else { if (u) { return new WarnUnimplemented("vmul (poly)", machInst); } else { return new WarnUnimplemented("vmul (int)", machInst); } } } else { return new WarnUnimplemented("vqdmlal", machInst); } case 0xb: if (!u) { return new Unknown(machInst); } else { return new WarnUnimplemented("vqdmlsl", machInst); } case 0xc: return new WarnUnimplemented("vmull (int)", machInst); case 0xd: if (!u) { return new Unknown(machInst); } else { return new WarnUnimplemented("vqdmull", machInst); } case 0xe: return new WarnUnimplemented("vmull (poly)", machInst); } return new Unknown(machInst); } static StaticInstPtr decodeNeonTwoRegScalar(ExtMachInst machInst) { const bool u = THUMB ? bits(machInst, 28) : bits(machInst, 24); const uint32_t a = bits(machInst, 11, 8); switch (a) { case 0x0: return new WarnUnimplemented("vmla (int scalar)", machInst); case 0x1: return new WarnUnimplemented("vmla (fp scalar)", machInst); case 0x4: return new WarnUnimplemented("vmls (int scalar)", machInst); case 0x5: return new WarnUnimplemented("vmls (fp scalar)", machInst); case 0x2: return new WarnUnimplemented("vmlal (scalar)", machInst); case 0x6: return new WarnUnimplemented("vmlsl (scalar)", machInst); case 0x3: if (u) { return new Unknown(machInst); } else { return new WarnUnimplemented("vqdmlal", machInst); } case 0x7: if (u) { return new Unknown(machInst); } else { return new WarnUnimplemented("vqdmlsl", machInst); } case 0x8: return new WarnUnimplemented("vmul (int scalar)", machInst); case 0x9: return new WarnUnimplemented("vmul (fp scalar)", machInst); case 0xa: return new WarnUnimplemented("vmull (scalar)", machInst); case 0xb: if (u) { return new Unknown(machInst); } else { return new WarnUnimplemented("vqdmull", machInst); } case 0xc: return new WarnUnimplemented("vqdmulh", machInst); case 0xd: return new WarnUnimplemented("vqrdmulh", machInst); } return new Unknown(machInst); } static StaticInstPtr decodeNeonTwoRegMisc(ExtMachInst machInst) { const uint32_t a = bits(machInst, 17, 16); const uint32_t b = bits(machInst, 10, 6); switch (a) { case 0x0: switch (bits(b, 4, 1)) { case 0x0: return new WarnUnimplemented("vrev64", machInst); case 0x1: return new WarnUnimplemented("vrev32", machInst); case 0x2: return new WarnUnimplemented("vrev16", machInst); case 0x4: case 0x5: return new WarnUnimplemented("vpaddl", machInst); case 0x8: return new WarnUnimplemented("vcls", machInst); case 0x9: return new WarnUnimplemented("vclz", machInst); case 0xa: return new WarnUnimplemented("vcnt", machInst); case 0xb: return new WarnUnimplemented("vmvn (reg)", machInst); case 0xc: case 0xd: return new WarnUnimplemented("vpadal", machInst); case 0xe: return new WarnUnimplemented("vqabs", machInst); case 0xf: return new WarnUnimplemented("vqneg", machInst); default: return new Unknown(machInst); } case 0x1: switch (bits(b, 3, 1)) { case 0x0: return new WarnUnimplemented("vcgt (imm #0)", machInst); case 0x1: return new WarnUnimplemented("vcge (imm #0)", machInst); case 0x2: return new WarnUnimplemented("vceq (imm #0)", machInst); case 0x3: return new WarnUnimplemented("vcle (imm #0)", machInst); case 0x4: return new WarnUnimplemented("vclt (imm #0)", machInst); case 0x6: return new WarnUnimplemented("vabs (imm #0)", machInst); case 0x7: return new WarnUnimplemented("vneg (imm #0)", machInst); } case 0x2: switch (bits(b, 4, 1)) { case 0x0: return new WarnUnimplemented("vswp", machInst); case 0x1: return new WarnUnimplemented("vtrn", machInst); case 0x2: return new WarnUnimplemented("vuzp", machInst); case 0x3: return new WarnUnimplemented("vzip", machInst); case 0x4: if (b == 0x8) { return new WarnUnimplemented("vmovn", machInst); } else { return new WarnUnimplemented("vqmovun", machInst); } case 0x5: return new WarnUnimplemented("vqmovn", machInst); case 0x6: if (b == 0xc) { return new WarnUnimplemented("vshll", machInst); } else { return new Unknown(machInst); } case 0xc: case 0xe: if (b == 0x18) { return new WarnUnimplemented("vcvt (single to half)", machInst); } else if (b == 0x1c) { return new WarnUnimplemented("vcvt (half to single)", machInst); } else { return new Unknown(machInst); } default: return new Unknown(machInst); } case 0x3: if (bits(b, 4, 3) == 0x3) { return new WarnUnimplemented("vcvt (fp and int)", machInst); } else if ((b & 0x1a) == 0x10) { return new WarnUnimplemented("vrecpe", machInst); } else if ((b & 0x1a) == 0x12) { return new WarnUnimplemented("vrsqrte", machInst); } else { return new Unknown(machInst); } } return new Unknown(machInst); } StaticInstPtr decodeNeonData(ExtMachInst machInst) { const bool u = THUMB ? bits(machInst, 28) : bits(machInst, 24); const uint32_t a = bits(machInst, 23, 19); const uint32_t b = bits(machInst, 11, 8); const uint32_t c = bits(machInst, 7, 4); if (bits(a, 4) == 0) { return decodeNeonThreeRegistersSameLength(machInst); } else if ((c & 0x9) == 1) { if ((a & 0x7) == 0) { return decodeNeonOneRegModImm(machInst); } else { return decodeNeonTwoRegAndShift(machInst); } } else if ((c & 0x9) == 9) { return decodeNeonTwoRegAndShift(machInst); } else if ((c & 0x5) == 0) { if (bits(a, 3, 2) != 0x3) { return decodeNeonThreeRegDiffLengths(machInst); } } else if ((c & 0x5) == 4) { if (bits(a, 3, 2) != 0x3) { return decodeNeonTwoRegScalar(machInst); } } else if ((a & 0x16) == 0x16) { if (!u) { if (bits(c, 0) == 0) { return new WarnUnimplemented("vext", machInst); } } else if (bits(b, 3) == 0 && bits(c, 0) == 0) { return decodeNeonTwoRegMisc(machInst); } else if (bits(b, 3, 2) == 0x2 && bits(c, 0) == 0) { if (bits(machInst, 6) == 0) { return new WarnUnimplemented("vtbl", machInst); } else { return new WarnUnimplemented("vtbx", machInst); } } else if (b == 0xc && (c & 0x9) == 0) { return new WarnUnimplemented("vdup (scalar)", machInst); } } return new Unknown(machInst); } ''' }}; def format ThumbNeonMem() {{ decode_block = ''' return decodeNeonMem(machInst); ''' }}; def format ThumbNeonData() {{ decode_block = ''' return decodeNeonMem(machInst); ''' }}; let {{ header_output = ''' StaticInstPtr decodeExtensionRegLoadStore(ExtMachInst machInst); ''' decoder_output = ''' StaticInstPtr decodeExtensionRegLoadStore(ExtMachInst machInst) { const uint32_t opcode = bits(machInst, 24, 20); const uint32_t offset = bits(machInst, 7, 0); const bool single = (bits(machInst, 8) == 0); const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); RegIndex vd; if (single) { vd = (RegIndex)(uint32_t)((bits(machInst, 15, 12) << 1) | bits(machInst, 22)); } else { vd = (RegIndex)(uint32_t)((bits(machInst, 15, 12) << 1) | (bits(machInst, 22) << 5)); } switch (bits(opcode, 4, 3)) { case 0x0: if (bits(opcode, 4, 1) == 0x2 && !(machInst.thumb == 1 && bits(machInst, 28) == 1) && !(machInst.thumb == 0 && machInst.condCode == 0xf)) { if ((bits(machInst, 7, 4) & 0xd) != 1) { break; } const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); const IntRegIndex rt2 = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); const bool op = bits(machInst, 20); uint32_t vm; if (single) { vm = (bits(machInst, 3, 0) << 1) | bits(machInst, 5); } else { vm = (bits(machInst, 3, 0) << 1) | (bits(machInst, 5) << 5); } if (op) { return new Vmov2Core2Reg(machInst, rt, rt2, (IntRegIndex)vm); } else { return new Vmov2Reg2Core(machInst, (IntRegIndex)vm, rt, rt2); } } break; case 0x1: { if (offset == 0 || vd + offset > NumFloatArchRegs) { break; } switch (bits(opcode, 1, 0)) { case 0x0: return new VLdmStm(machInst, rn, vd, single, true, false, false, offset); case 0x1: return new VLdmStm(machInst, rn, vd, single, true, false, true, offset); case 0x2: return new VLdmStm(machInst, rn, vd, single, true, true, false, offset); case 0x3: // If rn == sp, then this is called vpop. return new VLdmStm(machInst, rn, vd, single, true, true, true, offset); } } case 0x2: if (bits(opcode, 1, 0) == 0x2) { // If rn == sp, then this is called vpush. return new VLdmStm(machInst, rn, vd, single, false, true, false, offset); } else if (bits(opcode, 1, 0) == 0x3) { return new VLdmStm(machInst, rn, vd, single, false, true, true, offset); } // Fall through on purpose case 0x3: const bool up = (bits(machInst, 23) == 1); const uint32_t imm = bits(machInst, 7, 0) << 2; RegIndex vd; if (single) { vd = (RegIndex)(uint32_t)((bits(machInst, 15, 12) << 1) | (bits(machInst, 22))); } else { vd = (RegIndex)(uint32_t)((bits(machInst, 15, 12) << 1) | (bits(machInst, 22) << 5)); } if (bits(opcode, 1, 0) == 0x0) { if (single) { if (up) { return new %(vstr_us)s(machInst, vd, rn, up, imm); } else { return new %(vstr_s)s(machInst, vd, rn, up, imm); } } else { if (up) { return new %(vstr_ud)s(machInst, vd, vd + 1, rn, up, imm); } else { return new %(vstr_d)s(machInst, vd, vd + 1, rn, up, imm); } } } else if (bits(opcode, 1, 0) == 0x1) { if (single) { if (up) { return new %(vldr_us)s(machInst, vd, rn, up, imm); } else { return new %(vldr_s)s(machInst, vd, rn, up, imm); } } else { if (up) { return new %(vldr_ud)s(machInst, vd, vd + 1, rn, up, imm); } else { return new %(vldr_d)s(machInst, vd, vd + 1, rn, up, imm); } } } } return new Unknown(machInst); } ''' % { "vldr_us" : "VLDR_" + loadImmClassName(False, True, False), "vldr_s" : "VLDR_" + loadImmClassName(False, False, False), "vldr_ud" : "VLDR_" + loadDoubleImmClassName(False, True, False), "vldr_d" : "VLDR_" + loadDoubleImmClassName(False, False, False), "vstr_us" : "VSTR_" + storeImmClassName(False, True, False), "vstr_s" : "VSTR_" + storeImmClassName(False, False, False), "vstr_ud" : "VSTR_" + storeDoubleImmClassName(False, True, False), "vstr_d" : "VSTR_" + storeDoubleImmClassName(False, False, False) } }}; def format ExtensionRegLoadStore() {{ decode_block = ''' return decodeExtensionRegLoadStore(machInst); ''' }}; let {{ header_output = ''' StaticInstPtr decodeShortFpTransfer(ExtMachInst machInst); ''' decoder_output = ''' StaticInstPtr decodeShortFpTransfer(ExtMachInst machInst) { const uint32_t l = bits(machInst, 20); const uint32_t c = bits(machInst, 8); const uint32_t a = bits(machInst, 23, 21); const uint32_t b = bits(machInst, 6, 5); if ((machInst.thumb == 1 && bits(machInst, 28) == 1) || (machInst.thumb == 0 && machInst.condCode == 0xf)) { return new Unknown(machInst); } if (l == 0 && c == 0) { if (a == 0) { const uint32_t vn = (bits(machInst, 19, 16) << 1) | bits(machInst, 7); const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); if (bits(machInst, 20) == 1) { return new VmovRegCoreW(machInst, rt, (IntRegIndex)vn); } else { return new VmovCoreRegW(machInst, (IntRegIndex)vn, rt); } } else if (a == 0x7) { const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); uint32_t specReg = bits(machInst, 19, 16); switch (specReg) { case 0: specReg = MISCREG_FPSID; break; case 1: specReg = MISCREG_FPSCR; break; case 6: specReg = MISCREG_MVFR1; break; case 7: specReg = MISCREG_MVFR0; break; case 8: specReg = MISCREG_FPEXC; break; default: return new Unknown(machInst); } return new Vmsr(machInst, (IntRegIndex)specReg, rt); } } else if (l == 0 && c == 1) { if (bits(a, 2) == 0) { uint32_t vd = (bits(machInst, 7) << 5) | (bits(machInst, 19, 16) << 1); uint32_t index, size; const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); if (bits(machInst, 22) == 1) { size = 8; index = (bits(machInst, 21) << 2) | bits(machInst, 6, 5); } else if (bits(machInst, 5) == 1) { size = 16; index = (bits(machInst, 21) << 1) | bits(machInst, 6); } else if (bits(machInst, 6) == 0) { size = 32; index = bits(machInst, 21); } else { return new Unknown(machInst); } if (index >= (32 / size)) { index -= (32 / size); vd++; } switch (size) { case 8: return new VmovCoreRegB(machInst, (IntRegIndex)vd, rt, index); case 16: return new VmovCoreRegH(machInst, (IntRegIndex)vd, rt, index); case 32: return new VmovCoreRegW(machInst, (IntRegIndex)vd, rt); } } else if (bits(b, 1) == 0) { // A8-594 return new WarnUnimplemented("vdup", machInst); } } else if (l == 1 && c == 0) { if (a == 0) { const uint32_t vn = (bits(machInst, 19, 16) << 1) | bits(machInst, 7); const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); if (bits(machInst, 20) == 1) { return new VmovRegCoreW(machInst, rt, (IntRegIndex)vn); } else { return new VmovCoreRegW(machInst, (IntRegIndex)vn, rt); } } else if (a == 7) { const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); uint32_t specReg = bits(machInst, 19, 16); switch (specReg) { case 0: specReg = MISCREG_FPSID; break; case 1: specReg = MISCREG_FPSCR; break; case 6: specReg = MISCREG_MVFR1; break; case 7: specReg = MISCREG_MVFR0; break; case 8: specReg = MISCREG_FPEXC; break; default: return new Unknown(machInst); } if (rt == 0xf) { CPSR cpsrMask = 0; cpsrMask.n = 1; cpsrMask.z = 1; cpsrMask.c = 1; cpsrMask.v = 1; return new VmrsApsr(machInst, INTREG_CONDCODES, (IntRegIndex)specReg, (uint32_t)cpsrMask); } else { return new Vmrs(machInst, rt, (IntRegIndex)specReg); } } } else { uint32_t vd = (bits(machInst, 7) << 5) | (bits(machInst, 19, 16) << 1); uint32_t index, size; const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); const bool u = (bits(machInst, 23) == 1); if (bits(machInst, 22) == 1) { size = 8; index = (bits(machInst, 21) << 2) | bits(machInst, 6, 5); } else if (bits(machInst, 5) == 1) { size = 16; index = (bits(machInst, 21) << 1) | bits(machInst, 6); } else if (bits(machInst, 6) == 0 && !u) { size = 32; index = bits(machInst, 21); } else { return new Unknown(machInst); } if (index >= (32 / size)) { index -= (32 / size); vd++; } switch (size) { case 8: if (u) { return new VmovRegCoreUB(machInst, rt, (IntRegIndex)vd, index); } else { return new VmovRegCoreSB(machInst, rt, (IntRegIndex)vd, index); } case 16: if (u) { return new VmovRegCoreUH(machInst, rt, (IntRegIndex)vd, index); } else { return new VmovRegCoreSH(machInst, rt, (IntRegIndex)vd, index); } case 32: return new VmovRegCoreW(machInst, rt, (IntRegIndex)vd); } } return new Unknown(machInst); } ''' }}; def format ShortFpTransfer() {{ decode_block = ''' return decodeShortFpTransfer(machInst); ''' }}; let {{ header_output = ''' StaticInstPtr decodeVfpData(ExtMachInst machInst); ''' decoder_output = ''' StaticInstPtr decodeVfpData(ExtMachInst machInst) { const uint32_t opc1 = bits(machInst, 23, 20); const uint32_t opc2 = bits(machInst, 19, 16); const uint32_t opc3 = bits(machInst, 7, 6); //const uint32_t opc4 = bits(machInst, 3, 0); const bool single = (bits(machInst, 8) == 0); // Used to select between vcmp and vcmpe. const bool e = (bits(machInst, 7) == 1); IntRegIndex vd; IntRegIndex vm; IntRegIndex vn; if (single) { vd = (IntRegIndex)(bits(machInst, 22) | (bits(machInst, 15, 12) << 1)); vm = (IntRegIndex)(bits(machInst, 5) | (bits(machInst, 3, 0) << 1)); vn = (IntRegIndex)(bits(machInst, 7) | (bits(machInst, 19, 16) << 1)); } else { vd = (IntRegIndex)((bits(machInst, 22) << 5) | (bits(machInst, 15, 12) << 1)); vm = (IntRegIndex)((bits(machInst, 5) << 5) | (bits(machInst, 3, 0) << 1)); vn = (IntRegIndex)((bits(machInst, 7) << 5) | (bits(machInst, 19, 16) << 1)); } switch (opc1 & 0xb /* 1011 */) { case 0x0: if (bits(machInst, 6) == 0) { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } else { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } case 0x1: if (bits(machInst, 6) == 1) { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } else { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } case 0x2: if ((opc3 & 0x1) == 0) { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } else { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } case 0x3: if ((opc3 & 0x1) == 0) { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } else { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } case 0x8: if ((opc3 & 0x1) == 0) { if (single) { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, false); } else { return decodeVfpRegRegRegOp( machInst, vd, vn, vm, true); } } break; case 0xb: if ((opc3 & 0x1) == 0) { const uint32_t baseImm = bits(machInst, 3, 0) | (bits(machInst, 19, 16) << 4); if (single) { uint32_t imm = vfp_modified_imm(baseImm, false); return decodeVfpRegImmOp( machInst, vd, imm, false); } else { uint64_t imm = vfp_modified_imm(baseImm, true); return decodeVfpRegImmOp( machInst, vd, imm, true); } } switch (opc2) { case 0x0: if (opc3 == 1) { if (single) { return decodeVfpRegRegOp( machInst, vd, vm, false); } else { return decodeVfpRegRegOp( machInst, vd, vm, true); } } else { if (single) { return decodeVfpRegRegOp( machInst, vd, vm, false); } else { return decodeVfpRegRegOp( machInst, vd, vm, true); } } case 0x1: if (opc3 == 1) { if (single) { return decodeVfpRegRegOp( machInst, vd, vm, false); } else { return decodeVfpRegRegOp( machInst, vd, vm, true); } } else { if (single) { return decodeVfpRegRegOp( machInst, vd, vm, false); } else { return decodeVfpRegRegOp( machInst, vd, vm, true); } } case 0x2: case 0x3: { const bool toHalf = bits(machInst, 16); const bool top = bits(machInst, 7); if (top) { if (toHalf) { return new VcvtFpSFpHT(machInst, vd, vm); } else { return new VcvtFpHTFpS(machInst, vd, vm); } } else { if (toHalf) { return new VcvtFpSFpHB(machInst, vd, vm); } else { return new VcvtFpHBFpS(machInst, vd, vm); } } } case 0x4: if (single) { if (e) { return new VcmpeS(machInst, vd, vm); } else { return new VcmpS(machInst, vd, vm); } } else { if (e) { return new VcmpeD(machInst, vd, vm); } else { return new VcmpD(machInst, vd, vm); } } case 0x5: if (single) { if (e) { return new VcmpeZeroS(machInst, vd, 0); } else { return new VcmpZeroS(machInst, vd, 0); } } else { if (e) { return new VcmpeZeroD(machInst, vd, 0); } else { return new VcmpZeroD(machInst, vd, 0); } } case 0x7: if (opc3 == 0x3) { if (single) { vm = (IntRegIndex)(bits(machInst, 5) | (bits(machInst, 3, 0) << 1)); return new VcvtFpSFpD(machInst, vd, vm); } else { vd = (IntRegIndex)(bits(machInst, 22) | (bits(machInst, 15, 12) << 1)); return new VcvtFpDFpS(machInst, vd, vm); } } break; case 0x8: if (bits(machInst, 7) == 0) { if (single) { return new VcvtUIntFpS(machInst, vd, vm); } else { vm = (IntRegIndex)(bits(machInst, 5) | (bits(machInst, 3, 0) << 1)); return new VcvtUIntFpD(machInst, vd, vm); } } else { if (single) { return new VcvtSIntFpS(machInst, vd, vm); } else { vm = (IntRegIndex)(bits(machInst, 5) | (bits(machInst, 3, 0) << 1)); return new VcvtSIntFpD(machInst, vd, vm); } } case 0xa: { const bool half = (bits(machInst, 7) == 0); const uint32_t imm = bits(machInst, 5) | (bits(machInst, 3, 0) << 1); const uint32_t size = (bits(machInst, 7) == 0 ? 16 : 32) - imm; if (single) { if (half) { return new VcvtSHFixedFpS(machInst, vd, vd, size); } else { return new VcvtSFixedFpS(machInst, vd, vd, size); } } else { if (half) { return new VcvtSHFixedFpD(machInst, vd, vd, size); } else { return new VcvtSFixedFpD(machInst, vd, vd, size); } } } case 0xb: { const bool half = (bits(machInst, 7) == 0); const uint32_t imm = bits(machInst, 5) | (bits(machInst, 3, 0) << 1); const uint32_t size = (bits(machInst, 7) == 0 ? 16 : 32) - imm; if (single) { if (half) { return new VcvtUHFixedFpS(machInst, vd, vd, size); } else { return new VcvtUFixedFpS(machInst, vd, vd, size); } } else { if (half) { return new VcvtUHFixedFpD(machInst, vd, vd, size); } else { return new VcvtUFixedFpD(machInst, vd, vd, size); } } } case 0xc: if (bits(machInst, 7) == 0) { if (single) { return new VcvtFpUIntSR(machInst, vd, vm); } else { vd = (IntRegIndex)(bits(machInst, 22) | (bits(machInst, 15, 12) << 1)); return new VcvtFpUIntDR(machInst, vd, vm); } } else { if (single) { return new VcvtFpUIntS(machInst, vd, vm); } else { vd = (IntRegIndex)(bits(machInst, 22) | (bits(machInst, 15, 12) << 1)); return new VcvtFpUIntD(machInst, vd, vm); } } case 0xd: if (bits(machInst, 7) == 0) { if (single) { return new VcvtFpSIntSR(machInst, vd, vm); } else { vd = (IntRegIndex)(bits(machInst, 22) | (bits(machInst, 15, 12) << 1)); return new VcvtFpSIntDR(machInst, vd, vm); } } else { if (single) { return new VcvtFpSIntS(machInst, vd, vm); } else { vd = (IntRegIndex)(bits(machInst, 22) | (bits(machInst, 15, 12) << 1)); return new VcvtFpSIntD(machInst, vd, vm); } } case 0xe: { const bool half = (bits(machInst, 7) == 0); const uint32_t imm = bits(machInst, 5) | (bits(machInst, 3, 0) << 1); const uint32_t size = (bits(machInst, 7) == 0 ? 16 : 32) - imm; if (single) { if (half) { return new VcvtFpSHFixedS(machInst, vd, vd, size); } else { return new VcvtFpSFixedS(machInst, vd, vd, size); } } else { if (half) { return new VcvtFpSHFixedD(machInst, vd, vd, size); } else { return new VcvtFpSFixedD(machInst, vd, vd, size); } } } case 0xf: { const bool half = (bits(machInst, 7) == 0); const uint32_t imm = bits(machInst, 5) | (bits(machInst, 3, 0) << 1); const uint32_t size = (bits(machInst, 7) == 0 ? 16 : 32) - imm; if (single) { if (half) { return new VcvtFpUHFixedS(machInst, vd, vd, size); } else { return new VcvtFpUFixedS(machInst, vd, vd, size); } } else { if (half) { return new VcvtFpUHFixedD(machInst, vd, vd, size); } else { return new VcvtFpUFixedD(machInst, vd, vd, size); } } } } break; } return new Unknown(machInst); } ''' }}; def format VfpData() {{ decode_block = ''' return decodeVfpData(machInst); ''' }};