gem5/src/arch/arm/isa/formats/fp.isa
Matt Horsnell adbd84ab9f ARM: The ARM decoder should not panic when decoding undefined holes is arch.
This can abort simulations when the fetch unit runs ahead and speculatively
decodes instructions that are off the execution path.
2011-01-18 16:30:05 -06:00

2513 lines
97 KiB
C++

// -*- 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
//
output header {{
template<template <typename T> class Base>
StaticInstPtr
newNeonMemInst(const unsigned size,
const ExtMachInst &machInst,
const RegIndex dest, const RegIndex ra,
const uint32_t imm, const unsigned extraMemFlags)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, ra, imm, extraMemFlags);
case 1:
return new Base<uint16_t>(machInst, dest, ra, imm, extraMemFlags);
case 2:
return new Base<uint32_t>(machInst, dest, ra, imm, extraMemFlags);
case 3:
return new Base<uint64_t>(machInst, dest, ra, imm, extraMemFlags);
default:
panic("Unrecognized width %d for Neon mem inst.\n", (1 << size));
}
}
template<template <typename T> class Base>
StaticInstPtr
newNeonMixInst(const unsigned size,
const ExtMachInst &machInst,
const RegIndex dest, const RegIndex op1,
const uint32_t step)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, step);
case 1:
return new Base<uint16_t>(machInst, dest, op1, step);
case 2:
return new Base<uint32_t>(machInst, dest, op1, step);
case 3:
return new Base<uint64_t>(machInst, dest, op1, step);
default:
panic("Unrecognized width %d for Neon mem inst.\n", (1 << size));
}
}
}};
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 single = bits(machInst, 23);
const bool singleAll = single && (bits(b, 3, 2) == 3);
const bool load = bits(machInst, 21);
unsigned width = 0;
if (single) {
width = bits(b, 1, 0) + 1;
} else {
switch (bits(b, 3, 1)) {
case 0x0: width = 4;
break;
case 0x1: width = (b & 0x1) ? 2 : 1;
break;
case 0x2: width = 3;
break;
case 0x3: width = 1;
break;
case 0x4: width = 2;
break;
case 0x5:
if ((b & 0x1) == 0) {
width = 1;
break;
}
// Fall through on purpose.
default:
return new Unknown(machInst);
}
}
assert(width > 0 && width <= 4);
const RegIndex rm = (RegIndex)(uint32_t)bits(machInst, 3, 0);
const RegIndex rn = (RegIndex)(uint32_t)bits(machInst, 19, 16);
const RegIndex vd = (RegIndex)(uint32_t)(bits(machInst, 15, 12) |
bits(machInst, 22) << 4);
const uint32_t type = bits(machInst, 11, 8);
uint32_t size = 0;
uint32_t align = 0;
unsigned inc = 1;
unsigned regs = 1;
unsigned lane = 0;
if (single) {
if (singleAll) {
size = bits(machInst, 7, 6);
bool t = bits(machInst, 5);
unsigned eBytes = (1 << size);
align = (eBytes - 1) | TLB::AllowUnaligned;
if (width == 1) {
regs = t ? 2 : 1;
inc = 1;
} else {
regs = width;
inc = t ? 2 : 1;
}
switch (width) {
case 1:
case 2:
if (bits(machInst, 4))
align = width * eBytes - 1;
break;
case 3:
break;
case 4:
if (size == 3) {
if (bits(machInst, 4) == 0)
return new Unknown(machInst);
size = 2;
align = 0xf;
} else if (size == 2) {
if (bits(machInst, 4))
align = 7;
} else {
if (bits(machInst, 4))
align = 4 * eBytes - 1;
}
break;
}
} else {
size = bits(machInst, 11, 10);
unsigned eBytes = (1 << size);
align = (eBytes - 1) | TLB::AllowUnaligned;
regs = width;
unsigned indexAlign = bits(machInst, 7, 4);
// If width is 1, inc is always 1. That's overridden later.
switch (size) {
case 0:
inc = 1;
lane = bits(indexAlign, 3, 1);
break;
case 1:
inc = bits(indexAlign, 1) ? 2 : 1;
lane = bits(indexAlign, 3, 2);
break;
case 2:
inc = bits(indexAlign, 2) ? 2 : 1;
lane = bits(indexAlign, 3);
break;
}
// Override inc for width of 1.
if (width == 1) {
inc = 1;
}
switch (width) {
case 1:
switch (size) {
case 0:
break;
case 1:
if (bits(indexAlign, 0))
align = 1;
break;
case 2:
if (bits(indexAlign, 1, 0))
align = 3;
break;
}
break;
case 2:
if (bits(indexAlign, 0))
align = (2 * eBytes) - 1;
break;
case 3:
break;
case 4:
switch (size) {
case 0:
case 1:
if (bits(indexAlign, 0))
align = (4 * eBytes) - 1;
break;
case 2:
if (bits(indexAlign, 0))
align = (4 << bits(indexAlign, 1, 0)) - 1;
break;
}
break;
}
}
if (size == 0x3) {
return new Unknown(machInst);
}
} else {
size = bits(machInst, 7, 6);
align = bits(machInst, 5, 4);
if (align == 0) {
// @align wasn't specified, so alignment can be turned off.
align = ((1 << size) - 1) | TLB::AllowUnaligned;
} else {
align = ((4 << align) - 1);
}
switch (width) {
case 1:
switch (type) {
case 0x7: regs = 1;
break;
case 0xa: regs = 2;
break;
case 0x6: regs = 3;
break;
case 0x2: regs = 4;
break;
default:
return new Unknown(machInst);
}
break;
case 2:
// Regs doesn't behave exactly as it does in the manual
// because they loop over regs registers twice and we break
// it down in the macroop.
switch (type) {
case 0x8: regs = 2; inc = 1;
break;
case 0x9: regs = 2; inc = 2;
break;
case 0x3: regs = 4; inc = 2;
break;
default:
return new Unknown(machInst);
}
break;
case 3:
regs = 3;
switch (type) {
case 0x4: inc = 1;
break;
case 0x5: inc = 2;;
break;
default:
return new Unknown(machInst);
}
break;
case 4:
regs = 4;
switch (type) {
case 0: inc = 1;
break;
case 1: inc = 2;
break;
default:
return new Unknown(machInst);
}
break;
}
}
if (load) {
// Load instructions.
if (single) {
return new VldSingle(machInst, singleAll, width, rn, vd,
regs, inc, size, align, rm, lane);
} else {
return new VldMult(machInst, width, rn, vd,
regs, inc, size, align, rm);
}
} else {
// Store instructions.
if (single) {
if (singleAll) {
return new Unknown(machInst);
} else {
return new VstSingle(machInst, false, width, rn, vd,
regs, inc, size, align, rm, lane);
}
} else {
return new VstMult(machInst, width, rn, vd,
regs, inc, size, align, rm);
}
}
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);
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vn =
(IntRegIndex)(2 * (bits(machInst, 19, 16) |
(bits(machInst, 7) << 4)));
const IntRegIndex vm =
(IntRegIndex)(2 * (bits(machInst, 3, 0) |
(bits(machInst, 5) << 4)));
const unsigned size = bits(machInst, 21, 20);
const bool q = bits(machInst, 6);
if (q && ((vd & 0x1) || (vn & 0x1) || (vm & 0x1)))
return new Unknown(machInst);
switch (a) {
case 0x0:
if (b) {
if (u) {
return decodeNeonUThreeReg<VqaddUD, VqaddUQ>(
q, size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeReg<VqaddSD, VqaddSQ>(
q, size, machInst, vd, vn, vm);
}
} else {
if (size == 3)
return new Unknown(machInst);
return decodeNeonUSThreeReg<VhaddD, VhaddQ>(
q, u, size, machInst, vd, vn, vm);
}
case 0x1:
if (!b) {
return decodeNeonUSThreeReg<VrhaddD, VrhaddQ>(
q, u, size, machInst, vd, vn, vm);
} else {
if (u) {
switch (c) {
case 0:
if (q) {
return new VeorQ<uint64_t>(machInst, vd, vn, vm);
} else {
return new VeorD<uint64_t>(machInst, vd, vn, vm);
}
case 1:
if (q) {
return new VbslQ<uint64_t>(machInst, vd, vn, vm);
} else {
return new VbslD<uint64_t>(machInst, vd, vn, vm);
}
case 2:
if (q) {
return new VbitQ<uint64_t>(machInst, vd, vn, vm);
} else {
return new VbitD<uint64_t>(machInst, vd, vn, vm);
}
case 3:
if (q) {
return new VbifQ<uint64_t>(machInst, vd, vn, vm);
} else {
return new VbifD<uint64_t>(machInst, vd, vn, vm);
}
}
} else {
switch (c) {
case 0:
if (q) {
return new VandQ<uint64_t>(machInst, vd, vn, vm);
} else {
return new VandD<uint64_t>(machInst, vd, vn, vm);
}
case 1:
if (q) {
return new VbicQ<uint64_t>(machInst, vd, vn, vm);
} else {
return new VbicD<uint64_t>(machInst, vd, vn, vm);
}
case 2:
if (vn == vm) {
if (q) {
return new VmovQ<uint64_t>(
machInst, vd, vn, vm);
} else {
return new VmovD<uint64_t>(
machInst, vd, vn, vm);
}
} else {
if (q) {
return new VorrQ<uint64_t>(
machInst, vd, vn, vm);
} else {
return new VorrD<uint64_t>(
machInst, vd, vn, vm);
}
}
case 3:
if (q) {
return new VornQ<uint64_t>(
machInst, vd, vn, vm);
} else {
return new VornD<uint64_t>(
machInst, vd, vn, vm);
}
}
}
}
case 0x2:
if (b) {
if (u) {
return decodeNeonUThreeReg<VqsubUD, VqsubUQ>(
q, size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeReg<VqsubSD, VqsubSQ>(
q, size, machInst, vd, vn, vm);
}
} else {
if (size == 3)
return new Unknown(machInst);
return decodeNeonUSThreeReg<VhsubD, VhsubQ>(
q, u, size, machInst, vd, vn, vm);
}
case 0x3:
if (b) {
return decodeNeonUSThreeReg<VcgeD, VcgeQ>(
q, u, size, machInst, vd, vn, vm);
} else {
return decodeNeonUSThreeReg<VcgtD, VcgtQ>(
q, u, size, machInst, vd, vn, vm);
}
case 0x4:
if (b) {
if (u) {
return decodeNeonUThreeReg<VqshlUD, VqshlUQ>(
q, size, machInst, vd, vm, vn);
} else {
return decodeNeonSThreeReg<VqshlSD, VqshlSQ>(
q, size, machInst, vd, vm, vn);
}
} else {
return decodeNeonUSThreeReg<VshlD, VshlQ>(
q, u, size, machInst, vd, vm, vn);
}
case 0x5:
if (b) {
if (u) {
return decodeNeonUThreeReg<VqrshlUD, VqrshlUQ>(
q, size, machInst, vd, vm, vn);
} else {
return decodeNeonSThreeReg<VqrshlSD, VqrshlSQ>(
q, size, machInst, vd, vm, vn);
}
} else {
return decodeNeonUSThreeReg<VrshlD, VrshlQ>(
q, u, size, machInst, vd, vm, vn);
}
case 0x6:
if (b) {
return decodeNeonUSThreeReg<VminD, VminQ>(
q, u, size, machInst, vd, vn, vm);
} else {
return decodeNeonUSThreeReg<VmaxD, VmaxQ>(
q, u, size, machInst, vd, vn, vm);
}
case 0x7:
if (b) {
return decodeNeonUSThreeReg<VabaD, VabaQ>(
q, u, size, machInst, vd, vn, vm);
} else {
if (bits(machInst, 23) == 1) {
if (q) {
return new Unknown(machInst);
} else {
return decodeNeonUSThreeUSReg<Vabdl>(
u, size, machInst, vd, vn, vm);
}
} else {
return decodeNeonUSThreeReg<VabdD, VabdQ>(
q, u, size, machInst, vd, vn, vm);
}
}
case 0x8:
if (b) {
if (u) {
return decodeNeonUThreeReg<VceqD, VceqQ>(
q, size, machInst, vd, vn, vm);
} else {
return decodeNeonUThreeReg<VtstD, VtstQ>(
q, size, machInst, vd, vn, vm);
}
} else {
if (u) {
return decodeNeonUThreeReg<NVsubD, NVsubQ>(
q, size, machInst, vd, vn, vm);
} else {
return decodeNeonUThreeReg<NVaddD, NVaddQ>(
q, size, machInst, vd, vn, vm);
}
}
case 0x9:
if (b) {
if (u) {
return decodeNeonUThreeReg<NVmulpD, NVmulpQ>(
q, size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeReg<NVmulD, NVmulQ>(
q, size, machInst, vd, vn, vm);
}
} else {
if (u) {
return decodeNeonUSThreeReg<NVmlsD, NVmlsQ>(
q, u, size, machInst, vd, vn, vm);
} else {
return decodeNeonUSThreeReg<NVmlaD, NVmlaQ>(
q, u, size, machInst, vd, vn, vm);
}
}
case 0xa:
if (b) {
return decodeNeonUSThreeReg<VpminD, VpminQ>(
q, u, size, machInst, vd, vn, vm);
} else {
return decodeNeonUSThreeReg<VpmaxD, VpmaxQ>(
q, u, size, machInst, vd, vn, vm);
}
case 0xb:
if (b) {
if (u) {
return new Unknown(machInst);
} else {
return decodeNeonUThreeReg<NVpaddD, NVpaddQ>(
q, size, machInst, vd, vn, vm);
}
} else {
if (u) {
return decodeNeonSThreeSReg<VqrdmulhD, VqrdmulhQ>(
q, size, machInst, vd, vn, vm);
} else {
return decodeNeonSThreeSReg<VqdmulhD, VqdmulhQ>(
q, size, machInst, vd, vn, vm);
}
}
case 0xc:
return new Unknown(machInst);
case 0xd:
if (b) {
if (u) {
if (bits(c, 1) == 0) {
if (q) {
return new NVmulQFp<float>(machInst, vd, vn, vm);
} else {
return new NVmulDFp<float>(machInst, vd, vn, vm);
}
} else {
return new Unknown(machInst);
}
} else {
if (bits(c, 1) == 0) {
if (q) {
return new NVmlaQFp<float>(machInst, vd, vn, vm);
} else {
return new NVmlaDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new NVmlsQFp<float>(machInst, vd, vn, vm);
} else {
return new NVmlsDFp<float>(machInst, vd, vn, vm);
}
}
}
} else {
if (u) {
if (bits(c, 1) == 0) {
if (q) {
return new VpaddQFp<float>(machInst, vd, vn, vm);
} else {
return new VpaddDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VabdQFp<float>(machInst, vd, vn, vm);
} else {
return new VabdDFp<float>(machInst, vd, vn, vm);
}
}
} else {
if (bits(c, 1) == 0) {
if (q) {
return new VaddQFp<float>(machInst, vd, vn, vm);
} else {
return new VaddDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VsubQFp<float>(machInst, vd, vn, vm);
} else {
return new VsubDFp<float>(machInst, vd, vn, vm);
}
}
}
}
case 0xe:
if (b) {
if (u) {
if (bits(c, 1) == 0) {
if (q) {
return new VacgeQFp<float>(machInst, vd, vn, vm);
} else {
return new VacgeDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VacgtQFp<float>(machInst, vd, vn, vm);
} else {
return new VacgtDFp<float>(machInst, vd, vn, vm);
}
}
} else {
return new Unknown(machInst);
}
} else {
if (u) {
if (bits(c, 1) == 0) {
if (q) {
return new VcgeQFp<float>(machInst, vd, vn, vm);
} else {
return new VcgeDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VcgtQFp<float>(machInst, vd, vn, vm);
} else {
return new VcgtDFp<float>(machInst, vd, vn, vm);
}
}
} else {
if (bits(c, 1) == 0) {
if (q) {
return new VceqQFp<float>(machInst, vd, vn, vm);
} else {
return new VceqDFp<float>(machInst, vd, vn, vm);
}
} else {
return new Unknown(machInst);
}
}
}
case 0xf:
if (b) {
if (u) {
return new Unknown(machInst);
} else {
if (bits(c, 1) == 0) {
if (q) {
return new VrecpsQFp<float>(machInst, vd, vn, vm);
} else {
return new VrecpsDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VrsqrtsQFp<float>(machInst, vd, vn, vm);
} else {
return new VrsqrtsDFp<float>(machInst, vd, vn, vm);
}
}
}
} else {
if (u) {
if (bits(c, 1) == 0) {
if (q) {
return new VpmaxQFp<float>(machInst, vd, vn, vm);
} else {
return new VpmaxDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VpminQFp<float>(machInst, vd, vn, vm);
} else {
return new VpminDFp<float>(machInst, vd, vn, vm);
}
}
} else {
if (bits(c, 1) == 0) {
if (q) {
return new VmaxQFp<float>(machInst, vd, vn, vm);
} else {
return new VmaxDFp<float>(machInst, vd, vn, vm);
}
} else {
if (q) {
return new VminQFp<float>(machInst, vd, vn, vm);
} else {
return new VminDFp<float>(machInst, vd, vn, vm);
}
}
}
}
}
return new Unknown(machInst);
}
static StaticInstPtr
decodeNeonOneRegModImm(ExtMachInst machInst)
{
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const bool q = bits(machInst, 6);
const bool op = bits(machInst, 5);
const uint8_t cmode = bits(machInst, 11, 8);
const uint8_t imm = ((THUMB ? bits(machInst, 28) :
bits(machInst, 24)) << 7) |
(bits(machInst, 18, 16) << 4) |
(bits(machInst, 3, 0) << 0);
// Check for invalid immediate encodings and return an unknown op
// if it happens
bool immValid = true;
const uint64_t bigImm = simd_modified_imm(op, cmode, imm, immValid);
if (!immValid) {
return new Unknown(machInst);
}
if (op) {
if (bits(cmode, 3) == 0) {
if (bits(cmode, 0) == 0) {
if (q)
return new NVmvniQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmvniD<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new NVbiciQ<uint64_t>(machInst, vd, bigImm);
else
return new NVbiciD<uint64_t>(machInst, vd, bigImm);
}
} else {
if (bits(cmode, 2) == 1) {
switch (bits(cmode, 1, 0)) {
case 0:
case 1:
if (q)
return new NVmvniQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmvniD<uint64_t>(machInst, vd, bigImm);
case 2:
if (q)
return new NVmoviQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmoviD<uint64_t>(machInst, vd, bigImm);
case 3:
if (q)
return new Unknown(machInst);
else
return new Unknown(machInst);
}
} else {
if (bits(cmode, 0) == 0) {
if (q)
return new NVmvniQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmvniD<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new NVbiciQ<uint64_t>(machInst, vd, bigImm);
else
return new NVbiciD<uint64_t>(machInst, vd, bigImm);
}
}
}
} else {
if (bits(cmode, 3) == 0) {
if (bits(cmode, 0) == 0) {
if (q)
return new NVmoviQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmoviD<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new NVorriQ<uint64_t>(machInst, vd, bigImm);
else
return new NVorriD<uint64_t>(machInst, vd, bigImm);
}
} else {
if (bits(cmode, 2) == 1) {
if (q)
return new NVmoviQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmoviD<uint64_t>(machInst, vd, bigImm);
} else {
if (bits(cmode, 0) == 0) {
if (q)
return new NVmoviQ<uint64_t>(machInst, vd, bigImm);
else
return new NVmoviD<uint64_t>(machInst, vd, bigImm);
} else {
if (q)
return new NVorriQ<uint64_t>(machInst, vd, bigImm);
else
return new NVorriD<uint64_t>(machInst, vd, bigImm);
}
}
}
}
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);
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vm =
(IntRegIndex)(2 * (bits(machInst, 3, 0) |
(bits(machInst, 5) << 4)));
unsigned imm6 = bits(machInst, 21, 16);
unsigned imm = ((l ? 1 : 0) << 6) | imm6;
unsigned size = 3;
unsigned lShiftAmt = 0;
unsigned bitSel;
for (bitSel = 1 << 6; true; bitSel >>= 1) {
if (bitSel & imm)
break;
else if (!size)
return new Unknown(machInst);
size--;
}
lShiftAmt = imm6 & ~bitSel;
unsigned rShiftAmt = 0;
if (a != 0xe && a != 0xf) {
if (size > 2)
rShiftAmt = 64 - imm6;
else
rShiftAmt = 2 * (8 << size) - imm6;
}
switch (a) {
case 0x0:
return decodeNeonUSTwoShiftReg<NVshrD, NVshrQ>(
b, u, size, machInst, vd, vm, rShiftAmt);
case 0x1:
return decodeNeonUSTwoShiftReg<NVsraD, NVsraQ>(
b, u, size, machInst, vd, vm, rShiftAmt);
case 0x2:
return decodeNeonUSTwoShiftReg<NVrshrD, NVrshrQ>(
b, u, size, machInst, vd, vm, rShiftAmt);
case 0x3:
return decodeNeonUSTwoShiftReg<NVrsraD, NVrsraQ>(
b, u, size, machInst, vd, vm, rShiftAmt);
case 0x4:
if (u) {
return decodeNeonUTwoShiftReg<NVsriD, NVsriQ>(
b, size, machInst, vd, vm, rShiftAmt);
} else {
return new Unknown(machInst);
}
case 0x5:
if (u) {
return decodeNeonUTwoShiftReg<NVsliD, NVsliQ>(
b, size, machInst, vd, vm, lShiftAmt);
} else {
return decodeNeonUTwoShiftReg<NVshlD, NVshlQ>(
b, size, machInst, vd, vm, lShiftAmt);
}
case 0x6:
case 0x7:
if (u) {
if (a == 0x6) {
return decodeNeonSTwoShiftReg<NVqshlusD, NVqshlusQ>(
b, size, machInst, vd, vm, lShiftAmt);
} else {
return decodeNeonUTwoShiftReg<NVqshluD, NVqshluQ>(
b, size, machInst, vd, vm, lShiftAmt);
}
} else {
return decodeNeonSTwoShiftReg<NVqshlD, NVqshlQ>(
b, size, machInst, vd, vm, lShiftAmt);
}
case 0x8:
if (l) {
return new Unknown(machInst);
} else if (u) {
return decodeNeonSTwoShiftSReg<NVqshruns, NVqrshruns>(
b, size, machInst, vd, vm, rShiftAmt);
} else {
return decodeNeonUTwoShiftSReg<NVshrn, NVrshrn>(
b, size, machInst, vd, vm, rShiftAmt);
}
case 0x9:
if (l) {
return new Unknown(machInst);
} else if (u) {
return decodeNeonUTwoShiftSReg<NVqshrun, NVqrshrun>(
b, size, machInst, vd, vm, rShiftAmt);
} else {
return decodeNeonSTwoShiftSReg<NVqshrn, NVqrshrn>(
b, size, machInst, vd, vm, rShiftAmt);
}
case 0xa:
if (l || b) {
return new Unknown(machInst);
} else {
return decodeNeonUSTwoShiftSReg<NVmovl, NVshll>(
lShiftAmt, u, size, machInst, vd, vm, lShiftAmt);
}
case 0xe:
if (l) {
return new Unknown(machInst);
} else {
if (bits(imm6, 5) == 0)
return new Unknown(machInst);
if (u) {
if (b) {
return new NVcvtu2fpQ<float>(
machInst, vd, vm, 64 - imm6);
} else {
return new NVcvtu2fpD<float>(
machInst, vd, vm, 64 - imm6);
}
} else {
if (b) {
return new NVcvts2fpQ<float>(
machInst, vd, vm, 64 - imm6);
} else {
return new NVcvts2fpD<float>(
machInst, vd, vm, 64 - imm6);
}
}
}
case 0xf:
if (l) {
return new Unknown(machInst);
} else {
if (bits(imm6, 5) == 0)
return new Unknown(machInst);
if (u) {
if (b) {
return new NVcvt2ufxQ<float>(
machInst, vd, vm, 64 - imm6);
} else {
return new NVcvt2ufxD<float>(
machInst, vd, vm, 64 - imm6);
}
} else {
if (b) {
return new NVcvt2sfxQ<float>(
machInst, vd, vm, 64 - imm6);
} else {
return new NVcvt2sfxD<float>(
machInst, vd, vm, 64 - imm6);
}
}
}
}
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);
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vn =
(IntRegIndex)(2 * (bits(machInst, 19, 16) |
(bits(machInst, 7) << 4)));
const IntRegIndex vm =
(IntRegIndex)(2 * (bits(machInst, 3, 0) |
(bits(machInst, 5) << 4)));
const unsigned size = bits(machInst, 21, 20);
switch (a) {
case 0x0:
return decodeNeonUSThreeUSReg<Vaddl>(
u, size, machInst, vd, vn, vm);
case 0x1:
return decodeNeonUSThreeUSReg<Vaddw>(
u, size, machInst, vd, vn, vm);
case 0x2:
return decodeNeonUSThreeUSReg<Vsubl>(
u, size, machInst, vd, vn, vm);
case 0x3:
return decodeNeonUSThreeUSReg<Vsubw>(
u, size, machInst, vd, vn, vm);
case 0x4:
if (u) {
return decodeNeonUThreeUSReg<Vraddhn>(
size, machInst, vd, vn, vm);
} else {
return decodeNeonUThreeUSReg<Vaddhn>(
size, machInst, vd, vn, vm);
}
case 0x5:
return decodeNeonUSThreeUSReg<Vabal>(
u, size, machInst, vd, vn, vm);
case 0x6:
if (u) {
return decodeNeonUThreeUSReg<Vrsubhn>(
size, machInst, vd, vn, vm);
} else {
return decodeNeonUThreeUSReg<Vsubhn>(
size, machInst, vd, vn, vm);
}
case 0x7:
if (bits(machInst, 23)) {
return decodeNeonUSThreeUSReg<Vabdl>(
u, size, machInst, vd, vn, vm);
} else {
return decodeNeonUSThreeReg<VabdD, VabdQ>(
bits(machInst, 6), u, size, machInst, vd, vn, vm);
}
case 0x8:
return decodeNeonUSThreeUSReg<Vmlal>(
u, size, machInst, vd, vn, vm);
case 0xa:
return decodeNeonUSThreeUSReg<Vmlsl>(
u, size, machInst, vd, vn, vm);
case 0x9:
if (u) {
return new Unknown(machInst);
} else {
return decodeNeonSThreeUSReg<Vqdmlal>(
size, machInst, vd, vn, vm);
}
case 0xb:
if (u) {
return new Unknown(machInst);
} else {
return decodeNeonSThreeUSReg<Vqdmlsl>(
size, machInst, vd, vn, vm);
}
case 0xc:
return decodeNeonUSThreeUSReg<Vmull>(
u, size, machInst, vd, vn, vm);
case 0xd:
if (u) {
return new Unknown(machInst);
} else {
return decodeNeonSThreeUSReg<Vqdmull>(
size, machInst, vd, vn, vm);
}
case 0xe:
return decodeNeonUThreeUSReg<Vmullp>(
size, machInst, vd, vn, vm);
}
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);
const unsigned size = bits(machInst, 21, 20);
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vn =
(IntRegIndex)(2 * (bits(machInst, 19, 16) |
(bits(machInst, 7) << 4)));
const IntRegIndex vm = (size == 2) ?
(IntRegIndex)(2 * bits(machInst, 3, 0)) :
(IntRegIndex)(2 * bits(machInst, 2, 0));
const unsigned index = (size == 2) ? (unsigned)bits(machInst, 5) :
(bits(machInst, 3) | (bits(machInst, 5) << 1));
switch (a) {
case 0x0:
if (u) {
switch (size) {
case 1:
return new VmlasQ<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new VmlasQ<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new VmlasD<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new VmlasD<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x1:
if (u)
return new VmlasQFp<float>(machInst, vd, vn, vm, index);
else
return new VmlasDFp<float>(machInst, vd, vn, vm, index);
case 0x4:
if (u) {
switch (size) {
case 1:
return new VmlssQ<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new VmlssQ<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new VmlssD<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new VmlssD<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x5:
if (u)
return new VmlssQFp<float>(machInst, vd, vn, vm, index);
else
return new VmlssDFp<float>(machInst, vd, vn, vm, index);
case 0x2:
if (u) {
switch (size) {
case 1:
return new Vmlals<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vmlals<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new Vmlals<int16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vmlals<int32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x6:
if (u) {
switch (size) {
case 1:
return new Vmlsls<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vmlsls<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new Vmlsls<int16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vmlsls<int32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x3:
if (u) {
return new Unknown(machInst);
} else {
switch (size) {
case 1:
return new Vqdmlals<int16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vqdmlals<int32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x7:
if (u) {
return new Unknown(machInst);
} else {
switch (size) {
case 1:
return new Vqdmlsls<int16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vqdmlsls<int32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x8:
if (u) {
switch (size) {
case 1:
return new VmulsQ<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new VmulsQ<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new VmulsD<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new VmulsD<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0x9:
if (u)
return new VmulsQFp<float>(machInst, vd, vn, vm, index);
else
return new VmulsDFp<float>(machInst, vd, vn, vm, index);
case 0xa:
if (u) {
switch (size) {
case 1:
return new Vmulls<uint16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vmulls<uint32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new Vmulls<int16_t>(machInst, vd, vn, vm, index);
case 2:
return new Vmulls<int32_t>(machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0xb:
if (u) {
return new Unknown(machInst);
} else {
if (u) {
switch (size) {
case 1:
return new Vqdmulls<uint16_t>(
machInst, vd, vn, vm, index);
case 2:
return new Vqdmulls<uint32_t>(
machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new Vqdmulls<int16_t>(
machInst, vd, vn, vm, index);
case 2:
return new Vqdmulls<int32_t>(
machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
}
case 0xc:
if (u) {
switch (size) {
case 1:
return new VqdmulhsQ<int16_t>(
machInst, vd, vn, vm, index);
case 2:
return new VqdmulhsQ<int32_t>(
machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new VqdmulhsD<int16_t>(
machInst, vd, vn, vm, index);
case 2:
return new VqdmulhsD<int32_t>(
machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
}
case 0xd:
if (u) {
switch (size) {
case 1:
return new VqrdmulhsQ<int16_t>(
machInst, vd, vn, vm, index);
case 2:
return new VqrdmulhsQ<int32_t>(
machInst, vd, vn, vm, index);
default:
return new Unknown(machInst);
}
} else {
switch (size) {
case 1:
return new VqrdmulhsD<int16_t>(
machInst, vd, vn, vm, index);
case 2:
return new VqrdmulhsD<int32_t>(
machInst, vd, vn, vm, index);
default:
return new Unknown(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);
const bool q = bits(machInst, 6);
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vm =
(IntRegIndex)(2 * (bits(machInst, 3, 0) |
(bits(machInst, 5) << 4)));
const unsigned size = bits(machInst, 19, 18);
switch (a) {
case 0x0:
switch (bits(b, 4, 1)) {
case 0x0:
switch (size) {
case 0:
if (q) {
return new NVrev64Q<uint8_t>(machInst, vd, vm);
} else {
return new NVrev64D<uint8_t>(machInst, vd, vm);
}
case 1:
if (q) {
return new NVrev64Q<uint16_t>(machInst, vd, vm);
} else {
return new NVrev64D<uint16_t>(machInst, vd, vm);
}
case 2:
if (q) {
return new NVrev64Q<uint32_t>(machInst, vd, vm);
} else {
return new NVrev64D<uint32_t>(machInst, vd, vm);
}
default:
return new Unknown(machInst);
}
case 0x1:
switch (size) {
case 0:
if (q) {
return new NVrev32Q<uint8_t>(machInst, vd, vm);
} else {
return new NVrev32D<uint8_t>(machInst, vd, vm);
}
case 1:
if (q) {
return new NVrev32Q<uint16_t>(machInst, vd, vm);
} else {
return new NVrev32D<uint16_t>(machInst, vd, vm);
}
default:
return new Unknown(machInst);
}
case 0x2:
if (size != 0) {
return new Unknown(machInst);
} else if (q) {
return new NVrev16Q<uint8_t>(machInst, vd, vm);
} else {
return new NVrev16D<uint8_t>(machInst, vd, vm);
}
case 0x4:
return decodeNeonSTwoMiscSReg<NVpaddlD, NVpaddlQ>(
q, size, machInst, vd, vm);
case 0x5:
return decodeNeonUTwoMiscSReg<NVpaddlD, NVpaddlQ>(
q, size, machInst, vd, vm);
case 0x8:
return decodeNeonSTwoMiscReg<NVclsD, NVclsQ>(
q, size, machInst, vd, vm);
case 0x9:
return decodeNeonSTwoMiscReg<NVclzD, NVclzQ>(
q, size, machInst, vd, vm);
case 0xa:
return decodeNeonUTwoMiscReg<NVcntD, NVcntQ>(
q, size, machInst, vd, vm);
case 0xb:
if (q)
return new NVmvnQ<uint64_t>(machInst, vd, vm);
else
return new NVmvnD<uint64_t>(machInst, vd, vm);
case 0xc:
return decodeNeonSTwoMiscSReg<NVpadalD, NVpadalQ>(
q, size, machInst, vd, vm);
case 0xd:
return decodeNeonUTwoMiscSReg<NVpadalD, NVpadalQ>(
q, size, machInst, vd, vm);
case 0xe:
return decodeNeonSTwoMiscReg<NVqabsD, NVqabsQ>(
q, size, machInst, vd, vm);
case 0xf:
return decodeNeonSTwoMiscReg<NVqnegD, NVqnegQ>(
q, size, machInst, vd, vm);
default:
return new Unknown(machInst);
}
case 0x1:
switch (bits(b, 3, 1)) {
case 0x0:
if (bits(b, 4)) {
if (q) {
return new NVcgtQFp<float>(machInst, vd, vm);
} else {
return new NVcgtDFp<float>(machInst, vd, vm);
}
} else {
return decodeNeonSTwoMiscReg<NVcgtD, NVcgtQ>(
q, size, machInst, vd, vm);
}
case 0x1:
if (bits(b, 4)) {
if (q) {
return new NVcgeQFp<float>(machInst, vd, vm);
} else {
return new NVcgeDFp<float>(machInst, vd, vm);
}
} else {
return decodeNeonSTwoMiscReg<NVcgeD, NVcgeQ>(
q, size, machInst, vd, vm);
}
case 0x2:
if (bits(b, 4)) {
if (q) {
return new NVceqQFp<float>(machInst, vd, vm);
} else {
return new NVceqDFp<float>(machInst, vd, vm);
}
} else {
return decodeNeonSTwoMiscReg<NVceqD, NVceqQ>(
q, size, machInst, vd, vm);
}
case 0x3:
if (bits(b, 4)) {
if (q) {
return new NVcleQFp<float>(machInst, vd, vm);
} else {
return new NVcleDFp<float>(machInst, vd, vm);
}
} else {
return decodeNeonSTwoMiscReg<NVcleD, NVcleQ>(
q, size, machInst, vd, vm);
}
case 0x4:
if (bits(b, 4)) {
if (q) {
return new NVcltQFp<float>(machInst, vd, vm);
} else {
return new NVcltDFp<float>(machInst, vd, vm);
}
} else {
return decodeNeonSTwoMiscReg<NVcltD, NVcltQ>(
q, size, machInst, vd, vm);
}
case 0x6:
if (bits(machInst, 10)) {
if (q)
return new NVabsQFp<float>(machInst, vd, vm);
else
return new NVabsDFp<float>(machInst, vd, vm);
} else {
return decodeNeonSTwoMiscReg<NVabsD, NVabsQ>(
q, size, machInst, vd, vm);
}
case 0x7:
if (bits(machInst, 10)) {
if (q)
return new NVnegQFp<float>(machInst, vd, vm);
else
return new NVnegDFp<float>(machInst, vd, vm);
} else {
return decodeNeonSTwoMiscReg<NVnegD, NVnegQ>(
q, size, machInst, vd, vm);
}
}
case 0x2:
switch (bits(b, 4, 1)) {
case 0x0:
if (q)
return new NVswpQ<uint64_t>(machInst, vd, vm);
else
return new NVswpD<uint64_t>(machInst, vd, vm);
case 0x1:
return decodeNeonUTwoMiscReg<NVtrnD, NVtrnQ>(
q, size, machInst, vd, vm);
case 0x2:
return decodeNeonUTwoMiscReg<NVuzpD, NVuzpQ>(
q, size, machInst, vd, vm);
case 0x3:
return decodeNeonUTwoMiscReg<NVzipD, NVzipQ>(
q, size, machInst, vd, vm);
case 0x4:
if (b == 0x8) {
return decodeNeonUTwoMiscUSReg<NVmovn>(
size, machInst, vd, vm);
} else {
return decodeNeonSTwoMiscUSReg<NVqmovuns>(
size, machInst, vd, vm);
}
case 0x5:
if (q) {
return decodeNeonUTwoMiscUSReg<NVqmovun>(
size, machInst, vd, vm);
} else {
return decodeNeonSTwoMiscUSReg<NVqmovn>(
size, machInst, vd, vm);
}
case 0x6:
if (b == 0xc) {
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vm =
(IntRegIndex)(2 * (bits(machInst, 3, 0) |
(bits(machInst, 5) << 4)));
unsigned size = bits(machInst, 19, 18);
return decodeNeonSTwoShiftUSReg<NVshll>(
size, machInst, vd, vm, 8 << size);
} else {
return new Unknown(machInst);
}
case 0xc:
case 0xe:
if (b == 0x18) {
if (size != 1 || (vm % 2))
return new Unknown(machInst);
return new NVcvts2h<uint16_t>(machInst, vd, vm);
} else if (b == 0x1c) {
if (size != 1 || (vd % 2))
return new Unknown(machInst);
return new NVcvth2s<uint16_t>(machInst, vd, vm);
} else {
return new Unknown(machInst);
}
default:
return new Unknown(machInst);
}
case 0x3:
if (bits(b, 4, 3) == 0x3) {
if ((q && (vd % 2 || vm % 2)) || size != 2) {
return new Unknown(machInst);
} else {
if (bits(b, 2)) {
if (bits(b, 1)) {
if (q) {
return new NVcvt2ufxQ<float>(
machInst, vd, vm, 0);
} else {
return new NVcvt2ufxD<float>(
machInst, vd, vm, 0);
}
} else {
if (q) {
return new NVcvt2sfxQ<float>(
machInst, vd, vm, 0);
} else {
return new NVcvt2sfxD<float>(
machInst, vd, vm, 0);
}
}
} else {
if (bits(b, 1)) {
if (q) {
return new NVcvtu2fpQ<float>(
machInst, vd, vm, 0);
} else {
return new NVcvtu2fpD<float>(
machInst, vd, vm, 0);
}
} else {
if (q) {
return new NVcvts2fpQ<float>(
machInst, vd, vm, 0);
} else {
return new NVcvts2fpD<float>(
machInst, vd, vm, 0);
}
}
}
}
} else if ((b & 0x1a) == 0x10) {
if (bits(b, 2)) {
if (q) {
return new NVrecpeQFp<float>(machInst, vd, vm);
} else {
return new NVrecpeDFp<float>(machInst, vd, vm);
}
} else {
if (q) {
return new NVrecpeQ<uint32_t>(machInst, vd, vm);
} else {
return new NVrecpeD<uint32_t>(machInst, vd, vm);
}
}
} else if ((b & 0x1a) == 0x12) {
if (bits(b, 2)) {
if (q) {
return new NVrsqrteQFp<float>(machInst, vd, vm);
} else {
return new NVrsqrteDFp<float>(machInst, vd, vm);
}
} else {
if (q) {
return new NVrsqrteQ<uint32_t>(machInst, vd, vm);
} else {
return new NVrsqrteD<uint32_t>(machInst, vd, vm);
}
}
} 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 (bits(a, 2, 1) != 0x3) {
if ((c & 0x5) == 0) {
return decodeNeonThreeRegDiffLengths(machInst);
} else if ((c & 0x5) == 4) {
return decodeNeonTwoRegScalar(machInst);
}
} else if ((a & 0x16) == 0x16) {
const IntRegIndex vd =
(IntRegIndex)(2 * (bits(machInst, 15, 12) |
(bits(machInst, 22) << 4)));
const IntRegIndex vn =
(IntRegIndex)(2 * (bits(machInst, 19, 16) |
(bits(machInst, 7) << 4)));
const IntRegIndex vm =
(IntRegIndex)(2 * (bits(machInst, 3, 0) |
(bits(machInst, 5) << 4)));
if (!u) {
if (bits(c, 0) == 0) {
unsigned imm4 = bits(machInst, 11, 8);
bool q = bits(machInst, 6);
if (imm4 >= 16 && !q)
return new Unknown(machInst);
if (q) {
return new NVextQ<uint8_t>(machInst, vd, vn, vm, imm4);
} else {
return new NVextD<uint8_t>(machInst, vd, vn, vm, imm4);
}
}
} else if (bits(b, 3) == 0 && bits(c, 0) == 0) {
return decodeNeonTwoRegMisc(machInst);
} else if (bits(b, 3, 2) == 0x2 && bits(c, 0) == 0) {
unsigned length = bits(machInst, 9, 8) + 1;
if ((uint32_t)vn / 2 + length > 32)
return new Unknown(machInst);
if (bits(machInst, 6) == 0) {
switch (length) {
case 1:
return new NVtbl1(machInst, vd, vn, vm);
case 2:
return new NVtbl2(machInst, vd, vn, vm);
case 3:
return new NVtbl3(machInst, vd, vn, vm);
case 4:
return new NVtbl4(machInst, vd, vn, vm);
}
} else {
switch (length) {
case 1:
return new NVtbx1(machInst, vd, vn, vm);
case 2:
return new NVtbx2(machInst, vd, vn, vm);
case 3:
return new NVtbx3(machInst, vd, vn, vm);
case 4:
return new NVtbx4(machInst, vd, vn, vm);
}
}
} else if (b == 0xc && (c & 0x9) == 0) {
unsigned imm4 = bits(machInst, 19, 16);
if (bits(imm4, 2, 0) == 0)
return new Unknown(machInst);
unsigned size = 0;
while ((imm4 & 0x1) == 0) {
size++;
imm4 >>= 1;
}
unsigned index = imm4 >> 1;
const bool q = bits(machInst, 6);
return decodeNeonUTwoShiftSReg<NVdupD, NVdupQ>(
q, size, machInst, vd, vm, index);
}
}
return new Unknown(machInst);
}
'''
}};
def format ThumbNeonMem() {{
decode_block = '''
return decodeNeonMem(machInst);
'''
}};
def format ThumbNeonData() {{
decode_block = '''
return decodeNeonData(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/2 > 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);
}
if (specReg == MISCREG_FPSCR) {
return new VmsrFpscr(machInst, (IntRegIndex)specReg, rt);
} else {
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);
// Handle accessing each single precision half of the vector.
vd += bits(machInst, 21);
const IntRegIndex rt =
(IntRegIndex)(uint32_t)bits(machInst, 15, 12);
if (bits(machInst, 22) == 1) {
return new VmovCoreRegB(machInst, (IntRegIndex)vd,
rt, bits(machInst, 6, 5));
} else if (bits(machInst, 5) == 1) {
return new VmovCoreRegH(machInst, (IntRegIndex)vd,
rt, bits(machInst, 6));
} else if (bits(machInst, 6) == 0) {
return new VmovCoreRegW(machInst, (IntRegIndex)vd, rt);
} else {
return new Unknown(machInst);
}
} else if (bits(b, 1) == 0) {
bool q = bits(machInst, 21);
unsigned be = (bits(machInst, 22) << 1) | (bits(machInst, 5));
IntRegIndex vd = (IntRegIndex)(2 * (uint32_t)
(bits(machInst, 19, 16) | (bits(machInst, 7) << 4)));
IntRegIndex rt = (IntRegIndex)(uint32_t)
bits(machInst, 15, 12);
if (q) {
switch (be) {
case 0:
return new NVdupQGpr<uint32_t>(machInst, vd, rt);
case 1:
return new NVdupQGpr<uint16_t>(machInst, vd, rt);
case 2:
return new NVdupQGpr<uint8_t>(machInst, vd, rt);
case 3:
return new Unknown(machInst);
}
} else {
switch (be) {
case 0:
return new NVdupDGpr<uint32_t>(machInst, vd, rt);
case 1:
return new NVdupDGpr<uint16_t>(machInst, vd, rt);
case 2:
return new NVdupDGpr<uint8_t>(machInst, vd, rt);
case 3:
return new Unknown(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;
if (specReg == MISCREG_FPSCR) {
return new VmrsApsrFpscr(machInst, INTREG_CONDCODES,
(IntRegIndex)specReg, (uint32_t)cpsrMask);
} else {
return new VmrsApsr(machInst, INTREG_CONDCODES,
(IntRegIndex)specReg, (uint32_t)cpsrMask);
}
} else if (specReg == MISCREG_FPSCR) {
return new VmrsFpscr(machInst, rt, (IntRegIndex)specReg);
} else {
return new Vmrs(machInst, rt, (IntRegIndex)specReg);
}
}
} else {
uint32_t vd = (bits(machInst, 7) << 5) |
(bits(machInst, 19, 16) << 1);
// Handle indexing into each single precision half of the vector.
vd += bits(machInst, 21);
uint32_t index;
const IntRegIndex rt =
(IntRegIndex)(uint32_t)bits(machInst, 15, 12);
const bool u = (bits(machInst, 23) == 1);
if (bits(machInst, 22) == 1) {
index = bits(machInst, 6, 5);
if (u) {
return new VmovRegCoreUB(machInst, rt,
(IntRegIndex)vd, index);
} else {
return new VmovRegCoreSB(machInst, rt,
(IntRegIndex)vd, index);
}
} else if (bits(machInst, 5) == 1) {
index = bits(machInst, 6);
if (u) {
return new VmovRegCoreUH(machInst, rt,
(IntRegIndex)vd, index);
} else {
return new VmovRegCoreSH(machInst, rt,
(IntRegIndex)vd, index);
}
} else if (bits(machInst, 6) == 0 && !u) {
return new VmovRegCoreW(machInst, rt, (IntRegIndex)vd);
} else {
return new Unknown(machInst);
}
}
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<VmlaS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VmlaD>(
machInst, vd, vn, vm, true);
}
} else {
if (single) {
return decodeVfpRegRegRegOp<VmlsS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VmlsD>(
machInst, vd, vn, vm, true);
}
}
case 0x1:
if (bits(machInst, 6) == 1) {
if (single) {
return decodeVfpRegRegRegOp<VnmlaS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VnmlaD>(
machInst, vd, vn, vm, true);
}
} else {
if (single) {
return decodeVfpRegRegRegOp<VnmlsS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VnmlsD>(
machInst, vd, vn, vm, true);
}
}
case 0x2:
if ((opc3 & 0x1) == 0) {
if (single) {
return decodeVfpRegRegRegOp<VmulS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VmulD>(
machInst, vd, vn, vm, true);
}
} else {
if (single) {
return decodeVfpRegRegRegOp<VnmulS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VnmulD>(
machInst, vd, vn, vm, true);
}
}
case 0x3:
if ((opc3 & 0x1) == 0) {
if (single) {
return decodeVfpRegRegRegOp<VaddS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VaddD>(
machInst, vd, vn, vm, true);
}
} else {
if (single) {
return decodeVfpRegRegRegOp<VsubS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VsubD>(
machInst, vd, vn, vm, true);
}
}
case 0x8:
if ((opc3 & 0x1) == 0) {
if (single) {
return decodeVfpRegRegRegOp<VdivS>(
machInst, vd, vn, vm, false);
} else {
return decodeVfpRegRegRegOp<VdivD>(
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<VmovImmS>(
machInst, vd, imm, false);
} else {
uint64_t imm = vfp_modified_imm(baseImm, true);
return decodeVfpRegImmOp<VmovImmD>(
machInst, vd, imm, true);
}
}
switch (opc2) {
case 0x0:
if (opc3 == 1) {
if (single) {
return decodeVfpRegRegOp<VmovRegS>(
machInst, vd, vm, false);
} else {
return decodeVfpRegRegOp<VmovRegD>(
machInst, vd, vm, true);
}
} else {
if (single) {
return decodeVfpRegRegOp<VabsS>(
machInst, vd, vm, false);
} else {
return decodeVfpRegRegOp<VabsD>(
machInst, vd, vm, true);
}
}
case 0x1:
if (opc3 == 1) {
if (single) {
return decodeVfpRegRegOp<VnegS>(
machInst, vd, vm, false);
} else {
return decodeVfpRegRegOp<VnegD>(
machInst, vd, vm, true);
}
} else {
if (single) {
return decodeVfpRegRegOp<VsqrtS>(
machInst, vd, vm, false);
} else {
return decodeVfpRegRegOp<VsqrtD>(
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);
'''
}};