blob: a4a6567a85fca83391efc9714539facb73d56ef8 [file] [log] [blame]
/*
* Copyright (c) 2010, 2012-2013, 2017-2018 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.
*/
#ifndef __ARCH_ARM_INSTS_PREDINST_HH__
#define __ARCH_ARM_INSTS_PREDINST_HH__
#include "arch/arm/insts/static_inst.hh"
#include "arch/arm/pcstate.hh"
#include "base/compiler.hh"
#include "base/logging.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
namespace gem5
{
namespace ArmISA
{
static inline uint32_t
rotate_imm(uint32_t immValue, uint32_t rotateValue)
{
rotateValue &= 31;
return rotateValue == 0 ? immValue :
(immValue >> rotateValue) | (immValue << (32 - rotateValue));
}
static inline uint32_t
modified_imm(uint8_t ctrlImm, uint8_t dataImm)
{
uint32_t bigData = dataImm;
uint32_t bigCtrl = ctrlImm;
if (bigCtrl < 4) {
switch (bigCtrl) {
case 0:
return bigData;
case 1:
return bigData | (bigData << 16);
case 2:
return (bigData << 8) | (bigData << 24);
case 3:
return (bigData << 0) | (bigData << 8) |
(bigData << 16) | (bigData << 24);
}
}
bigCtrl = (bigCtrl << 1) | ((bigData >> 7) & 0x1);
bigData |= (1 << 7);
return bigData << (32 - bigCtrl);
}
static inline uint64_t
simd_modified_imm(bool op, uint8_t cmode, uint8_t data, bool &immValid,
bool isAarch64 = false)
{
uint64_t bigData = data;
immValid = true;
switch (cmode) {
case 0x0:
case 0x1:
bigData = (bigData << 0) | (bigData << 32);
break;
case 0x2:
case 0x3:
bigData = (bigData << 8) | (bigData << 40);
break;
case 0x4:
case 0x5:
bigData = (bigData << 16) | (bigData << 48);
break;
case 0x6:
case 0x7:
bigData = (bigData << 24) | (bigData << 56);
break;
case 0x8:
case 0x9:
bigData = (bigData << 0) | (bigData << 16) |
(bigData << 32) | (bigData << 48);
break;
case 0xa:
case 0xb:
bigData = (bigData << 8) | (bigData << 24) |
(bigData << 40) | (bigData << 56);
break;
case 0xc:
bigData = (0xffULL << 0) | (bigData << 8) |
(0xffULL << 32) | (bigData << 40);
break;
case 0xd:
bigData = (0xffffULL << 0) | (bigData << 16) |
(0xffffULL << 32) | (bigData << 48);
break;
case 0xe:
if (op) {
bigData = 0;
for (int i = 7; i >= 0; i--) {
if (bits(data, i)) {
bigData |= (0xFFULL << (i * 8));
}
}
} else {
bigData = (bigData << 0) | (bigData << 8) |
(bigData << 16) | (bigData << 24) |
(bigData << 32) | (bigData << 40) |
(bigData << 48) | (bigData << 56);
}
break;
case 0xf:
{
uint64_t bVal = 0;
if (!op) {
bVal = bits(bigData, 6) ? (0x1F) : (0x20);
bigData = (bits(bigData, 5, 0) << 19) |
(bVal << 25) | (bits(bigData, 7) << 31);
bigData |= (bigData << 32);
break;
} else if (isAarch64) {
bVal = bits(bigData, 6) ? (0x0FF) : (0x100);
bigData = (bits(bigData, 5, 0) << 48) |
(bVal << 54) | (bits(bigData, 7) << 63);
break;
}
}
[[fallthrough]];
default:
immValid = false;
break;
}
return bigData;
}
/** Floating point data types. */
enum class FpDataType { Fp16, Fp32, Fp64 };
static inline uint64_t
vfp_modified_imm(uint8_t data, FpDataType dtype)
{
uint64_t bigData = data;
uint64_t repData;
switch (dtype) {
case FpDataType::Fp16:
repData = bits(data, 6) ? 0x3 : 0;
bigData = (bits(bigData, 5, 0) << 6) |
(repData << 12) | (bits(~bigData, 6) << 14) |
(bits(bigData, 7) << 15);
break;
case FpDataType::Fp32:
repData = bits(data, 6) ? 0x1F : 0;
bigData = (bits(bigData, 5, 0) << 19) |
(repData << 25) | (bits(~bigData, 6) << 30) |
(bits(bigData, 7) << 31);
break;
case FpDataType::Fp64:
repData = bits(data, 6) ? 0xFF : 0;
bigData = (bits(bigData, 5, 0) << 48) |
(repData << 54) | (bits(~bigData, 6) << 62) |
(bits(bigData, 7) << 63);
break;
default:
panic("Unrecognized FP data type");
}
return bigData;
}
static inline FpDataType
decode_fp_data_type(uint8_t encoding)
{
switch (encoding) {
case 1: return FpDataType::Fp16;
case 2: return FpDataType::Fp32;
case 3: return FpDataType::Fp64;
default:
panic(
"Invalid floating point data type in VFP/SIMD or SVE instruction");
}
}
/**
* Base class for predicated integer operations.
*/
class PredOp : public ArmStaticInst
{
protected:
ConditionCode condCode;
/// Constructor
PredOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
ArmStaticInst(mnem, _machInst, __opClass)
{
if (machInst.aarch64)
condCode = COND_UC;
else if (machInst.itstateMask)
condCode = (ConditionCode)(uint8_t)machInst.itstateCond;
else
condCode = (ConditionCode)(unsigned)machInst.condCode;
}
};
/**
* Base class for predicated immediate operations.
*/
class PredImmOp : public PredOp
{
protected:
uint32_t imm;
uint32_t rotated_imm;
uint32_t rotated_carry;
uint32_t rotate;
/// Constructor
PredImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
PredOp(mnem, _machInst, __opClass),
imm(machInst.imm), rotated_imm(0), rotated_carry(0),
rotate(machInst.rotate << 1)
{
rotated_imm = rotate_imm(imm, rotate);
if (rotate != 0)
rotated_carry = bits(rotated_imm, 31);
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
/**
* Base class for predicated integer operations.
*/
class PredIntOp : public PredOp
{
protected:
uint32_t shift_size;
uint32_t shift;
/// Constructor
PredIntOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
PredOp(mnem, _machInst, __opClass),
shift_size(machInst.shiftSize), shift(machInst.shift)
{
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class DataImmOp : public PredOp
{
protected:
IntRegIndex dest, op1;
uint32_t imm;
// Whether the carry flag should be modified if that's an option for
// this instruction.
bool rotC;
DataImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _dest, IntRegIndex _op1, uint32_t _imm, bool _rotC) :
PredOp(mnem, _machInst, __opClass),
dest(_dest), op1(_op1), imm(_imm), rotC(_rotC)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class DataRegOp : public PredOp
{
protected:
IntRegIndex dest, op1, op2;
int32_t shiftAmt;
ArmShiftType shiftType;
DataRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
int32_t _shiftAmt, ArmShiftType _shiftType) :
PredOp(mnem, _machInst, __opClass),
dest(_dest), op1(_op1), op2(_op2),
shiftAmt(_shiftAmt), shiftType(_shiftType)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class DataRegRegOp : public PredOp
{
protected:
IntRegIndex dest, op1, op2, shift;
ArmShiftType shiftType;
DataRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
IntRegIndex _shift, ArmShiftType _shiftType) :
PredOp(mnem, _machInst, __opClass),
dest(_dest), op1(_op1), op2(_op2), shift(_shift),
shiftType(_shiftType)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
/**
* Base class for predicated macro-operations.
*/
class PredMacroOp : public PredOp
{
protected:
uint32_t numMicroops;
StaticInstPtr * microOps;
/// Constructor
PredMacroOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
PredOp(mnem, _machInst, __opClass),
numMicroops(0), microOps(nullptr)
{
// We rely on the subclasses of this object to handle the
// initialization of the micro-operations, since they are
// all of variable length
flags[IsMacroop] = true;
}
~PredMacroOp()
{
if (numMicroops)
delete [] microOps;
}
StaticInstPtr
fetchMicroop(MicroPC microPC) const override
{
assert(microPC < numMicroops);
return microOps[microPC];
}
Fault
execute(ExecContext *, Trace::InstRecord *) const override
{
panic("Execute method called when it shouldn't!");
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
/**
* Base class for predicated micro-operations.
*/
class PredMicroop : public PredOp
{
/// Constructor
PredMicroop(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
PredOp(mnem, _machInst, __opClass)
{
flags[IsMicroop] = true;
}
void
advancePC(PCStateBase &pcState) const override
{
auto &apc = pcState.as<PCState>();
if (flags[IsLastMicroop])
apc.uEnd();
else
apc.uAdvance();
}
void
advancePC(ThreadContext *tc) const override
{
PCState pc = tc->pcState().as<PCState>();
if (flags[IsLastMicroop])
pc.uEnd();
else
pc.uAdvance();
tc->pcState(pc);
}
};
} // namespace ArmISA
} // namespace gem5
#endif //__ARCH_ARM_INSTS_PREDINST_HH__