| /* |
| * Copyright 2021 Google Inc. |
| * |
| * 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_X86_INSTS_MICROOP_ARGS_HH__ |
| #define __ARCH_X86_INSTS_MICROOP_ARGS_HH__ |
| |
| #include <cstdint> |
| #include <sstream> |
| #include <string> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "arch/x86/insts/static_inst.hh" |
| #include "arch/x86/regs/int.hh" |
| #include "arch/x86/regs/segment.hh" |
| #include "arch/x86/types.hh" |
| #include "base/compiler.hh" |
| #include "base/cprintf.hh" |
| #include "cpu/reg_class.hh" |
| #include "sim/faults.hh" |
| |
| namespace gem5 |
| { |
| |
| namespace X86ISA |
| { |
| |
| struct DestOp |
| { |
| const RegIndex dest; |
| const size_t size; |
| RegIndex opIndex() const { return dest; } |
| |
| DestOp(RegIndex _dest, size_t _size) : dest(_dest), size(_size) {} |
| template <class InstType> |
| DestOp(RegIndex _dest, InstType *inst) : dest(_dest), |
| size(inst->getDestSize()) |
| {} |
| }; |
| |
| struct Src1Op |
| { |
| const RegIndex src1; |
| const size_t size; |
| RegIndex opIndex() const { return src1; } |
| |
| Src1Op(RegIndex _src1, size_t _size) : src1(_src1), size(_size) {} |
| template <class InstType> |
| Src1Op(RegIndex _src1, InstType *inst) : src1(_src1), |
| size(inst->getSrcSize()) |
| {} |
| }; |
| |
| struct Src2Op |
| { |
| const RegIndex src2; |
| const size_t size; |
| RegIndex opIndex() const { return src2; } |
| |
| Src2Op(RegIndex _src2, size_t _size) : src2(_src2), size(_size) {} |
| template <class InstType> |
| Src2Op(RegIndex _src2, InstType *inst) : src2(_src2), |
| size(inst->getSrcSize()) |
| {} |
| }; |
| |
| struct DataOp |
| { |
| const RegIndex data; |
| const size_t size; |
| RegIndex opIndex() const { return data; } |
| |
| DataOp(RegIndex _data, size_t _size) : data(_data), size(_size) {} |
| }; |
| |
| struct DataHiOp |
| { |
| const RegIndex dataHi; |
| const size_t size; |
| RegIndex opIndex() const { return dataHi; } |
| |
| DataHiOp(RegIndex data_hi, size_t _size) : dataHi(data_hi), size(_size) {} |
| }; |
| |
| struct DataLowOp |
| { |
| const RegIndex dataLow; |
| const size_t size; |
| RegIndex opIndex() const { return dataLow; } |
| |
| DataLowOp(RegIndex data_low, size_t _size) : dataLow(data_low), size(_size) |
| {} |
| }; |
| |
| template <class T, class Enabled=void> |
| struct HasDataSize : public std::false_type {}; |
| |
| template <class T> |
| struct HasDataSize<T, decltype((void)&T::dataSize)> : public std::true_type {}; |
| |
| template <class T> |
| constexpr bool HasDataSizeV = HasDataSize<T>::value; |
| |
| template <class Base> |
| struct IntOp : public Base |
| { |
| using ArgType = GpRegIndex; |
| |
| template <class Inst> |
| IntOp(Inst *inst, std::enable_if_t<HasDataSizeV<Inst>, ArgType> idx) : |
| Base(idx.index, inst->dataSize) |
| {} |
| |
| template <class Inst> |
| IntOp(Inst *inst, std::enable_if_t<!HasDataSizeV<Inst>, ArgType> idx) : |
| Base(idx.index, inst) |
| {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| X86StaticInst::printReg(os, RegId(IntRegClass, this->opIndex()), |
| this->size); |
| } |
| }; |
| |
| template <class Base> |
| struct FoldedOp : public Base |
| { |
| using ArgType = GpRegIndex; |
| |
| template <class InstType> |
| FoldedOp(InstType *inst, ArgType idx) : |
| Base(INTREG_FOLDED(idx.index, inst->foldOBit), inst->dataSize) |
| {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| X86StaticInst::printReg(os, RegId(IntRegClass, this->opIndex()), |
| this->size); |
| } |
| }; |
| |
| template <class Base> |
| struct CrOp : public Base |
| { |
| using ArgType = CrRegIndex; |
| |
| template <class InstType> |
| CrOp(InstType *inst, ArgType idx) : Base(idx.index, 0) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| ccprintf(os, "cr%d", this->opIndex()); |
| } |
| }; |
| |
| template <class Base> |
| struct DbgOp : public Base |
| { |
| using ArgType = DbgRegIndex; |
| |
| template <class InstType> |
| DbgOp(InstType *inst, ArgType idx) : Base(idx.index, 0) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| ccprintf(os, "dr%d", this->opIndex()); |
| } |
| |
| }; |
| |
| template <class Base> |
| struct SegOp : public Base |
| { |
| using ArgType = SegRegIndex; |
| |
| template <class InstType> |
| SegOp(InstType *inst, ArgType idx) : Base(idx.index, 0) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| X86StaticInst::printSegment(os, this->opIndex()); |
| } |
| }; |
| |
| template <class Base> |
| struct MiscOp : public Base |
| { |
| using ArgType = CtrlRegIndex; |
| |
| template <class InstType> |
| MiscOp(InstType *inst, ArgType idx) : Base(idx.index, inst->dataSize) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| X86StaticInst::printReg(os, RegId(MiscRegClass, this->opIndex()), |
| this->size); |
| } |
| }; |
| |
| template <class Base> |
| struct FloatOp : public Base |
| { |
| using ArgType = FpRegIndex; |
| |
| template <class Inst> |
| FloatOp(Inst *inst, std::enable_if_t<HasDataSizeV<Inst>, ArgType> idx) : |
| Base(idx.index, inst->dataSize) |
| {} |
| |
| template <class Inst> |
| FloatOp(Inst *inst, std::enable_if_t<!HasDataSizeV<Inst>, ArgType> idx) : |
| Base(idx.index, inst) |
| {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| X86StaticInst::printReg(os, RegId(FloatRegClass, this->opIndex()), |
| this->size); |
| } |
| }; |
| |
| using FoldedDestOp = FoldedOp<DestOp>; |
| using DbgDestOp = DbgOp<DestOp>; |
| using CrDestOp = CrOp<DestOp>; |
| using SegDestOp = SegOp<DestOp>; |
| using MiscDestOp = MiscOp<DestOp>; |
| using FloatDestOp = FloatOp<DestOp>; |
| using IntDestOp = IntOp<DestOp>; |
| |
| using FoldedSrc1Op = FoldedOp<Src1Op>; |
| using DbgSrc1Op = DbgOp<Src1Op>; |
| using CrSrc1Op = CrOp<Src1Op>; |
| using SegSrc1Op = SegOp<Src1Op>; |
| using MiscSrc1Op = MiscOp<Src1Op>; |
| using FloatSrc1Op = FloatOp<Src1Op>; |
| using IntSrc1Op = IntOp<Src1Op>; |
| |
| using FoldedSrc2Op = FoldedOp<Src2Op>; |
| using FloatSrc2Op = FloatOp<Src2Op>; |
| using IntSrc2Op = IntOp<Src2Op>; |
| |
| using FoldedDataOp = FoldedOp<DataOp>; |
| using FloatDataOp = FloatOp<DataOp>; |
| using FoldedDataHiOp = FoldedOp<DataHiOp>; |
| using FoldedDataLowOp = FoldedOp<DataLowOp>; |
| |
| struct Imm8Op |
| { |
| using ArgType = uint8_t; |
| |
| uint8_t imm8; |
| |
| template <class InstType> |
| Imm8Op(InstType *inst, ArgType _imm8) : imm8(_imm8) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| ccprintf(os, "%#x", imm8); |
| } |
| }; |
| |
| struct Imm64Op |
| { |
| using ArgType = uint64_t; |
| |
| uint64_t imm64; |
| |
| template <class InstType> |
| Imm64Op(InstType *inst, ArgType _imm64) : imm64(_imm64) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| ccprintf(os, "%#x", imm64); |
| } |
| }; |
| |
| struct UpcOp |
| { |
| using ArgType = MicroPC; |
| |
| MicroPC target; |
| |
| template <class InstType> |
| UpcOp(InstType *inst, ArgType _target) : target(_target) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| ccprintf(os, "%#x", target); |
| } |
| }; |
| |
| struct FaultOp |
| { |
| using ArgType = Fault; |
| |
| Fault fault; |
| |
| template <class InstType> |
| FaultOp(InstType *inst, ArgType _fault) : fault(_fault) {} |
| |
| void |
| print(std::ostream &os) const |
| { |
| ccprintf(os, fault ? fault->name() : "NoFault"); |
| } |
| }; |
| |
| struct AddrOp |
| { |
| struct ArgType |
| { |
| uint8_t scale; |
| GpRegIndex index; |
| GpRegIndex base; |
| uint64_t disp; |
| SegRegIndex segment; |
| }; |
| |
| const uint8_t scale; |
| const RegIndex index; |
| const RegIndex base; |
| const uint64_t disp; |
| const uint8_t segment; |
| const size_t size; |
| |
| template <class InstType> |
| AddrOp(InstType *inst, const ArgType &args) : scale(args.scale), |
| index(INTREG_FOLDED(args.index.index, inst->foldABit)), |
| base(INTREG_FOLDED(args.base.index, inst->foldABit)), |
| disp(args.disp), segment(args.segment.index), |
| size(inst->addressSize) |
| { |
| assert(segment < NUM_SEGMENTREGS); |
| } |
| |
| void |
| print(std::ostream &os) const |
| { |
| X86StaticInst::printMem( |
| os, segment, scale, index, base, disp, size, false); |
| } |
| }; |
| |
| template <typename Base, typename ...Operands> |
| class InstOperands : public Base, public Operands... |
| { |
| private: |
| using ArgTuple = std::tuple<typename Operands::ArgType...>; |
| |
| template <std::size_t ...I, typename ...CTorArgs> |
| InstOperands(std::index_sequence<I...>, ExtMachInst mach_inst, |
| const char *mnem, const char *inst_mnem, uint64_t set_flags, |
| OpClass op_class, [[maybe_unused]] ArgTuple args, |
| CTorArgs... ctor_args) : |
| Base(mach_inst, mnem, inst_mnem, set_flags, op_class, ctor_args...), |
| Operands(this, std::get<I>(args))... |
| {} |
| |
| protected: |
| template <typename ...CTorArgs> |
| InstOperands(ExtMachInst mach_inst, const char *mnem, |
| const char *inst_mnem, uint64_t set_flags, OpClass op_class, |
| ArgTuple args, CTorArgs... ctor_args) : |
| InstOperands(std::make_index_sequence<sizeof...(Operands)>{}, |
| mach_inst, mnem, inst_mnem, set_flags, op_class, |
| std::move(args), ctor_args...) |
| {} |
| |
| std::string |
| generateDisassembly(Addr pc, |
| const loader::SymbolTable *symtab) const override |
| { |
| std::stringstream response; |
| Base::printMnemonic(response, this->instMnem, this->mnemonic); |
| int count = 0; |
| GEM5_FOR_EACH_IN_PACK(ccprintf(response, count++ ? ", " : ""), |
| Operands::print(response)); |
| return response.str(); |
| } |
| }; |
| |
| } // namespace X86ISA |
| } // namespace gem5 |
| |
| #endif //__ARCH_X86_INSTS_MICROOP_ARGS_HH__ |