// Copyright (c) AMD
// All rights reserved.

// Monitor Instruction

output header {{
    class MonitorInst : public X86ISA::X86StaticInst
    {
      public:
        static const RegIndex foldOBit = 0;
        /// Constructor
        MonitorInst(const char *_mnemonic, ExtMachInst _machInst,
                OpClass __opClass) :
            X86ISA::X86StaticInst(_mnemonic, _machInst, __opClass)
        { }

        std::string generateDisassembly(Addr pc,
                const Loader::SymbolTable *symtab) const override;
    };
}};

output decoder {{
    std::string
    MonitorInst::generateDisassembly(
            Addr PC, const Loader::SymbolTable *symtab) const
    {
        std::stringstream response;

        printMnemonic(response, mnemonic);
        ccprintf(response, " ");
        printReg(response, _srcRegIdx[0], machInst.opSize);
        return response.str();
    }
}};

def format MonitorInst(code, *opt_flags) {{
    iop = InstObjParams(name, Name, 'MonitorInst', code, opt_flags)
    header_output = BasicDeclare.subst(iop)
    decoder_output = BasicConstructor.subst(iop)
    decode_block = BasicDecode.subst(iop)
    exec_output = BasicExecute.subst(iop)
}};


// Mwait instruction

def template MwaitDeclare {{
    class %(class_name)s : public %(base_class)s
    {
        public:
        // Constructor.
        %(class_name)s(ExtMachInst machInst);
        Fault execute(ExecContext *, Trace::InstRecord *) const override;
        Fault initiateAcc(ExecContext *, Trace::InstRecord *) const override;
        Fault completeAcc(PacketPtr, ExecContext *,
                          Trace::InstRecord *) const override;
    };
}};

def template MwaitInitiateAcc {{
    Fault %(class_name)s::initiateAcc(ExecContext * xc,
            Trace::InstRecord * traceData) const
    {
        unsigned s = 0x8;        //size
        unsigned f = 0;          //flags
        initiateMemRead(xc, traceData, xc->getAddrMonitor()->vAddr, s, f);
        return NoFault;
    }
}};

def template MwaitCompleteAcc {{
    Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
            Trace::InstRecord *traceData) const
    {
        MicroHalt hltObj(machInst, mnemonic, 0x0);
        if(xc->mwait(pkt)) {
            hltObj.execute(xc, traceData);
        }
        return NoFault;
    }
}};

output header {{
    class MwaitInst : public X86ISA::X86StaticInst
    {
      public:
        static const RegIndex foldOBit = 0;
        /// Constructor
        MwaitInst(const char *_mnemonic, ExtMachInst _machInst,
                OpClass __opClass) :
            X86ISA::X86StaticInst(_mnemonic, _machInst, __opClass)
        {
            flags[IsMemRef] = 1;
            flags[IsLoad] = 1;
        }

        std::string generateDisassembly(Addr pc,
                const Loader::SymbolTable *symtab) const override;
    };
}};

output decoder {{
    std::string
    MwaitInst::generateDisassembly(
            Addr PC, const Loader::SymbolTable *symtab) const
    {
        std::stringstream response;

        // Although mwait could take hints from eax and ecx, the _srcRegIdx
        // is not set, and thus should not be printed here
        printMnemonic(response, mnemonic);
        return response.str();
    }
}};

def format MwaitInst(code, *opt_flags) {{
    iop = InstObjParams(name, Name, 'MwaitInst', code, opt_flags)
    header_output = MwaitDeclare.subst(iop)
    decoder_output = BasicConstructor.subst(iop)
    decode_block = BasicDecode.subst(iop)
    exec_output = BasicExecute.subst(iop)
    exec_output += MwaitInitiateAcc.subst(iop)
    exec_output += MwaitCompleteAcc.subst(iop)
}};

