// 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
    {
      private:
        %(reg_idx_arr_decl)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[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)
}};

