MIPS: Final overhaul of MIPS faults to kill #if FULL_SYSTEM

This change is a significant reorganization of the MIPS fault code that gets
rid of duplication, fixes some bugs, doubtlessly introduces others, and adds
names for the exception code constants.
This commit is contained in:
Gabe Black 2011-09-19 06:17:21 -07:00
parent 4455fc484d
commit 9a38dc6194
2 changed files with 226 additions and 313 deletions

View file

@ -48,54 +48,56 @@ namespace MipsISA
typedef MipsFaultBase::FaultVals FaultVals;
template <> FaultVals MipsFault<MachineCheckFault>::vals =
{ "Machine Check", 0x0401 };
template <> FaultVals MipsFault<ResetFault>::vals =
#if FULL_SYSTEM
{ "Reset Fault", 0xBFC00000};
#else
{ "Reset Fault", 0x001};
#endif
template <> FaultVals MipsFault<AddressErrorFault>::vals =
{ "Address Error", 0x0180 };
template <> FaultVals MipsFault<SystemCallFault>::vals =
{ "Syscall", 0x0180 };
template <> FaultVals MipsFault<CoprocessorUnusableFault>::vals =
{ "Coprocessor Unusable Fault", 0x180 };
{ "Syscall", 0x180, ExcCodeSys };
template <> FaultVals MipsFault<ReservedInstructionFault>::vals =
{ "Reserved Instruction Fault", 0x0180 };
{ "Reserved Instruction Fault", 0x180, ExcCodeRI };
template <> FaultVals MipsFault<ThreadFault>::vals =
{ "Thread Fault", 0x00F1 };
{ "Thread Fault", 0x180, ExcCodeDummy };
template <> FaultVals MipsFault<IntegerOverflowFault>::vals =
{ "Integer Overflow Exception", 0x180 };
template <> FaultVals MipsFault<InterruptFault>::vals =
{ "interrupt", 0x0180 };
{ "Integer Overflow Exception", 0x180, ExcCodeOv };
template <> FaultVals MipsFault<TrapFault>::vals =
{ "Trap", 0x0180 };
{ "Trap", 0x180, ExcCodeTr };
template <> FaultVals MipsFault<BreakpointFault>::vals =
{ "Breakpoint", 0x0180 };
template <> FaultVals MipsFault<TlbInvalidFault>::vals =
{ "Invalid TLB Entry Exception", 0x0180 };
template <> FaultVals MipsFault<TlbRefillFault>::vals =
{ "TLB Refill Exception", 0x0180 };
template <> FaultVals MipsFault<TlbModifiedFault>::vals =
{ "TLB Modified Exception", 0x0180 };
{ "Breakpoint", 0x180, ExcCodeBp };
template <> FaultVals MipsFault<DspStateDisabledFault>::vals =
{ "DSP Disabled Fault", 0x001a };
{ "DSP Disabled Fault", 0x180, ExcCodeDummy };
template <> FaultVals MipsFault<MachineCheckFault>::vals =
{ "Machine Check", 0x180, ExcCodeMCheck };
template <> FaultVals MipsFault<ResetFault>::vals =
{ "Reset Fault", 0x000, ExcCodeDummy };
template <> FaultVals MipsFault<SoftResetFault>::vals =
{ "Soft Reset Fault", 0x000, ExcCodeDummy };
template <> FaultVals MipsFault<NonMaskableInterrupt>::vals =
{ "Non Maskable Interrupt", 0x000, ExcCodeDummy };
template <> FaultVals MipsFault<CoprocessorUnusableFault>::vals =
{ "Coprocessor Unusable Fault", 0x180, ExcCodeCpU };
template <> FaultVals MipsFault<InterruptFault>::vals =
{ "Interrupt", 0x000, ExcCodeInt };
template <> FaultVals MipsFault<AddressErrorFault>::vals =
{ "Address Error", 0x180, ExcCodeDummy };
template <> FaultVals MipsFault<TlbInvalidFault>::vals =
{ "Invalid TLB Entry Exception", 0x180, ExcCodeDummy };
template <> FaultVals MipsFault<TlbRefillFault>::vals =
{ "TLB Refill Exception", 0x180, ExcCodeDummy };
template <> FaultVals MipsFault<TlbModifiedFault>::vals =
{ "TLB Modified Exception", 0x180, ExcCodeMod };
void
MipsFaultBase::setExceptionState(ThreadContext *tc, uint8_t excCode)
@ -129,118 +131,28 @@ MipsFaultBase::setExceptionState(ThreadContext *tc, uint8_t excCode)
tc->setMiscRegNoEffect(MISCREG_CAUSE, cause);
}
#if FULL_SYSTEM
void
IntegerOverflowFault::invoke(ThreadContext *tc, StaticInstPtr inst)
MipsFaultBase::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, 0xC);
// Set new PC
StatusReg status = tc->readMiscReg(MISCREG_STATUS);
if (!status.bev) {
// See MIPS ARM Vol 3, Revision 2, Page 38
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
if (FULL_SYSTEM) {
DPRINTF(MipsPRA, "Fault %s encountered.\n", name());
setExceptionState(tc, code());
tc->pcState(vect(tc));
} else {
tc->pcState(0xBFC00200);
panic("Fault %s encountered.\n", name());
}
}
void
TrapFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, 0xD);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
}
void
BreakpointFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
setExceptionState(tc, 0x9);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
}
void
AddressErrorFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, store ? 0x5 : 0x4);
tc->setMiscRegNoEffect(MISCREG_BADVADDR, vaddr);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
}
void
TlbInvalidFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
setTlbExceptionState(tc, store ? 0x3 : 0x2);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
}
void
TlbRefillFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
// Since handler depends on EXL bit, must check EXL bit before setting it!!
StatusReg status = tc->readMiscReg(MISCREG_STATUS);
setTlbExceptionState(tc, store ? 0x3 : 0x2);
// See MIPS ARM Vol 3, Revision 2, Page 38
if (status.exl == 1) {
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
} else {
tc->pcState(tc->readMiscReg(MISCREG_EBASE));
}
}
void
TlbModifiedFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
setTlbExceptionState(tc, 0x1);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
}
void
SystemCallFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, 0x8);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
}
void
InterruptFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, 0x0A);
CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE);
if (cause.iv) {
// Offset 200 for release 2
tc->pcState(0x20 + vect() + tc->readMiscRegNoEffect(MISCREG_EBASE));
} else {
//Ofset at 180 for release 1
tc->pcState(vect() + tc->readMiscRegNoEffect(MISCREG_EBASE));
}
}
#endif // FULL_SYSTEM
void
ResetFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
#if FULL_SYSTEM
DPRINTF(MipsPRA, "%s encountered.\n", name());
/* All reset activity must be invoked from here */
tc->pcState(vect());
DPRINTF(MipsPRA, "ResetFault::invoke : PC set to %x", tc->readPC());
#endif
if (FULL_SYSTEM) {
DPRINTF(MipsPRA, "%s encountered.\n", name());
/* All reset activity must be invoked from here */
Addr handler = vect(tc);
tc->pcState(handler);
DPRINTF(MipsPRA, "ResetFault::invoke : PC set to %x", handler);
}
// Set Coprocessor 1 (Floating Point) To Usable
StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
@ -249,46 +161,15 @@ ResetFault::invoke(ThreadContext *tc, StaticInstPtr inst)
}
void
ReservedInstructionFault::invoke(ThreadContext *tc, StaticInstPtr inst)
SoftResetFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
#if FULL_SYSTEM
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, 0x0A);
tc->pcState(vect() + tc->readMiscRegNoEffect(MISCREG_EBASE));
#else
panic("%s encountered.\n", name());
#endif
panic("Soft reset not implemented.\n");
}
void
ThreadFault::invoke(ThreadContext *tc, StaticInstPtr inst)
NonMaskableInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
panic("%s encountered.\n", name());
}
void
DspStateDisabledFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
panic("%s encountered.\n", name());
}
void
CoprocessorUnusableFault::invoke(ThreadContext *tc, StaticInstPtr inst)
{
#if FULL_SYSTEM
DPRINTF(MipsPRA, "%s encountered.\n", name());
setExceptionState(tc, 0xb);
// The ID of the coprocessor causing the exception is stored in
// CoprocessorUnusableFault::coProcID
CauseReg cause = tc->readMiscReg(MISCREG_CAUSE);
cause.ce = coProcID;
tc->setMiscRegNoEffect(MISCREG_CAUSE, cause);
tc->pcState(vect() + tc->readMiscReg(MISCREG_EBASE));
#else
warn("%s (CP%d) encountered.\n", name(), coProcID);
#endif
panic("Non maskable interrupt not implemented.\n");
}
} // namespace MipsISA

