| /* |
| * 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: |
| RegIndex 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, |
| RegIndex _dest, RegIndex _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: |
| RegIndex dest, op1, op2; |
| int32_t shiftAmt; |
| ArmShiftType shiftType; |
| |
| DataRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, |
| RegIndex _dest, RegIndex _op1, RegIndex _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: |
| RegIndex dest, op1, op2, shift; |
| ArmShiftType shiftType; |
| |
| DataRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, |
| RegIndex _dest, RegIndex _op1, RegIndex _op2, |
| RegIndex _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__ |