From f3fd7469677ab1f25533d82c36460a700831ceec Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 6 Sep 2019 17:14:59 -0700 Subject: [PATCH] arch, x86: Rework the debug faults and microops. This makes the non-fatal microops advance the PC, and adds missing functions. The *_once Faults now also can be run once per *something*. They would previously be run once per Fault invoke function which is common to all M5WarnOnceFaults. The warn_once microop will now warn once per message. Change-Id: I05974b93f3b2700077a411b243679c2ff0e8c2cb Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20739 Reviewed-by: Gabe Black Reviewed-by: Brandon Potter Maintainer: Gabe Black Tested-by: kokoro --- src/arch/generic/debugfaults.hh | 153 +++++++++++++++--------- src/arch/x86/insts/badmicroop.cc | 5 +- src/arch/x86/isa/microops/debug.isa | 175 ++++++++++++++++------------ 3 files changed, 203 insertions(+), 130 deletions(-) diff --git a/src/arch/generic/debugfaults.hh b/src/arch/generic/debugfaults.hh index 5c5aa01ea..1c8d882aa 100644 --- a/src/arch/generic/debugfaults.hh +++ b/src/arch/generic/debugfaults.hh @@ -50,78 +50,125 @@ namespace GenericISA class M5DebugFault : public FaultBase { - public: - enum DebugFunc - { - PanicFunc, - FatalFunc, - WarnFunc, - WarnOnceFunc - }; - protected: - std::string message; - DebugFunc func; + std::string _message; + virtual void debugFunc() = 0; + void + advancePC(ThreadContext *tc, const StaticInstPtr &inst) + { + if (inst) { + auto pc = tc->pcState(); + inst->advancePC(pc); + tc->pcState(pc); + } + } public: - M5DebugFault(DebugFunc _func, std::string _message) : - message(_message), func(_func) + M5DebugFault(std::string _m) : _message(_m) {} + + template + M5DebugFault(const std::string &format, const Args &...args) : + _message(csprintf(format, args...)) {} - FaultName - name() const + std::string message() { return _message; } + + void + invoke(ThreadContext *tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr) override { - switch (func) { - case PanicFunc: - return "panic fault"; - case FatalFunc: - return "fatal fault"; - case WarnFunc: - return "warn fault"; - case WarnOnceFunc: - return "warn_once fault"; - default: - panic("unrecognized debug function number\n"); - } + debugFunc(); + advancePC(tc, inst); + } +}; + +// The "Flavor" template parameter is to keep warn, hack or inform messages +// with the same token from blocking each other. +template +class M5DebugOnceFault : public M5DebugFault +{ + protected: + bool &once; + + template + static bool & + lookUpToken(const OnceToken &token) + { + static std::map tokenMap; + return tokenMap[token]; } + public: + template + M5DebugOnceFault(const OnceToken &token, const std::string &format, + const Args &...args) : + M5DebugFault(format, args...), once(lookUpToken(token)) + {} + void invoke(ThreadContext *tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr) + StaticInst::nullStaticInstPtr) override { - switch (func) { - case PanicFunc: - panic(message); - break; - case FatalFunc: - fatal(message); - break; - case WarnFunc: - warn(message); - break; - case WarnOnceFunc: - warn_once(message); - break; - default: - panic("unrecognized debug function number\n"); + if (!once) { + once = true; + debugFunc(); } + advancePC(tc, inst); } }; -template -class M5VarArgsFault : public M5DebugFault +class M5PanicFault : public M5DebugFault { public: - template - M5VarArgsFault(const std::string &format, const Args &...args) : - M5DebugFault((DebugFunc)Func, csprintf(format, args...)) - {} + using M5DebugFault::M5DebugFault; + void debugFunc() override { panic(message()); } + FaultName name() const override { return "panic fault"; } +}; + +class M5FatalFault : public M5DebugFault +{ + public: + using M5DebugFault::M5DebugFault; + void debugFunc() override { fatal(message()); } + FaultName name() const override { return "fatal fault"; } +}; + +template +class M5WarnFaultBase : public Base +{ + public: + using Base::Base; + void debugFunc() override { warn(this->message()); } + FaultName name() const override { return "warn fault"; } +}; + +using M5WarnFault = M5WarnFaultBase; +using M5WarnOnceFault = M5WarnFaultBase>; + +template +class M5HackFaultBase : public Base +{ + public: + using Base::Base; + void debugFunc() override { hack(this->message()); } + FaultName name() const override { return "hack fault"; } +}; + +using M5HackFault = M5HackFaultBase; +using M5HackOnceFault = M5HackFaultBase>; + +template +class M5InformFaultBase : public Base +{ + public: + using Base::Base; + void debugFunc() override { inform(this->message()); } + FaultName name() const override { return "inform fault"; } }; -typedef M5VarArgsFault M5PanicFault; -typedef M5VarArgsFault M5FatalFault; -typedef M5VarArgsFault M5WarnFault; -typedef M5VarArgsFault M5WarnOnceFault; +using M5InformFault = M5InformFaultBase; +using M5InformOnceFault = + M5InformFaultBase>; } // namespace GenericISA diff --git a/src/arch/x86/insts/badmicroop.cc b/src/arch/x86/insts/badmicroop.cc index 09248738d..5d9c381f0 100644 --- a/src/arch/x86/insts/badmicroop.cc +++ b/src/arch/x86/insts/badmicroop.cc @@ -39,6 +39,7 @@ #include "arch/x86/insts/badmicroop.hh" +#include "arch/generic/debugfaults.hh" #include "arch/x86/generated/decoder.hh" #include "arch/x86/isa_traits.hh" @@ -56,8 +57,8 @@ namespace X86ISA // try to delete the static memory when it was destructed. const StaticInstPtr badMicroop = - new X86ISAInst::MicroPanic(dummyMachInst, "BAD", + new X86ISAInst::MicroDebug(dummyMachInst, "panic", "BAD", StaticInst::IsMicroop | StaticInst::IsLastMicroop, - "Invalid microop!", 0); + new GenericISA::M5PanicFault("Invalid microop!")); } // namespace X86ISA diff --git a/src/arch/x86/isa/microops/debug.isa b/src/arch/x86/isa/microops/debug.isa index 6852f6826..da1f9fc6d 100644 --- a/src/arch/x86/isa/microops/debug.isa +++ b/src/arch/x86/isa/microops/debug.isa @@ -42,21 +42,21 @@ ////////////////////////////////////////////////////////////////////////// output header {{ - class MicroDebugBase : public X86ISA::X86MicroopBase + class MicroDebug : public X86ISA::X86MicroopBase { protected: - typedef GenericISA::M5DebugFault::DebugFunc DebugFunc; - DebugFunc func; - std::string message; - uint8_t cc; + std::shared_ptr fault; public: - MicroDebugBase(ExtMachInst machInst, const char * mnem, - const char * instMnem, uint64_t setFlags, - DebugFunc _func, std::string _message, uint8_t _cc) : - X86MicroopBase(machInst, mnem, instMnem, setFlags, No_OpClass), - func(_func), message(_message), cc(_cc) - {} + MicroDebug(ExtMachInst _machInst, const char *mnem, + const char *instMnem, uint64_t setFlags, + GenericISA::M5DebugFault *_fault); + + Fault + execute(ExecContext *xc, Trace::InstRecord *traceData) const + { + return fault; + } std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const @@ -64,25 +64,37 @@ output header {{ std::stringstream response; printMnemonic(response, instMnem, mnemonic); - response << "\"" << message << "\""; + response << "\"" << fault->message() << "\""; return response.str(); } }; -}}; -def template MicroDebugDeclare {{ - class %(class_name)s : public %(base_class)s + class MicroDebugFlags : public MicroDebug { + protected: + uint8_t cc; + public: - %(class_name)s(ExtMachInst _machInst, const char * instMnem, - uint64_t setFlags, std::string _message, uint8_t _cc); + MicroDebugFlags(ExtMachInst _machInst, const char *mnem, + const char *instMnem, uint64_t setFlags, + GenericISA::M5DebugFault *_fault, uint8_t _cc); Fault execute(ExecContext *, Trace::InstRecord *) const; }; }}; -def template MicroDebugExecute {{ +output decoder {{ + MicroDebug::MicroDebug(ExtMachInst _machInst, const char *mnem, + const char *instMnem, uint64_t setFlags, + GenericISA::M5DebugFault *_fault) : + X86ISA::X86MicroopBase(_machInst, mnem, instMnem, + setFlags, No_OpClass), + fault(_fault) + {} +}}; + +def template MicroDebugFlagsExecute {{ Fault %(class_name)s::execute(ExecContext *xc, Trace::InstRecord *traceData) const @@ -90,82 +102,95 @@ def template MicroDebugExecute {{ %(op_decl)s %(op_rd)s if (%(cond_test)s) { - return std::make_shared(func, - message); + return %(base_class)s::execute(xc, traceData); } else { return NoFault; } } }}; -def template MicroDebugConstructor {{ +def template MicroDebugFlagsConstructor {{ %(class_name)s::%(class_name)s( - ExtMachInst machInst, const char * instMnem, uint64_t setFlags, - std::string _message, uint8_t _cc) : - %(base_class)s(machInst, "%(func)s", instMnem, - setFlags, %(func_num)s, _message, _cc) + ExtMachInst machInst, const char *mnem, + const char *instMnem, uint64_t setFlags, + GenericISA::M5DebugFault *_fault, uint8_t _cc) : + %(base_class)s(machInst, mnem, instMnem, setFlags, _fault), + cc(_cc) { %(constructor)s; } }}; +let {{ + iop = InstObjParams("", "MicroDebugFlags", "MicroDebug", + {"code": "", + "cond_test": "checkCondition(ccFlagBits | cfofBits | \ + dfBit | ecfBit | ezfBit, cc)"}) + exec_output = MicroDebugFlagsExecute.subst(iop) + decoder_output = MicroDebugFlagsConstructor.subst(iop) +}}; + let {{ class MicroDebug(X86Microop): - def __init__(self, message, flags=None): + def __init__(self, name, fault, message, once, flags): + self.name = name + self.fault = fault self.message = message - if flags: - if not isinstance(flags, (list, tuple)): - raise Exception, "flags must be a list or tuple of flags" - self.cond = " | ".join(flags) - self.className += "Flags" - else: - self.cond = "0" + self.once = once + self.flags = flags + if flags and not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + + self.className = "MicroDebugFlags" if flags else "MicroDebug" def getAllocator(self, microFlags): - allocator = '''new %(class_name)s(machInst, macrocodeBlock, - %(flags)s, "%(message)s", %(cc)s)''' % { - "class_name" : self.className, - "flags" : self.microFlagsText(microFlags), - "message" : self.message, - "cc" : self.cond} - return allocator - - exec_output = "" - header_output = "" - decoder_output = "" - - def buildDebugMicro(func, func_num): - global exec_output, header_output, decoder_output - - iop = InstObjParams(func, "Micro%sFlags" % func.capitalize(), - "MicroDebugBase", - {"code": "", - "func": func, - "func_num": "GenericISA::M5DebugFault::%s" % func_num, - "cond_test": "checkCondition(ccFlagBits | cfofBits | \ - dfBit | ecfBit | ezfBit, cc)"}) - exec_output += MicroDebugExecute.subst(iop) - header_output += MicroDebugDeclare.subst(iop) - decoder_output += MicroDebugConstructor.subst(iop) - - iop = InstObjParams(func, "Micro%s" % func.capitalize(), - "MicroDebugBase", - {"code": "", - "func": func, - "func_num": "GenericISA::M5DebugFault::%s" % func_num, - "cond_test": "true"}) - exec_output += MicroDebugExecute.subst(iop) - header_output += MicroDebugDeclare.subst(iop) - decoder_output += MicroDebugConstructor.subst(iop) + if self.once: + fault_allocator_template = \ + "new %(fault_type)s(%(token)s, %(message)s)" + else: + fault_allocator_template = \ + "new %(fault_type)s(%(message)s)" + fault_allocator = fault_allocator_template % { + "fault_type": self.fault, + "token": "std::string(\"%s\")" % self.message, + "message": "\"%s\"" % self.message + } - class MicroDebugChild(MicroDebug): - className = "Micro%s" % func.capitalize() + args = ["machInst", "\"%s\"" % self.name, "macrocodeBlock", + self.microFlagsText(microFlags), fault_allocator] + + if self.flags: + args.append(" | ".join(self.flags)) + + return "new " + self.className + "(" + ", ".join(args) + ")" + def buildDebugMicro(name, with_once=False): global microopClasses - microopClasses[func] = MicroDebugChild - buildDebugMicro("panic", "PanicFunc") - buildDebugMicro("fatal", "FatalFunc") - buildDebugMicro("warn", "WarnFunc") - buildDebugMicro("warn_once", "WarnOnceFunc") + fault_class = "GenericISA::M5" + name.capitalize() + "Fault" + + class MicroDebugChild(MicroDebug): + def __init__(self, message, flags=None): + super(MicroDebugChild, self).__init__( + name, fault_class, message, False, flags) + + microopClasses[name] = MicroDebugChild + + if with_once: + fault_once_class = \ + "GenericISA::M5" + name.capitalize() + "OnceFault" + name_once = name + "_once" + + class MicroDebugOnceChild(MicroDebug): + def __init__(self, message, flags=None): + super(MicroDebugOnceChild, self).__init__( + name_once, fault_once_class, message, True, flags) + + microopClasses[name_once] = MicroDebugOnceChild + + buildDebugMicro("panic") + buildDebugMicro("fatal") + buildDebugMicro("hack", True) + buildDebugMicro("inform", True) + buildDebugMicro("warn", True) }}; -- 2.30.2