View file

@ -44,21 +44,63 @@ namespace MipsISA
typedef const Addr FaultVect;
enum ExcCode {
// A dummy value to use when the code isn't defined or doesn't matter.
ExcCodeDummy = 0,
ExcCodeInt = 0,
ExcCodeMod = 1,
ExcCodeTlbL = 2,
ExcCodeTlbS = 3,
ExcCodeAdEL = 4,
ExcCodeAdES = 5,
ExcCodeIBE = 6,
ExcCodeDBE = 7,
ExcCodeSys = 8,
ExcCodeBp = 9,
ExcCodeRI = 10,
ExcCodeCpU = 11,
ExcCodeOv = 12,
ExcCodeTr = 13,
ExcCodeC2E = 18,
ExcCodeMDMX = 22,
ExcCodeWatch = 23,
ExcCodeMCheck = 24,
ExcCodeThread = 25,
ExcCodeCacheErr = 30
};
class MipsFaultBase : public FaultBase
{
public:
struct FaultVals
{
const FaultName name;
const FaultVect vect;
const FaultVect offset;
const ExcCode code;
};
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInst::StaticInstPtr inst = StaticInst::nullStaticInstPtr)
{}
#endif
void setExceptionState(ThreadContext *, uint8_t);
virtual FaultVect offset(ThreadContext *tc) const = 0;
virtual ExcCode code() const = 0;
virtual FaultVect base(ThreadContext *tc) const
{
StatusReg status = tc->readMiscReg(MISCREG_STATUS);
if (status.bev)
return tc->readMiscReg(MISCREG_EBASE);
else
return 0xbfc00200;
}
FaultVect
vect(ThreadContext *tc) const
{
return base(tc) + offset(tc);
}
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
template <typename T>
@ -68,7 +110,81 @@ class MipsFault : public MipsFaultBase
static FaultVals vals;
public:
FaultName name() const { return vals.name; }
FaultVect vect() const { return vals.vect; }
FaultVect offset(ThreadContext *tc) const { return vals.offset; }
ExcCode code() const { return vals.code; }
};
class SystemCallFault : public MipsFault<SystemCallFault> {};
class ReservedInstructionFault : public MipsFault<ReservedInstructionFault> {};
class ThreadFault : public MipsFault<ThreadFault> {};
class IntegerOverflowFault : public MipsFault<IntegerOverflowFault> {};
class TrapFault : public MipsFault<TrapFault> {};
class BreakpointFault : public MipsFault<BreakpointFault> {};
class DspStateDisabledFault : public MipsFault<DspStateDisabledFault> {};
class MachineCheckFault : public MipsFault<MachineCheckFault>
{
public:
bool isMachineCheckFault() { return true; }
};
static inline Fault genMachineCheckFault()
{
return new MachineCheckFault;
}
class ResetFault : public MipsFault<ResetFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class SoftResetFault : public MipsFault<SoftResetFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class NonMaskableInterrupt : public MipsFault<NonMaskableInterrupt>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class CoprocessorUnusableFault : public MipsFault<CoprocessorUnusableFault>
{
protected:
int coProcID;
public:
CoprocessorUnusableFault(int _procid) : coProcID(_procid)
{}
void
invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr)
{
MipsFault<CoprocessorUnusableFault>::invoke(tc, inst);
if (FULL_SYSTEM) {
CauseReg cause = tc->readMiscReg(MISCREG_CAUSE);
cause.ce = coProcID;
tc->setMiscReg(MISCREG_CAUSE, cause);
}
}
};
class InterruptFault : public MipsFault<InterruptFault>
{
public:
FaultVect
offset(ThreadContext *tc) const
{
CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE);
return cause.iv ? 0x200 : 0x000;
}
};
template <typename T>
@ -80,6 +196,30 @@ class AddressFault : public MipsFault<T>
AddressFault(Addr _vaddr, bool _store) : vaddr(_vaddr), store(_store)
{}
void
invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr)
{
MipsFault<T>::invoke(tc, inst);
if (FULL_SYSTEM)
tc->setMiscRegNoEffect(MISCREG_BADVADDR, vaddr);
}
};
class AddressErrorFault : public AddressFault<AddressErrorFault>
{
public:
AddressErrorFault(Addr _vaddr, bool _store) :
AddressFault<AddressErrorFault>(_vaddr, _store)
{}
ExcCode
code() const
{
return store ? ExcCodeAdES : ExcCodeAdEL;
}
};
template <typename T>
@ -96,7 +236,6 @@ class TlbFault : public AddressFault<T>
void
setTlbExceptionState(ThreadContext *tc, uint8_t excCode)
{
DPRINTF(MipsPRA, "%s encountered.\n", name());
this->setExceptionState(tc, excCode);
tc->setMiscRegNoEffect(MISCREG_BADVADDR, this->vaddr);
@ -110,122 +249,25 @@ class TlbFault : public AddressFault<T>
context.badVPN2 = this->vpn >> 2;
tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
}
};
class MachineCheckFault : public MipsFault<MachineCheckFault>
{
public:
bool isMachineCheckFault() {return true;}
};
void
invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr)
{
if (FULL_SYSTEM) {
DPRINTF(MipsPRA, "Fault %s encountered.\n", name());
tc->pcState(this->vect(tc));
setTlbExceptionState(tc, this->code());
} else {
AddressFault<T>::invoke(tc, inst);
}
}
static inline Fault genMachineCheckFault()
{
return new MachineCheckFault;
}
class NonMaskableInterrupt : public MipsFault<NonMaskableInterrupt>
{
public:
bool isNonMaskableInterrupt() {return true;}
};
class AddressErrorFault : public AddressFault<AddressErrorFault>
{
public:
AddressErrorFault(Addr _vaddr, bool _store) :
AddressFault<AddressErrorFault>(_vaddr, _store)
{}
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class ResetFault : public MipsFault<ResetFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class SystemCallFault : public MipsFault<SystemCallFault>
{
public:
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class SoftResetFault : public MipsFault<SoftResetFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class CoprocessorUnusableFault : public MipsFault<CoprocessorUnusableFault>
{
protected:
int coProcID;
public:
CoprocessorUnusableFault(int _procid) : coProcID(_procid)
{}
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class ReservedInstructionFault : public MipsFault<ReservedInstructionFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class ThreadFault : public MipsFault<ThreadFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
};
class IntegerOverflowFault : public MipsFault<IntegerOverflowFault>
{
public:
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class InterruptFault : public MipsFault<InterruptFault>
{
public:
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class TrapFault : public MipsFault<TrapFault>
{
public:
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class BreakpointFault : public MipsFault<BreakpointFault>
{
public:
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
ExcCode
code() const
{
return this->store ? ExcCodeTlbS : ExcCodeTlbL;
}
};
class TlbRefillFault : public TlbFault<TlbRefillFault>
@ -234,10 +276,13 @@ class TlbRefillFault : public TlbFault<TlbRefillFault>
TlbRefillFault(Addr asid, Addr vaddr, Addr vpn, bool store) :
TlbFault<TlbRefillFault>(asid, vaddr, vpn, store)
{}
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
FaultVect
offset(ThreadContext *tc) const
{
StatusReg status = tc->readMiscReg(MISCREG_STATUS);
return status.exl ? 0x180 : 0x000;
}
};
class TlbInvalidFault : public TlbFault<TlbInvalidFault>
@ -246,10 +291,6 @@ class TlbInvalidFault : public TlbFault<TlbInvalidFault>
TlbInvalidFault(Addr asid, Addr vaddr, Addr vpn, bool store) :
TlbFault<TlbInvalidFault>(asid, vaddr, vpn, store)
{}
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class TlbModifiedFault : public TlbFault<TlbModifiedFault>
@ -258,17 +299,8 @@ class TlbModifiedFault : public TlbFault<TlbModifiedFault>
TlbModifiedFault(Addr asid, Addr vaddr, Addr vpn) :
TlbFault<TlbModifiedFault>(asid, vaddr, vpn, false)
{}
#if FULL_SYSTEM
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
#endif
};
class DspStateDisabledFault : public MipsFault<DspStateDisabledFault>
{
public:
void invoke(ThreadContext * tc,
StaticInstPtr inst = StaticInst::nullStaticInstPtr);
ExcCode code() const { return vals.code; }
};
} // namespace MipsISA