| // Copyright (c) 2012-2013 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: Giacomo Gabrielli |
| // Mbou Eyole |
| |
| output header {{ |
| namespace Aarch64 |
| { |
| // AdvSIMD three same |
| template <typename DecoderFeatures> |
| StaticInstPtr decodeNeon3Same(ExtMachInst machInst); |
| // AdvSIMD three different |
| inline StaticInstPtr decodeNeon3Diff(ExtMachInst machInst); |
| // AdvSIMD two-reg misc |
| inline StaticInstPtr decodeNeon2RegMisc(ExtMachInst machInst); |
| // AdvSIMD across lanes |
| inline StaticInstPtr decodeNeonAcrossLanes(ExtMachInst machInst); |
| // AdvSIMD copy |
| inline StaticInstPtr decodeNeonCopy(ExtMachInst machInst); |
| // AdvSIMD vector x indexed element |
| template <typename DecoderFeatures> |
| StaticInstPtr decodeNeonIndexedElem(ExtMachInst machInst); |
| // AdvSIMD modified immediate |
| inline StaticInstPtr decodeNeonModImm(ExtMachInst machInst); |
| // AdvSIMD shift by immediate |
| inline StaticInstPtr decodeNeonShiftByImm(ExtMachInst machInst); |
| // AdvSIMD TBL/TBX |
| inline StaticInstPtr decodeNeonTblTbx(ExtMachInst machInst); |
| // AdvSIMD ZIP/UZP/TRN |
| inline StaticInstPtr decodeNeonZipUzpTrn(ExtMachInst machInst); |
| // AdvSIMD EXT |
| inline StaticInstPtr decodeNeonExt(ExtMachInst machInst); |
| |
| // AdvSIMD scalar three same |
| inline StaticInstPtr decodeNeonSc3Same(ExtMachInst machInst); |
| // AdvSIMD scalar three different |
| inline StaticInstPtr decodeNeonSc3Diff(ExtMachInst machInst); |
| // AdvSIMD scalar two-reg misc |
| inline StaticInstPtr decodeNeonSc2RegMisc(ExtMachInst machInst); |
| // AdvSIMD scalar pairwise |
| inline StaticInstPtr decodeNeonScPwise(ExtMachInst machInst); |
| // AdvSIMD scalar copy |
| inline StaticInstPtr decodeNeonScCopy(ExtMachInst machInst); |
| // AdvSIMD scalar x indexed element |
| inline StaticInstPtr decodeNeonScIndexedElem(ExtMachInst machInst); |
| // AdvSIMD scalar shift by immediate |
| inline StaticInstPtr decodeNeonScShiftByImm(ExtMachInst machInst); |
| |
| // AdvSIMD load/store |
| inline StaticInstPtr decodeNeonMem(ExtMachInst machInst); |
| } |
| }}; |
| |
| output decoder {{ |
| namespace Aarch64 |
| { |
| template <typename DecoderFeatures> |
| StaticInstPtr |
| decodeNeon3Same(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 15, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| uint8_t size_q = (size << 1) | q; |
| uint8_t sz_q = size_q & 0x3; |
| |
| switch (opcode) { |
| case 0x00: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UhaddDX, UhaddQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<ShaddDX, ShaddQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x01: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<UqaddDX, UqaddQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<SqaddDX, SqaddQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x02: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UrhaddDX, UrhaddQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SrhaddDX, SrhaddQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x03: |
| switch (size) { |
| case 0x0: |
| if (u) { |
| if (q) |
| return new EorQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new EorDX<uint64_t>(machInst, vd, vn, vm); |
| } else { |
| if (q) |
| return new AndQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new AndDX<uint64_t>(machInst, vd, vn, vm); |
| } |
| case 0x1: |
| if (u) { |
| if (q) |
| return new BslQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new BslDX<uint64_t>(machInst, vd, vn, vm); |
| } else { |
| if (q) |
| return new BicQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new BicDX<uint64_t>(machInst, vd, vn, vm); |
| } |
| case 0x2: |
| if (u) { |
| if (q) |
| return new BitQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new BitDX<uint64_t>(machInst, vd, vn, vm); |
| } else { |
| if (q) |
| return new OrrQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new OrrDX<uint64_t>(machInst, vd, vn, vm); |
| } |
| case 0x3: |
| if (u) { |
| if (q) |
| return new BifQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new BifDX<uint64_t>(machInst, vd, vn, vm); |
| } else { |
| if (q) |
| return new OrnQX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new OrnDX<uint64_t>(machInst, vd, vn, vm); |
| } |
| default: |
| M5_UNREACHABLE; |
| } |
| case 0x04: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UhsubDX, UhsubQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<ShsubDX, ShsubQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x05: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<UqsubDX, UqsubQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<SqsubDX, SqsubQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x06: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<CmhiDX, CmhiQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<CmgtDX, CmgtQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x07: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<CmhsDX, CmhsQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<CmgeDX, CmgeQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x08: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<UshlDX, UshlQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<SshlDX, SshlQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x09: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<UqshlDX, UqshlQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<SqshlDX, SqshlQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x0a: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<UrshlDX, UrshlQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<SrshlDX, SrshlQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x0b: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<UqrshlDX, UqrshlQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeXReg<SqrshlDX, SqrshlQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x0c: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UmaxDX, UmaxQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SmaxDX, SmaxQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x0d: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UminDX, UminQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SminDX, SminQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x0e: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UabdDX, UabdQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SabdDX, SabdQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x0f: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UabaDX, UabaQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SabaDX, SabaQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x10: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<SubDX, SubQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeXReg<AddDX, AddQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x11: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeXReg<CmeqDX, CmeqQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeXReg<CmtstDX, CmtstQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x12: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<MlsDX, MlsQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeSReg<MlaDX, MlaQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x13: |
| if (size == 0x3 || (size != 0x0 && bits(machInst, 29))) |
| return new Unknown64(machInst); |
| if (u) { |
| if (q) |
| return new PmulQX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new PmulDX<uint8_t>(machInst, vd, vn, vm); |
| } else { |
| return decodeNeonUThreeSReg<MulDX, MulQX>( |
| q, size, machInst, vd, vn, vm); |
| } |
| case 0x14: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UmaxpDX, UmaxpQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SmaxpDX, SmaxpQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x15: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UminpDX, UminpQX>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SminpDX, SminpQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x16: |
| if (size == 0x3 || size == 0x0) |
| return new Unknown64(machInst); |
| if (u) { |
| if (q) |
| return decodeNeonSThreeHAndWReg<SqrdmulhQX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeHAndWReg<SqrdmulhDX>( |
| size, machInst, vd, vn, vm); |
| } else { |
| if (q) |
| return decodeNeonSThreeHAndWReg<SqdmulhQX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeHAndWReg<SqdmulhDX>( |
| size, machInst, vd, vn, vm); |
| } |
| case 0x17: |
| if (u || size_q == 0x6) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeXReg<AddpDX, AddpQX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x18: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FmaxnmpDX, FmaxnmpQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FmaxnmDX, FmaxnmQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u) |
| return decodeNeonUThreeFpReg<FminnmpDX, FminnmpQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FminnmDX, FminnmQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } |
| case 0x19: |
| if (size < 0x2) { |
| if (u || sz_q == 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeFpReg<FmlaDX, FmlaQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u || sz_q == 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeFpReg<FmlsDX, FmlsQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } |
| case 0x1a: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FaddpDX, FaddpQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FaddDX, FaddQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u) |
| return decodeNeonUThreeFpReg<FabdDX, FabdQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FsubDX, FsubQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } |
| case 0x1b: |
| if (size < 0x2 && sz_q != 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FmulDX, FmulQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FmulxDX, FmulxQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0x1c: |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FcmgeDX, FcmgeQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FcmeqDX, FcmeqQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u) |
| return decodeNeonUThreeFpReg<FcmgtDX, FcmgtQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return new Unknown64(machInst); |
| } |
| case 0x1d: |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FacgeDX, FacgeQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return new Unknown64(machInst); |
| } else { |
| if (u) |
| return decodeNeonUThreeFpReg<FacgtDX, FacgtQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return new Unknown64(machInst); |
| } |
| case 0x1e: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FmaxpDX, FmaxpQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FmaxDX, FmaxQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u) |
| return decodeNeonUThreeFpReg<FminpDX, FminpQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FminDX, FminQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } |
| case 0x1f: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeFpReg<FdivDX, FdivQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeFpReg<FrecpsDX, FrecpsQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeFpReg<FrsqrtsDX, FrsqrtsQX>( |
| q, size & 0x1, machInst, vd, vn, vm); |
| } |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeon3Diff(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 15, 12); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| switch (opcode) { |
| case 0x0: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UaddlX, Uaddl2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SaddlX, Saddl2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x1: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UaddwX, Uaddw2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SaddwX, Saddw2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x2: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UsublX, Usubl2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SsublX, Ssubl2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x3: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UsubwX, Usubw2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SsubwX, Ssubw2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x4: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<RaddhnX, Raddhn2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeSReg<AddhnX, Addhn2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x5: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UabalX, Uabal2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SabalX, Sabal2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x6: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<RsubhnX, Rsubhn2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeSReg<SubhnX, Subhn2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x7: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UabdlX, Uabdl2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SabdlX, Sabdl2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x8: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UmlalX, Umlal2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SmlalX, Smlal2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0x9: |
| if (u || (size == 0x0 || size == 0x3)) { |
| return new Unknown64(machInst); |
| } else { |
| if (q) { |
| return decodeNeonSThreeHAndWReg<Sqdmlal2X>( |
| size, machInst, vd, vn, vm); |
| } else { |
| return decodeNeonSThreeHAndWReg<SqdmlalX>( |
| size, machInst, vd, vn, vm); |
| } |
| } |
| case 0xa: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UmlslX, Umlsl2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SmlslX, Smlsl2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0xb: |
| if (u || (size == 0x0 || size == 0x3)) { |
| return new Unknown64(machInst); |
| } else { |
| if (q) { |
| return decodeNeonSThreeHAndWReg<Sqdmlsl2X>( |
| size, machInst, vd, vn, vm); |
| } else { |
| return decodeNeonSThreeHAndWReg<SqdmlslX>( |
| size, machInst, vd, vn, vm); |
| } |
| } |
| case 0xc: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeSReg<UmullX, Umull2X>( |
| q, size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeSReg<SmullX, Smull2X>( |
| q, size, machInst, vd, vn, vm); |
| case 0xd: |
| if (u || (size == 0x0 || size == 0x3)) { |
| return new Unknown64(machInst); |
| } else { |
| if (q) { |
| return decodeNeonSThreeHAndWReg<Sqdmull2X>( |
| size, machInst, vd, vn, vm); |
| } else { |
| return decodeNeonSThreeHAndWReg<SqdmullX>( |
| size, machInst, vd, vn, vm); |
| } |
| } |
| case 0xe: |
| if (u || size != 0) { |
| return new Unknown64(machInst); |
| } else { |
| if (q) |
| return new Pmull2X<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new PmullX<uint8_t>(machInst, vd, vn, vm); |
| } |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeon2RegMisc(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 16, 12); |
| |
| IntRegIndex vd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); |
| |
| uint8_t size_q = (size << 1) | q; |
| uint8_t sz_q = size_q & 0x3; |
| uint8_t op = (uint8_t)((bits(machInst, 12) << 1) | |
| bits(machInst, 29)); |
| uint8_t switchVal = opcode | ((u ? 1 : 0) << 5); |
| |
| switch (switchVal) { |
| case 0x00: |
| if (op + size >= 3) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscSReg<Rev64DX, Rev64QX>( |
| q, size, machInst, vd, vn); |
| case 0x01: |
| if (op + size >= 3) |
| return new Unknown64(machInst); |
| if (q) |
| return new Rev16QX<uint8_t>(machInst, vd, vn); |
| else |
| return new Rev16DX<uint8_t>(machInst, vd, vn); |
| case 0x02: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscSReg<SaddlpDX, SaddlpQX>( |
| q, size, machInst, vd, vn); |
| case 0x03: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscXReg<SuqaddDX, SuqaddQX>( |
| q, size, machInst, vd, vn); |
| case 0x04: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscSReg<ClsDX, ClsQX>( |
| q, size, machInst, vd, vn); |
| case 0x05: |
| if (size != 0x0) |
| return new Unknown64(machInst); |
| if (q) |
| return new CntQX<uint8_t>(machInst, vd, vn); |
| else |
| return new CntDX<uint8_t>(machInst, vd, vn); |
| case 0x06: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscSReg<SadalpDX, SadalpQX>( |
| q, size, machInst, vd, vn); |
| case 0x07: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<SqabsDX, SqabsQX>( |
| q, size, machInst, vd, vn); |
| case 0x08: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<CmgtZeroDX, CmgtZeroQX>( |
| q, size, machInst, vd, vn); |
| case 0x09: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<CmeqZeroDX, CmeqZeroQX>( |
| q, size, machInst, vd, vn); |
| case 0x0a: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<CmltZeroDX, CmltZeroQX>( |
| q, size, machInst, vd, vn); |
| case 0x0b: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<AbsDX, AbsQX>( |
| q, size, machInst, vd, vn); |
| case 0x0c: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FcmgtZeroDX, FcmgtZeroQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x0d: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FcmeqZeroDX, FcmeqZeroQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x0e: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FcmltZeroDX, FcmltZeroQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x0f: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FabsDX, FabsQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x12: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscSReg<XtnX, Xtn2X>( |
| q, size, machInst, vd, vn); |
| case 0x14: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscSReg<SqxtnX, Sqxtn2X>( |
| q, size, machInst, vd, vn); |
| case 0x16: |
| if (size > 0x1) |
| return new Unknown64(machInst); |
| if (q) { |
| if (size) |
| return new Fcvtn2X<uint32_t>(machInst, vd, vn); |
| else |
| return new Fcvtn2X<uint16_t>(machInst, vd, vn); |
| } else { |
| if (size) |
| return new FcvtnX<uint32_t>(machInst, vd, vn); |
| else |
| return new FcvtnX<uint16_t>(machInst, vd, vn); |
| } |
| case 0x17: |
| if (size > 0x1) |
| return new Unknown64(machInst); |
| if (q) { |
| if (size) |
| return new Fcvtl2X<uint32_t>(machInst, vd, vn); |
| else |
| return new Fcvtl2X<uint16_t>(machInst, vd, vn); |
| } else { |
| if (size) |
| return new FcvtlX<uint32_t>(machInst, vd, vn); |
| else |
| return new FcvtlX<uint16_t>(machInst, vd, vn); |
| } |
| case 0x18: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FrintnDX, FrintnQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FrintpDX, FrintpQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x19: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FrintmDX, FrintmQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FrintzDX, FrintzQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x1a: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FcvtnsDX, FcvtnsQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FcvtpsDX, FcvtpsQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x1b: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FcvtmsDX, FcvtmsQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FcvtzsIntDX, FcvtzsIntQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x1c: |
| if (size < 0x2) { |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FcvtasDX, FcvtasQX>( |
| q, size & 0x1, machInst, vd, vn); |
| } else { |
| if (size & 0x1) |
| return new Unknown64(machInst); |
| if (q) |
| return new UrecpeQX<uint32_t>(machInst, vd, vn); |
| else |
| return new UrecpeDX<uint32_t>(machInst, vd, vn); |
| } |
| case 0x1d: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (q) { |
| if (size & 0x1) |
| return new ScvtfIntDQX<uint64_t>(machInst, vd, vn); |
| else |
| return new ScvtfIntSQX<uint32_t>(machInst, vd, vn); |
| } else { |
| if (size & 0x1) |
| return new Unknown(machInst); |
| else |
| return new ScvtfIntDX<uint32_t>(machInst, vd, vn); |
| } |
| } else { |
| return decodeNeonUTwoMiscFpReg<FrecpeDX, FrecpeQX>( |
| q, size & 0x1, machInst, vd, vn); |
| } |
| case 0x20: |
| if (op + size >= 3) |
| return new Unknown64(machInst); |
| if (q) { |
| if (size & 0x1) |
| return new Rev32QX<uint16_t>(machInst, vd, vn); |
| else |
| return new Rev32QX<uint8_t>(machInst, vd, vn); |
| } else { |
| if (size & 0x1) |
| return new Rev32DX<uint16_t>(machInst, vd, vn); |
| else |
| return new Rev32DX<uint8_t>(machInst, vd, vn); |
| } |
| case 0x22: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscSReg<UaddlpDX, UaddlpQX>( |
| q, size, machInst, vd, vn); |
| case 0x23: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscXReg<UsqaddDX, UsqaddQX>( |
| q, size, machInst, vd, vn); |
| return new Unknown64(machInst); |
| case 0x24: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscSReg<ClzDX, ClzQX>( |
| q, size, machInst, vd, vn); |
| case 0x25: |
| if (size == 0x0) { |
| if (q) |
| return new MvnQX<uint64_t>(machInst, vd, vn); |
| else |
| return new MvnDX<uint64_t>(machInst, vd, vn); |
| } else if (size == 0x1) { |
| if (q) |
| return new RbitQX<uint8_t>(machInst, vd, vn); |
| else |
| return new RbitDX<uint8_t>(machInst, vd, vn); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0x26: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscSReg<UadalpDX, UadalpQX>( |
| q, size, machInst, vd, vn); |
| case 0x27: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<SqnegDX, SqnegQX>( |
| q, size, machInst, vd, vn); |
| case 0x28: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<CmgeZeroDX, CmgeZeroQX>( |
| q, size, machInst, vd, vn); |
| case 0x29: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<CmleZeroDX, CmleZeroQX>( |
| q, size, machInst, vd, vn); |
| case 0x2b: |
| if (size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscXReg<NegDX, NegQX>( |
| q, size, machInst, vd, vn); |
| case 0x2c: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FcmgeZeroDX, FcmgeZeroQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x2d: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FcmleZeroDX, FcmleZeroQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x2f: |
| if (size < 0x2 || size_q == 0x6) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FnegDX, FnegQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x32: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSTwoMiscSReg<SqxtunX, Sqxtun2X>( |
| q, size, machInst, vd, vn); |
| case 0x33: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscSReg<ShllX, Shll2X>( |
| q, size, machInst, vd, vn); |
| case 0x34: |
| if (size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscSReg<UqxtnX, Uqxtn2X>( |
| q, size, machInst, vd, vn); |
| case 0x36: |
| if (size != 0x1) |
| return new Unknown64(machInst); |
| if (q) |
| return new Fcvtxn2X<uint32_t>(machInst, vd, vn); |
| else |
| return new FcvtxnX<uint32_t>(machInst, vd, vn); |
| case 0x38: |
| if (size > 0x1 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FrintaDX, FrintaQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x39: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FrintxDX, FrintxQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FrintiDX, FrintiQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x3a: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FcvtnuDX, FcvtnuQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FcvtpuDX, FcvtpuQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x3b: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<FcvtmuDX, FcvtmuQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FcvtzuIntDX, FcvtzuIntQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x3c: |
| if (size < 0x2) { |
| return decodeNeonUTwoMiscFpReg<FcvtauDX, FcvtauQX>( |
| q, size & 0x1, machInst, vd, vn); |
| } else if (size == 0x2) { |
| if (q) |
| return new UrsqrteQX<uint32_t>(machInst, vd, vn); |
| else |
| return new UrsqrteDX<uint32_t>(machInst, vd, vn); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0x3d: |
| if (sz_q == 0x2) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUTwoMiscFpReg<UcvtfIntDX, UcvtfIntQX>( |
| q, size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscFpReg<FrsqrteDX, FrsqrteQX>( |
| q, size & 0x1, machInst, vd, vn); |
| case 0x3f: |
| if (size < 0x2 || sz_q == 0x2) |
| return new Unknown64(machInst); |
| return decodeNeonUTwoMiscFpReg<FsqrtDX, FsqrtQX>( |
| q, size & 0x1, machInst, vd, vn); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonAcrossLanes(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 16, 12); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| uint8_t size_q = (size << 1) | q; |
| uint8_t sz_q = size_q & 0x3; |
| uint8_t switchVal = opcode | ((u ? 1 : 0) << 5); |
| |
| switch (switchVal) { |
| case 0x03: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSAcrossLanesLongReg<SaddlvDX, SaddlvQX, |
| SaddlvBQX>( |
| q, size, machInst, vd, vn); |
| case 0x0a: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSAcrossLanesReg<SmaxvDX, SmaxvQX>( |
| q, size, machInst, vd, vn); |
| case 0x1a: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonSAcrossLanesReg<SminvDX, SminvQX>( |
| q, size, machInst, vd, vn); |
| case 0x1b: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUAcrossLanesReg<AddvDX, AddvQX>( |
| q, size, machInst, vd, vn); |
| case 0x23: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUAcrossLanesLongReg<UaddlvDX, UaddlvQX, |
| UaddlvBQX>( |
| q, size, machInst, vd, vn); |
| case 0x2a: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUAcrossLanesReg<UmaxvDX, UmaxvQX>( |
| q, size, machInst, vd, vn); |
| case 0x2c: |
| if (sz_q != 0x1) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (q) |
| return new FmaxnmvQX<uint32_t>(machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| } else { |
| if (q) |
| return new FminnmvQX<uint32_t>(machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| } |
| case 0x2f: |
| if (sz_q != 0x1) |
| return new Unknown64(machInst); |
| if (size < 0x2) { |
| if (q) |
| return new FmaxvQX<uint32_t>(machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| } else { |
| if (q) |
| return new FminvQX<uint32_t>(machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| } |
| case 0x3a: |
| if (size_q == 0x4 || size == 0x3) |
| return new Unknown64(machInst); |
| return decodeNeonUAcrossLanesReg<UminvDX, UminvQX>( |
| q, size, machInst, vd, vn); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonCopy(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t op = bits(machInst, 29); |
| uint8_t imm5 = bits(machInst, 20, 16); |
| uint8_t imm4 = bits(machInst, 14, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| uint8_t imm5_pos = findLsbSet(imm5); |
| uint8_t index1 = 0, index2 = 0; |
| |
| if (op) { |
| if (!q || (imm4 & mask(imm5_pos))) |
| return new Unknown64(machInst); |
| |
| index1 = bits(imm5, 4, imm5_pos + 1); // dst |
| index2 = bits(imm4, 3, imm5_pos); // src |
| |
| switch (imm5_pos) { |
| case 0: |
| return new InsElemX<uint8_t>(machInst, vd, vn, index1, index2); |
| case 1: |
| return new InsElemX<uint16_t>(machInst, vd, vn, index1, index2); |
| case 2: |
| return new InsElemX<uint32_t>(machInst, vd, vn, index1, index2); |
| case 3: |
| return new InsElemX<uint64_t>(machInst, vd, vn, index1, index2); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| switch (imm4) { |
| case 0x0: |
| index1 = bits(imm5, 4, imm5_pos + 1); |
| switch (imm5_pos) { |
| case 0: |
| if (q) |
| return new DupElemQX<uint8_t>(machInst, vd, vn, index1); |
| else |
| return new DupElemDX<uint8_t>(machInst, vd, vn, index1); |
| case 1: |
| if (q) |
| return new DupElemQX<uint16_t>(machInst, vd, vn, index1); |
| else |
| return new DupElemDX<uint16_t>(machInst, vd, vn, index1); |
| case 2: |
| if (q) |
| return new DupElemQX<uint32_t>(machInst, vd, vn, index1); |
| else |
| return new DupElemDX<uint32_t>(machInst, vd, vn, index1); |
| case 3: |
| if (q) |
| return new DupElemQX<uint64_t>(machInst, vd, vn, index1); |
| else |
| return new Unknown64(machInst); |
| default: |
| return new Unknown64(machInst); |
| } |
| case 0x1: |
| switch (imm5) { |
| case 0x1: |
| if (q) |
| return new DupGprWQX<uint8_t>(machInst, vd, vn); |
| else |
| return new DupGprWDX<uint8_t>(machInst, vd, vn); |
| case 0x2: |
| if (q) |
| return new DupGprWQX<uint16_t>(machInst, vd, vn); |
| else |
| return new DupGprWDX<uint16_t>(machInst, vd, vn); |
| case 0x4: |
| if (q) |
| return new DupGprWQX<uint32_t>(machInst, vd, vn); |
| else |
| return new DupGprWDX<uint32_t>(machInst, vd, vn); |
| case 0x8: |
| if (q) |
| return new DupGprXQX<uint64_t>(machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| default: |
| return new Unknown64(machInst); |
| } |
| case 0x3: |
| index1 = imm5 >> (imm5_pos + 1); |
| switch (imm5_pos) { |
| case 0: |
| return new InsGprWX<uint8_t>(machInst, vd, vn, index1); |
| case 1: |
| return new InsGprWX<uint16_t>(machInst, vd, vn, index1); |
| case 2: |
| return new InsGprWX<uint32_t>(machInst, vd, vn, index1); |
| case 3: |
| return new InsGprXX<uint64_t>(machInst, vd, vn, index1); |
| default: |
| return new Unknown64(machInst); |
| } |
| case 0x5: |
| index1 = bits(imm5, 4, imm5_pos + 1); |
| switch (imm5_pos) { |
| case 0: |
| if (q) |
| return new SmovXX<int8_t>(machInst, vd, vn, index1); |
| else |
| return new SmovWX<int8_t>(machInst, vd, vn, index1); |
| case 1: |
| if (q) |
| return new SmovXX<int16_t>(machInst, vd, vn, index1); |
| else |
| return new SmovWX<int16_t>(machInst, vd, vn, index1); |
| case 2: |
| if (q) |
| return new SmovXX<int32_t>(machInst, vd, vn, index1); |
| else |
| return new Unknown64(machInst); |
| default: |
| return new Unknown64(machInst); |
| } |
| case 0x7: |
| index1 = imm5 >> (imm5_pos + 1); |
| |
| if ((q && imm5_pos != 3) || (!q && imm5_pos >= 3)) |
| return new Unknown64(machInst); |
| |
| switch (imm5_pos) { |
| case 0: |
| return new UmovWX<uint8_t>(machInst, vd, vn, index1); |
| case 1: |
| return new UmovWX<uint16_t>(machInst, vd, vn, index1); |
| case 2: |
| return new UmovWX<uint32_t>(machInst, vd, vn, index1); |
| case 3: |
| return new UmovXX<uint64_t>(machInst, vd, vn, index1); |
| default: |
| return new Unknown64(machInst); |
| } |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| template <typename DecoderFeatures> |
| StaticInstPtr |
| decodeNeonIndexedElem(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t L = bits(machInst, 21); |
| uint8_t M = bits(machInst, 20); |
| uint8_t opcode = bits(machInst, 15, 12); |
| uint8_t H = bits(machInst, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm_bf = (IntRegIndex) (uint8_t) bits(machInst, 19, 16); |
| |
| uint8_t index = 0; |
| uint8_t index_fp = 0; |
| uint8_t vmh = 0; |
| uint8_t sz = size & 0x1; |
| uint8_t sz_q = (sz << 1) | bits(machInst, 30); |
| uint8_t sz_L = (sz << 1) | L; |
| |
| // Index and 2nd register operand for integer instructions |
| if (size == 0x1) { |
| index = (H << 2) | (L << 1) | M; |
| // vmh = 0; |
| } else if (size == 0x2) { |
| index = (H << 1) | L; |
| vmh = M; |
| } |
| IntRegIndex vm = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); |
| |
| // Index and 2nd register operand for FP instructions |
| vmh = M; |
| if ((size & 0x1) == 0) { |
| index_fp = (H << 1) | L; |
| } else if (L == 0) { |
| index_fp = H; |
| } |
| IntRegIndex vm_fp = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); |
| |
| switch (opcode) { |
| case 0x0: |
| if (!u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeImmHAndWReg<MlaElemDX, MlaElemQX>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0x1: |
| if (!u && size >= 2 && sz_q != 0x2 && sz_L != 0x3) |
| return decodeNeonUThreeImmFpReg<FmlaElemDX, FmlaElemQX>( |
| q, sz, machInst, vd, vn, vm_fp, index_fp); |
| else |
| return new Unknown64(machInst); |
| case 0x2: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeImmHAndWReg<UmlalElemX, UmlalElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| else |
| return decodeNeonSThreeImmHAndWReg<SmlalElemX, SmlalElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0x3: |
| if (u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmlalElemX, |
| SqdmlalElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0x4: |
| if (u && !(size == 0x0 || size == 0x3)) |
| return decodeNeonUThreeImmHAndWReg<MlsElemDX, MlsElemQX>( |
| q, size, machInst, vd, vn, vm, index); |
| else |
| return new Unknown64(machInst); |
| case 0x5: |
| if (!u && size >= 0x2 && sz_L != 0x3 && sz_q != 0x2) |
| return decodeNeonUThreeImmFpReg<FmlsElemDX, FmlsElemQX>( |
| q, sz, machInst, vd, vn, vm_fp, index_fp); |
| else |
| return new Unknown64(machInst); |
| case 0x6: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeImmHAndWReg<UmlslElemX, UmlslElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| else |
| return decodeNeonSThreeImmHAndWReg<SmlslElemX, SmlslElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0x7: |
| if (u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmlslElemX, |
| SqdmlslElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0x8: |
| if (u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeImmHAndWReg<MulElemDX, MulElemQX>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0x9: |
| if (size >= 2 && sz_q != 0x2 && sz_L != 0x3) { |
| if (u) |
| return decodeNeonUThreeImmFpReg<FmulxElemDX, FmulxElemQX>( |
| q, sz, machInst, vd, vn, vm_fp, index_fp); |
| else |
| return decodeNeonUThreeImmFpReg<FmulElemDX, FmulElemQX>( |
| q, sz, machInst, vd, vn, vm_fp, index_fp); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0xa: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeImmHAndWReg<UmullElemX, UmullElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| else |
| return decodeNeonSThreeImmHAndWReg<SmullElemX, SmullElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0xb: |
| if (u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmullElemX, SqdmullElem2X>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0xc: |
| if (u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmulhElemDX, SqdmulhElemQX>( |
| q, size, machInst, vd, vn, vm, index); |
| case 0xd: |
| if (u || (size == 0x0 || size == 0x3)) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqrdmulhElemDX, SqrdmulhElemQX>( |
| q, size, machInst, vd, vn, vm, index); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonModImm(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t op = bits(machInst, 29); |
| uint8_t abcdefgh = (bits(machInst, 18, 16) << 5) | |
| bits(machInst, 9, 5); |
| uint8_t cmode = bits(machInst, 15, 12); |
| uint8_t o2 = bits(machInst, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| |
| if (o2 == 0x1 || (op == 0x1 && cmode == 0xf && !q)) |
| return new Unknown64(machInst); |
| |
| bool immValid = true; |
| const uint64_t bigImm = simd_modified_imm(op, cmode, abcdefgh, |
| immValid, |
| true /* isAarch64 */); |
| if (!immValid) { |
| return new Unknown(machInst); |
| } |
| |
| if (op) { |
| if (bits(cmode, 3) == 0) { |
| if (bits(cmode, 0) == 0) { |
| if (q) |
| return new MvniQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MvniDX<uint64_t>(machInst, vd, bigImm); |
| } else { |
| if (q) |
| return new BicImmQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new BicImmDX<uint64_t>(machInst, vd, bigImm); |
| } |
| } else { |
| if (bits(cmode, 2) == 1) { |
| switch (bits(cmode, 1, 0)) { |
| case 0: |
| case 1: |
| if (q) |
| return new MvniQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MvniDX<uint64_t>(machInst, vd, bigImm); |
| case 2: |
| if (q) |
| return new MoviQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MoviDX<uint64_t>(machInst, vd, bigImm); |
| case 3: |
| if (q) |
| return new FmovQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MoviDX<uint64_t>(machInst, vd, bigImm); |
| } |
| } else { |
| if (bits(cmode, 0) == 0) { |
| if (q) |
| return new MvniQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MvniDX<uint64_t>(machInst, vd, bigImm); |
| } else { |
| if (q) |
| return new BicImmQX<uint64_t>(machInst, vd, |
| bigImm); |
| else |
| return new BicImmDX<uint64_t>(machInst, vd, |
| bigImm); |
| } |
| } |
| } |
| } else { |
| if (bits(cmode, 3) == 0) { |
| if (bits(cmode, 0) == 0) { |
| if (q) |
| return new MoviQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MoviDX<uint64_t>(machInst, vd, bigImm); |
| } else { |
| if (q) |
| return new OrrImmQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new OrrImmDX<uint64_t>(machInst, vd, bigImm); |
| } |
| } else { |
| if (bits(cmode, 2) == 1) { |
| if (bits(cmode, 1, 0) == 0x3) { |
| if (q) |
| return new FmovQX<uint32_t>(machInst, vd, bigImm); |
| else |
| return new FmovDX<uint32_t>(machInst, vd, bigImm); |
| } else { |
| if (q) |
| return new MoviQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MoviDX<uint64_t>(machInst, vd, bigImm); |
| } |
| } else { |
| if (bits(cmode, 0) == 0) { |
| if (q) |
| return new MoviQX<uint64_t>(machInst, vd, bigImm); |
| else |
| return new MoviDX<uint64_t>(machInst, vd, bigImm); |
| } else { |
| if (q) |
| return new OrrImmQX<uint64_t>(machInst, vd, |
| bigImm); |
| else |
| return new OrrImmDX<uint64_t>(machInst, vd, bigImm); |
| } |
| } |
| } |
| } |
| return new Unknown(machInst); |
| } |
| |
| StaticInstPtr |
| decodeNeonShiftByImm(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t u = bits(machInst, 29); |
| uint8_t immh = bits(machInst, 22, 19); |
| uint8_t immb = bits(machInst, 18, 16); |
| uint8_t opcode = bits(machInst, 15, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| uint8_t immh3 = bits(machInst, 22); |
| uint8_t immh3_q = (immh3 << 1) | q; |
| uint8_t op_u = (bits(machInst, 12) << 1) | u; |
| uint8_t size = findMsbSet(immh); |
| int shiftAmt = 0; |
| |
| switch (opcode) { |
| case 0x00: |
| if (immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftXReg<UshrDX, UshrQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftXReg<SshrDX, SshrQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x02: |
| if (immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftXReg<UsraDX, UsraQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftXReg<SsraDX, SsraQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x04: |
| if (immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftXReg<UrshrDX, UrshrQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftXReg<SrshrDX, SrshrQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x06: |
| if (immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftXReg<UrsraDX, UrsraQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftXReg<SrsraDX, SrsraQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x08: |
| if (u && !(immh3_q == 0x2)) { |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| return decodeNeonUTwoShiftXReg<SriDX, SriQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0x0a: |
| if (immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| if (u) |
| return decodeNeonUTwoShiftXReg<SliDX, SliQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonUTwoShiftXReg<ShlDX, ShlQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x0c: |
| if (u && !(immh3_q == 0x2 || op_u == 0x0)) { |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| return decodeNeonSTwoShiftXReg<SqshluDX, SqshluQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0x0e: |
| if (immh3_q == 0x2 || op_u == 0x0) |
| return new Unknown64(machInst); |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| if (u) |
| return decodeNeonUTwoShiftXReg<UqshlImmDX, UqshlImmQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftXReg<SqshlImmDX, SqshlImmQX>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x10: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonSTwoShiftSReg<SqshrunX, Sqshrun2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonUTwoShiftSReg<ShrnX, Shrn2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x11: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonSTwoShiftSReg<SqrshrunX, Sqrshrun2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonUTwoShiftSReg<RshrnX, Rshrn2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x12: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftSReg<UqshrnX, Uqshrn2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftSReg<SqshrnX, Sqshrn2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x13: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftSReg<UqrshrnX, Uqrshrn2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftSReg<SqrshrnX, Sqrshrn2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x14: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| if (u) |
| return decodeNeonUTwoShiftSReg<UshllX, Ushll2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftSReg<SshllX, Sshll2X>( |
| q, size, machInst, vd, vn, shiftAmt); |
| case 0x1c: |
| if (immh < 0x4 || immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) { |
| return decodeNeonUTwoShiftFpReg<UcvtfFixedDX, UcvtfFixedQX>( |
| q, size & 0x1, machInst, vd, vn, shiftAmt); |
| } else { |
| if (q) { |
| if (size & 0x1) |
| return new ScvtfFixedDQX<uint64_t>(machInst, vd, vn, |
| shiftAmt); |
| else |
| return new ScvtfFixedSQX<uint32_t>(machInst, vd, vn, |
| shiftAmt); |
| } else { |
| if (size & 0x1) |
| return new Unknown(machInst); |
| else |
| return new ScvtfFixedDX<uint32_t>(machInst, vd, vn, |
| shiftAmt); |
| } |
| } |
| case 0x1f: |
| if (immh < 0x4 || immh3_q == 0x2) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftFpReg<FcvtzuFixedDX, FcvtzuFixedQX>( |
| q, size & 0x1, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonUTwoShiftFpReg<FcvtzsFixedDX, FcvtzsFixedQX>( |
| q, size & 0x1, machInst, vd, vn, shiftAmt); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonTblTbx(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| uint8_t switchVal = bits(machInst, 14, 12); |
| |
| switch (switchVal) { |
| case 0x0: |
| if (q) |
| return new Tbl1QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbl1DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x1: |
| if (q) |
| return new Tbx1QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbx1DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x2: |
| if (q) |
| return new Tbl2QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbl2DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x3: |
| if (q) |
| return new Tbx2QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbx2DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x4: |
| if (q) |
| return new Tbl3QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbl3DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x5: |
| if (q) |
| return new Tbx3QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbx3DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x6: |
| if (q) |
| return new Tbl4QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbl4DX<uint8_t>(machInst, vd, vn, vm); |
| case 0x7: |
| if (q) |
| return new Tbx4QX<uint8_t>(machInst, vd, vn, vm); |
| else |
| return new Tbx4DX<uint8_t>(machInst, vd, vn, vm); |
| default: |
| return new Unknown64(machInst); |
| } |
| |
| return new Unknown64(machInst); |
| } |
| |
| StaticInstPtr |
| decodeNeonZipUzpTrn(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 14, 12); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| switch (opcode) { |
| case 0x1: |
| return decodeNeonUThreeXReg<Uzp1DX, Uzp1QX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x2: |
| return decodeNeonUThreeXReg<Trn1DX, Trn1QX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x3: |
| return decodeNeonUThreeXReg<Zip1DX, Zip1QX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x5: |
| return decodeNeonUThreeXReg<Uzp2DX, Uzp2QX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x6: |
| return decodeNeonUThreeXReg<Trn2DX, Trn2QX>( |
| q, size, machInst, vd, vn, vm); |
| case 0x7: |
| return decodeNeonUThreeXReg<Zip2DX, Zip2QX>( |
| q, size, machInst, vd, vn, vm); |
| default: |
| return new Unknown64(machInst); |
| } |
| return new Unknown64(machInst); |
| } |
| |
| StaticInstPtr |
| decodeNeonExt(ExtMachInst machInst) |
| { |
| uint8_t q = bits(machInst, 30); |
| uint8_t op2 = bits(machInst, 23, 22); |
| uint8_t imm4 = bits(machInst, 14, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| if (op2 != 0 || (q == 0x0 && bits(imm4, 3) == 0x1)) |
| return new Unknown64(machInst); |
| |
| uint8_t index = q ? imm4 : imm4 & 0x7; |
| |
| if (q) { |
| return new ExtQX<uint8_t>(machInst, vd, vn, vm, index); |
| } else { |
| return new ExtDX<uint8_t>(machInst, vd, vn, vm, index); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonSc3Same(ExtMachInst machInst) |
| { |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 15, 11); |
| uint8_t s = bits(machInst, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| switch (opcode) { |
| case 0x01: |
| if (u) |
| return decodeNeonUThreeUReg<UqaddScX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeUReg<SqaddScX>( |
| size, machInst, vd, vn, vm); |
| case 0x05: |
| if (u) |
| return decodeNeonUThreeUReg<UqsubScX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeUReg<SqsubScX>( |
| size, machInst, vd, vn, vm); |
| case 0x06: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return new CmhiDX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new CmgtDX<int64_t>(machInst, vd, vn, vm); |
| case 0x07: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return new CmhsDX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new CmgeDX<int64_t>(machInst, vd, vn, vm); |
| case 0x08: |
| if (!s && size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return new UshlDX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new SshlDX<int64_t>(machInst, vd, vn, vm); |
| case 0x09: |
| if (!s && size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeUReg<UqshlScX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeUReg<SqshlScX>( |
| size, machInst, vd, vn, vm); |
| case 0x0a: |
| if (!s && size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return new UrshlDX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new SrshlDX<int64_t>(machInst, vd, vn, vm); |
| case 0x0b: |
| if (!s && size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeUReg<UqrshlScX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeUReg<SqrshlScX>( |
| size, machInst, vd, vn, vm); |
| case 0x10: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return new SubDX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new AddDX<uint64_t>(machInst, vd, vn, vm); |
| case 0x11: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return new CmeqDX<uint64_t>(machInst, vd, vn, vm); |
| else |
| return new CmtstDX<uint64_t>(machInst, vd, vn, vm); |
| case 0x16: |
| if (size == 0x3 || size == 0x0) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonSThreeHAndWReg<SqrdmulhScX>( |
| size, machInst, vd, vn, vm); |
| else |
| return decodeNeonSThreeHAndWReg<SqdmulhScX>( |
| size, machInst, vd, vn, vm); |
| case 0x1a: |
| if (!u || size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeScFpReg<FabdScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| case 0x1b: |
| if (u || size > 0x1) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeScFpReg<FmulxScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| case 0x1c: |
| if (size < 0x2) { |
| if (u) |
| return decodeNeonUThreeScFpReg<FcmgeScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeScFpReg<FcmeqScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| } else { |
| if (u) |
| return decodeNeonUThreeScFpReg<FcmgtScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| else |
| return new Unknown64(machInst); |
| } |
| case 0x1d: |
| if (!u) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUThreeScFpReg<FacgeScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeScFpReg<FacgtScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| case 0x1f: |
| if (u) |
| return new Unknown64(machInst); |
| if (size < 0x2) |
| return decodeNeonUThreeScFpReg<FrecpsScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| else |
| return decodeNeonUThreeScFpReg<FrsqrtsScX>( |
| size & 0x1, machInst, vd, vn, vm); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonSc3Diff(ExtMachInst machInst) |
| { |
| if (bits(machInst, 29)) |
| return new Unknown64(machInst); |
| |
| uint8_t size = bits(machInst, 23, 22); |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| |
| uint8_t opcode = bits(machInst, 15, 12); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| switch (opcode) { |
| case 0x9: |
| return decodeNeonSThreeHAndWReg<SqdmlalScX>(size, machInst, vd, vn, vm); |
| case 0xb: |
| return decodeNeonSThreeHAndWReg<SqdmlslScX>(size, machInst, vd, vn, vm); |
| case 0xd: |
| return decodeNeonSThreeHAndWReg<SqdmullScX>(size, machInst, vd, vn, vm); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonSc2RegMisc(ExtMachInst machInst) |
| { |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 16, 12); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| uint8_t switchVal = opcode | ((u ? 1 : 0) << 5); |
| switch (switchVal) { |
| case 0x03: |
| return decodeNeonUTwoMiscUReg<SuqaddScX>(size, machInst, vd, vn); |
| case 0x07: |
| return decodeNeonSTwoMiscUReg<SqabsScX>(size, machInst, vd, vn); |
| case 0x08: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new CmgtZeroDX<int64_t>(machInst, vd, vn); |
| case 0x09: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new CmeqZeroDX<int64_t>(machInst, vd, vn); |
| case 0x0a: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new CmltZeroDX<int64_t>(machInst, vd, vn); |
| case 0x0b: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new AbsDX<int64_t>(machInst, vd, vn); |
| case 0x0c: |
| if (size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcmgtZeroScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x0d: |
| if (size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcmeqZeroScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x0e: |
| if (size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcmltZeroScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x14: |
| switch (size) { |
| case 0x0: |
| return new SqxtnScX<int8_t>(machInst, vd, vn); |
| case 0x1: |
| return new SqxtnScX<int16_t>(machInst, vd, vn); |
| case 0x2: |
| return new SqxtnScX<int32_t>(machInst, vd, vn); |
| case 0x3: |
| return new Unknown64(machInst); |
| default: |
| M5_UNREACHABLE; |
| } |
| case 0x1a: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<FcvtnsScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcvtpsScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x1b: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<FcvtmsScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcvtzsIntScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x1c: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<FcvtasScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| case 0x1d: |
| if (size < 0x2) { |
| if (size & 0x1) |
| return new ScvtfIntScDX<uint64_t>(machInst, vd, vn); |
| else |
| return new ScvtfIntScSX<uint32_t>(machInst, vd, vn); |
| } else { |
| return decodeNeonUTwoMiscScFpReg<FrecpeScX>( |
| size & 0x1, machInst, vd, vn); |
| } |
| case 0x1f: |
| if (size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUTwoMiscScFpReg<FrecpxX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x23: |
| return decodeNeonUTwoMiscUReg<UsqaddScX>(size, machInst, vd, vn); |
| case 0x27: |
| return decodeNeonSTwoMiscUReg<SqnegScX>(size, machInst, vd, vn); |
| case 0x28: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new CmgeZeroDX<int64_t>(machInst, vd, vn); |
| case 0x29: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new CmleZeroDX<int64_t>(machInst, vd, vn); |
| case 0x2b: |
| if (size != 0x3) |
| return new Unknown64(machInst); |
| else |
| return new NegDX<int64_t>(machInst, vd, vn); |
| case 0x2c: |
| if (size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcmgeZeroScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x2d: |
| if (size < 0x2) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcmleZeroScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x32: |
| switch (size) { |
| case 0x0: |
| return new SqxtunScX<int8_t>(machInst, vd, vn); |
| case 0x1: |
| return new SqxtunScX<int16_t>(machInst, vd, vn); |
| case 0x2: |
| return new SqxtunScX<int32_t>(machInst, vd, vn); |
| case 0x3: |
| return new Unknown64(machInst); |
| default: |
| M5_UNREACHABLE; |
| } |
| case 0x34: |
| switch (size) { |
| case 0x0: |
| return new UqxtnScX<uint8_t>(machInst, vd, vn); |
| case 0x1: |
| return new UqxtnScX<uint16_t>(machInst, vd, vn); |
| case 0x2: |
| return new UqxtnScX<uint32_t>(machInst, vd, vn); |
| case 0x3: |
| return new Unknown64(machInst); |
| default: |
| M5_UNREACHABLE; |
| } |
| case 0x36: |
| if (size != 0x1) { |
| return new Unknown64(machInst); |
| } else { |
| return new FcvtxnScX<uint32_t>(machInst, vd, vn); |
| } |
| case 0x3a: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<FcvtnuScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcvtpuScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x3b: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<FcvtmuScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscScFpReg<FcvtzuIntScX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x3c: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<FcvtauScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| case 0x3d: |
| if (size < 0x2) |
| return decodeNeonUTwoMiscScFpReg<UcvtfIntScX>( |
| size & 0x1, machInst, vd, vn); |
| else |
| return decodeNeonUTwoMiscScFpReg<FrsqrteScX>( |
| size & 0x1, machInst, vd, vn); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonScPwise(ExtMachInst machInst) |
| { |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t opcode = bits(machInst, 16, 12); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| if (!u) { |
| if (opcode == 0x1b && size == 0x3) |
| return new AddpScQX<uint64_t>(machInst, vd, vn); |
| else |
| return new Unknown64(machInst); |
| } |
| |
| uint8_t switchVal = (opcode << 0) | (size << 5); |
| switch (switchVal) { |
| case 0x0c: |
| case 0x2c: |
| return decodeNeonUTwoMiscPwiseScFpReg<FmaxnmpScDX, FmaxnmpScQX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x0d: |
| case 0x2d: |
| return decodeNeonUTwoMiscPwiseScFpReg<FaddpScDX, FaddpScQX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x0f: |
| case 0x2f: |
| return decodeNeonUTwoMiscPwiseScFpReg<FmaxpScDX, FmaxpScQX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x4c: |
| case 0x6c: |
| return decodeNeonUTwoMiscPwiseScFpReg<FminnmpScDX, FminnmpScQX>( |
| size & 0x1, machInst, vd, vn); |
| case 0x4f: |
| case 0x6f: |
| return decodeNeonUTwoMiscPwiseScFpReg<FminpScDX, FminpScQX>( |
| size & 0x1, machInst, vd, vn); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonScCopy(ExtMachInst machInst) |
| { |
| if (bits(machInst, 14, 11) != 0 || bits(machInst, 29)) |
| return new Unknown64(machInst); |
| |
| uint8_t imm5 = bits(machInst, 20, 16); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| uint8_t size = findLsbSet(imm5); |
| uint8_t index = bits(imm5, 4, size + 1); |
| |
| return decodeNeonUTwoShiftUReg<DupElemScX>( |
| size, machInst, vd, vn, index); |
| } |
| |
| StaticInstPtr |
| decodeNeonScIndexedElem(ExtMachInst machInst) |
| { |
| uint8_t u = bits(machInst, 29); |
| uint8_t size = bits(machInst, 23, 22); |
| uint8_t L = bits(machInst, 21); |
| uint8_t M = bits(machInst, 20); |
| uint8_t opcode = bits(machInst, 15, 12); |
| uint8_t H = bits(machInst, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex vm_bf = (IntRegIndex) (uint8_t) bits(machInst, 19, 16); |
| |
| uint8_t index = 0; |
| uint8_t index_fp = 0; |
| uint8_t vmh = 0; |
| uint8_t sz_L = bits(machInst, 22, 21); |
| |
| // Index and 2nd register operand for integer instructions |
| if (size == 0x1) { |
| index = (H << 2) | (L << 1) | M; |
| // vmh = 0; |
| } else if (size == 0x2) { |
| index = (H << 1) | L; |
| vmh = M; |
| } else if (size == 0x3) { |
| index = H; |
| vmh = M; |
| } |
| IntRegIndex vm = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); |
| |
| // Index and 2nd register operand for FP instructions |
| vmh = M; |
| if ((size & 0x1) == 0) { |
| index_fp = (H << 1) | L; |
| } else if (L == 0) { |
| index_fp = H; |
| } |
| IntRegIndex vm_fp = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); |
| |
| if (u && opcode != 9) |
| return new Unknown64(machInst); |
| |
| switch (opcode) { |
| case 0x1: |
| if (size < 2 || sz_L == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeImmScFpReg<FmlaElemScX>( |
| size & 0x1, machInst, vd, vn, vm_fp, index_fp); |
| case 0x3: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmlalElemScX>( |
| size, machInst, vd, vn, vm, index); |
| case 0x5: |
| if (size < 2 || sz_L == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonUThreeImmScFpReg<FmlsElemScX>( |
| size & 0x1, machInst, vd, vn, vm_fp, index_fp); |
| case 0x7: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmlslElemScX>( |
| size, machInst, vd, vn, vm, index); |
| case 0x9: |
| if (size < 2 || sz_L == 0x3) |
| return new Unknown64(machInst); |
| if (u) |
| return decodeNeonUThreeImmScFpReg<FmulxElemScX>( |
| size & 0x1, machInst, vd, vn, vm_fp, index_fp); |
| else |
| return decodeNeonUThreeImmScFpReg<FmulElemScX>( |
| size & 0x1, machInst, vd, vn, vm_fp, index_fp); |
| case 0xb: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmullElemScX>( |
| size, machInst, vd, vn, vm, index); |
| case 0xc: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqdmulhElemScX>( |
| size, machInst, vd, vn, vm, index); |
| case 0xd: |
| if (size == 0x0 || size == 0x3) |
| return new Unknown64(machInst); |
| else |
| return decodeNeonSThreeImmHAndWReg<SqrdmulhElemScX>( |
| size, machInst, vd, vn, vm, index); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonScShiftByImm(ExtMachInst machInst) |
| { |
| bool u = bits(machInst, 29); |
| uint8_t immh = bits(machInst, 22, 19); |
| uint8_t immb = bits(machInst, 18, 16); |
| uint8_t opcode = bits(machInst, 15, 11); |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| |
| uint8_t immh3 = bits(machInst, 22); |
| uint8_t size = findMsbSet(immh); |
| int shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| |
| if (immh == 0x0) |
| return new Unknown64(machInst); |
| |
| switch (opcode) { |
| case 0x00: |
| if (!immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return new UshrDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| else |
| return new SshrDX<int64_t>(machInst, vd, vn, shiftAmt); |
| case 0x02: |
| if (!immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return new UsraDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| else |
| return new SsraDX<int64_t>(machInst, vd, vn, shiftAmt); |
| case 0x04: |
| if (!immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return new UrshrDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| else |
| return new SrshrDX<int64_t>(machInst, vd, vn, shiftAmt); |
| case 0x06: |
| if (!immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return new UrsraDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| else |
| return new SrsraDX<int64_t>(machInst, vd, vn, shiftAmt); |
| case 0x08: |
| if (!immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return new SriDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| else |
| return new Unknown64(machInst); |
| case 0x0a: |
| if (!immh3) |
| return new Unknown64(machInst); |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| if (u) |
| return new SliDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| else |
| return new ShlDX<uint64_t>(machInst, vd, vn, shiftAmt); |
| case 0x0c: |
| if (u) { |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| return decodeNeonSTwoShiftUReg<SqshluScX>( |
| size, machInst, vd, vn, shiftAmt); |
| } else { |
| return new Unknown64(machInst); |
| } |
| case 0x0e: |
| shiftAmt = ((immh << 3) | immb) - (8 << size); |
| if (u) |
| return decodeNeonUTwoShiftUReg<UqshlImmScX>( |
| size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftUReg<SqshlImmScX>( |
| size, machInst, vd, vn, shiftAmt); |
| case 0x10: |
| if (!u || immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| return decodeNeonSTwoShiftUSReg<SqshrunScX>( |
| size, machInst, vd, vn, shiftAmt); |
| case 0x11: |
| if (!u || immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| return decodeNeonSTwoShiftUSReg<SqrshrunScX>( |
| size, machInst, vd, vn, shiftAmt); |
| case 0x12: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftUSReg<UqshrnScX>( |
| size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftUSReg<SqshrnScX>( |
| size, machInst, vd, vn, shiftAmt); |
| case 0x13: |
| if (immh3) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftUSReg<UqrshrnScX>( |
| size, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonSTwoShiftUSReg<SqrshrnScX>( |
| size, machInst, vd, vn, shiftAmt); |
| case 0x1c: |
| if (immh < 0x4) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) { |
| return decodeNeonUTwoShiftUFpReg<UcvtfFixedScX>( |
| size & 0x1, machInst, vd, vn, shiftAmt); |
| } else { |
| if (size & 0x1) |
| return new ScvtfFixedScDX<uint64_t>(machInst, vd, vn, |
| shiftAmt); |
| else |
| return new ScvtfFixedScSX<uint32_t>(machInst, vd, vn, |
| shiftAmt); |
| } |
| case 0x1f: |
| if (immh < 0x4) |
| return new Unknown64(machInst); |
| shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); |
| if (u) |
| return decodeNeonUTwoShiftUFpReg<FcvtzuFixedScX>( |
| size & 0x1, machInst, vd, vn, shiftAmt); |
| else |
| return decodeNeonUTwoShiftUFpReg<FcvtzsFixedScX>( |
| size & 0x1, machInst, vd, vn, shiftAmt); |
| default: |
| return new Unknown64(machInst); |
| } |
| } |
| |
| StaticInstPtr |
| decodeNeonMem(ExtMachInst machInst) |
| { |
| uint8_t dataSize = bits(machInst, 30) ? 128 : 64; |
| bool multiple = bits(machInst, 24, 23) < 0x2; |
| bool load = bits(machInst, 22); |
| |
| uint8_t numStructElems = 0; |
| uint8_t numRegs = 0; |
| |
| if (multiple) { // AdvSIMD load/store multiple structures |
| uint8_t opcode = bits(machInst, 15, 12); |
| uint8_t eSize = bits(machInst, 11, 10); |
| bool wb = !(bits(machInst, 20, 16) == 0x0 && !bits(machInst, 23)); |
| |
| switch (opcode) { |
| case 0x0: // LD/ST4 (4 regs) |
| numStructElems = 4; |
| numRegs = 4; |
| break; |
| case 0x2: // LD/ST1 (4 regs) |
| numStructElems = 1; |
| numRegs = 4; |
| break; |
| case 0x4: // LD/ST3 (3 regs) |
| numStructElems = 3; |
| numRegs = 3; |
| break; |
| case 0x6: // LD/ST1 (3 regs) |
| numStructElems = 1; |
| numRegs = 3; |
| break; |
| case 0x7: // LD/ST1 (1 reg) |
| numStructElems = 1; |
| numRegs = 1; |
| break; |
| case 0x8: // LD/ST2 (2 regs) |
| numStructElems = 2; |
| numRegs = 2; |
| break; |
| case 0xa: // LD/ST1 (2 regs) |
| numStructElems = 1; |
| numRegs = 2; |
| break; |
| default: |
| return new Unknown64(machInst); |
| } |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex rn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex rm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| if (load) { |
| return new VldMult64(machInst, rn, vd, rm, eSize, dataSize, |
| numStructElems, numRegs, wb); |
| } else { |
| return new VstMult64(machInst, rn, vd, rm, eSize, dataSize, |
| numStructElems, numRegs, wb); |
| } |
| } else { // AdvSIMD load/store single structure |
| uint8_t scale = bits(machInst, 15, 14); |
| uint8_t numStructElems = (((uint8_t) bits(machInst, 13) << 1) | |
| (uint8_t) bits(machInst, 21)) + 1; |
| uint8_t index = 0; |
| bool wb = !(bits(machInst, 20, 16) == 0x0 && !bits(machInst, 23)); |
| bool replicate = false; |
| |
| switch (scale) { |
| case 0x0: |
| index = ((uint8_t) bits(machInst, 30) << 3) | |
| ((uint8_t) bits(machInst, 12) << 2) | |
| (uint8_t) bits(machInst, 11, 10); |
| break; |
| case 0x1: |
| index = ((uint8_t) bits(machInst, 30) << 2) | |
| ((uint8_t) bits(machInst, 12) << 1) | |
| (uint8_t) bits(machInst, 11); |
| break; |
| case 0x2: |
| if (bits(machInst, 10) == 0x0) { |
| index = ((uint8_t) bits(machInst, 30) << 1) | |
| bits(machInst, 12); |
| } else { |
| index = (uint8_t) bits(machInst, 30); |
| scale = 0x3; |
| } |
| break; |
| case 0x3: |
| scale = bits(machInst, 11, 10); |
| replicate = true; |
| break; |
| default: |
| return new Unknown64(machInst); |
| } |
| |
| uint8_t eSize = scale; |
| |
| IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); |
| IntRegIndex rn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); |
| IntRegIndex rm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); |
| |
| if (load) { |
| return new VldSingle64(machInst, rn, vd, rm, eSize, dataSize, |
| numStructElems, index, wb, replicate); |
| } else { |
| return new VstSingle64(machInst, rn, vd, rm, eSize, dataSize, |
| numStructElems, index, wb, replicate); |
| } |
| } |
| } |
| } |
| }}; |