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 <gabeblack@google.com> Reviewed-by: Brandon Potter <Brandon.Potter@amd.com> Maintainer: Gabe Black <gabeblack@google.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -50,78 +50,125 @@ namespace GenericISA
|
||||
|
||||
class M5DebugFault : public FaultBase
|
||||
{
|
||||
public:
|
||||
enum DebugFunc
|
||||
{
|
||||
PanicFunc,
|
||||
FatalFunc,
|
||||
WarnFunc,
|
||||
WarnOnceFunc
|
||||
};
|
||||
|
||||
protected:
|
||||
std::string message;
|
||||
DebugFunc func;
|
||||
|
||||
public:
|
||||
M5DebugFault(DebugFunc _func, std::string _message) :
|
||||
message(_message), func(_func)
|
||||
{}
|
||||
|
||||
FaultName
|
||||
name() const
|
||||
std::string _message;
|
||||
virtual void debugFunc() = 0;
|
||||
void
|
||||
advancePC(ThreadContext *tc, const StaticInstPtr &inst)
|
||||
{
|
||||
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");
|
||||
if (inst) {
|
||||
auto pc = tc->pcState();
|
||||
inst->advancePC(pc);
|
||||
tc->pcState(pc);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
M5DebugFault(std::string _m) : _message(_m) {}
|
||||
|
||||
template <class ...Args>
|
||||
M5DebugFault(const std::string &format, const Args &...args) :
|
||||
_message(csprintf(format, args...))
|
||||
{}
|
||||
|
||||
std::string message() { return _message; }
|
||||
|
||||
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");
|
||||
}
|
||||
debugFunc();
|
||||
advancePC(tc, inst);
|
||||
}
|
||||
};
|
||||
|
||||
template <int Func>
|
||||
class M5VarArgsFault : public M5DebugFault
|
||||
// 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<typename ...Args>
|
||||
M5VarArgsFault(const std::string &format, const Args &...args) :
|
||||
M5DebugFault((DebugFunc)Func, csprintf(format, args...))
|
||||
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) override
|
||||
{
|
||||
if (!once) {
|
||||
once = true;
|
||||
debugFunc();
|
||||
}
|
||||
advancePC(tc, inst);
|
||||
}
|
||||
};
|
||||
|
||||
typedef M5VarArgsFault<M5DebugFault::PanicFunc> M5PanicFault;
|
||||
typedef M5VarArgsFault<M5DebugFault::FatalFunc> M5FatalFault;
|
||||
typedef M5VarArgsFault<M5DebugFault::WarnFunc> M5WarnFault;
|
||||
typedef M5VarArgsFault<M5DebugFault::WarnOnceFunc> M5WarnOnceFault;
|
||||
class M5PanicFault : public M5DebugFault
|
||||
{
|
||||
public:
|
||||
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"; }
|
||||
};
|
||||
|
||||
using M5InformFault = M5InformFaultBase<M5DebugFault>;
|
||||
using M5InformOnceFault =
|
||||
M5InformFaultBase<M5DebugOnceFault<M5InformFault>>;
|
||||
|
||||
} // namespace GenericISA
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<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
|
||||
@@ -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<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
|
||||
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
|
||||
}
|
||||
|
||||
exec_output = ""
|
||||
header_output = ""
|
||||
decoder_output = ""
|
||||
args = ["machInst", "\"%s\"" % self.name, "macrocodeBlock",
|
||||
self.microFlagsText(microFlags), fault_allocator]
|
||||
|
||||
def buildDebugMicro(func, func_num):
|
||||
global exec_output, header_output, decoder_output
|
||||
if self.flags:
|
||||
args.append(" | ".join(self.flags))
|
||||
|
||||
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)
|
||||
return "new " + self.className + "(" + ", ".join(args) + ")"
|
||||
|
||||
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)
|
||||
def buildDebugMicro(name, with_once=False):
|
||||
global microopClasses
|
||||
|
||||
fault_class = "GenericISA::M5" + name.capitalize() + "Fault"
|
||||
|
||||
class MicroDebugChild(MicroDebug):
|
||||
className = "Micro%s" % func.capitalize()
|
||||
def __init__(self, message, flags=None):
|
||||
super(MicroDebugChild, self).__init__(
|
||||
name, fault_class, message, False, flags)
|
||||
|
||||
global microopClasses
|
||||
microopClasses[func] = MicroDebugChild
|
||||
microopClasses[name] = MicroDebugChild
|
||||
|
||||
buildDebugMicro("panic", "PanicFunc")
|
||||
buildDebugMicro("fatal", "FatalFunc")
|
||||
buildDebugMicro("warn", "WarnFunc")
|
||||
buildDebugMicro("warn_once", "WarnOnceFunc")
|
||||
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)
|
||||
}};
|
||||
|
||||
Reference in New Issue
Block a user