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 <class ...Args>
+ 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 Flavor>
+class M5DebugOnceFault : public M5DebugFault
+{
+ protected:
+ bool &once;
+
+ template <class F, class OnceToken>
+ static bool &
+ lookUpToken(const OnceToken &token)
+ {
+ static std::map<OnceToken, bool> tokenMap;
+ return tokenMap[token];
}
+ public:
+ template <class OnceToken, class ...Args>
+ M5DebugOnceFault(const OnceToken &token, const std::string &format,
+ const Args &...args) :
+ M5DebugFault(format, args...), once(lookUpToken<Flavor>(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 <int Func>
-class M5VarArgsFault : public M5DebugFault
+class M5PanicFault : public M5DebugFault
{
public:
- template<typename ...Args>
- 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 Base>
+class M5WarnFaultBase : public Base
+{
+ public:
+ using Base::Base;
+ void debugFunc() override { warn(this->message()); }
+ FaultName name() const override { return "warn fault"; }
+};
+
+using M5WarnFault = M5WarnFaultBase<M5DebugFault>;
+using M5WarnOnceFault = M5WarnFaultBase<M5DebugOnceFault<M5WarnFault>>;
+
+template <class Base>
+class M5HackFaultBase : public Base
+{
+ public:
+ using Base::Base;
+ void debugFunc() override { hack(this->message()); }
+ FaultName name() const override { return "hack fault"; }
+};
+
+using M5HackFault = M5HackFaultBase<M5DebugFault>;
+using M5HackOnceFault = M5HackFaultBase<M5DebugOnceFault<M5HackFault>>;
+
+template <class Base>
+class M5InformFaultBase : public Base
+{
+ public:
+ using Base::Base;
+ void debugFunc() override { inform(this->message()); }
+ FaultName name() const override { return "inform fault"; }
};
-typedef M5VarArgsFault<M5DebugFault::PanicFunc> M5PanicFault;
-typedef M5VarArgsFault<M5DebugFault::FatalFunc> M5FatalFault;
-typedef M5VarArgsFault<M5DebugFault::WarnFunc> M5WarnFault;
-typedef M5VarArgsFault<M5DebugFault::WarnOnceFunc> M5WarnOnceFault;
+using M5InformFault = M5InformFaultBase<M5DebugFault>;
+using M5InformOnceFault =
+ M5InformFaultBase<M5DebugOnceFault<M5InformFault>>;
} // namespace GenericISA
//////////////////////////////////////////////////////////////////////////
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<GenericISA::M5DebugFault> 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
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
%(op_decl)s
%(op_rd)s
if (%(cond_test)s) {
- return std::make_shared<GenericISA::M5DebugFault>(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)
}};