template<> ArmFault::FaultVals ArmFaultVals<ReExec>::vals =
{"ReExec Flush", 0x00, MODE_SVC, 0, 0, true, true}; // some dummy values
+template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals =
+ {"ArmSev Flush", 0x00, MODE_SVC, 0, 0, true, true}; // some dummy values
Addr
ArmFault::getVector(ThreadContext *tc)
{
cpsr.i = 1;
cpsr.e = sctlr.ee;
tc->setMiscReg(MISCREG_CPSR, cpsr);
+ // Make sure mailbox sets to one always
+ tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
tc->setIntReg(INTREG_LR, curPc +
(saved_cpsr.t ? thumbPcOffset() : armPcOffset()));
template void AbortFault<DataAbort>::invoke(ThreadContext *tc,
StaticInstPtr inst);
+void
+ArmSev::invoke(ThreadContext *tc, StaticInstPtr inst) {
+ DPRINTF(Faults, "Invoking ArmSev Fault\n");
+#if FULL_SYSTEM
+ // Set sev_mailbox to 1, clear the pending interrupt from remote
+ // SEV execution and let pipeline continue as pcState is still
+ // valid.
+ tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
+ tc->getCpuPtr()->clearInterrupt(INT_SEV, 0);
+#endif
+}
+
// return via SUBS pc, lr, xxx; rfe, movs, ldm
} // namespace ArmISA
return new Reset();
}
+// A fault that flushes the pipe, excluding the faulting instructions
+class ArmSev : public ArmFaultVals<ArmSev>
+{
+ public:
+ ArmSev () {}
+ void invoke(ThreadContext *tc,
+ StaticInstPtr inst = StaticInst::nullStaticInstPtr);
+};
+
} // namespace ArmISA
#endif // __ARM_FAULTS_HH__
return ((interrupts[INT_IRQ] && !cpsr.i) ||
(interrupts[INT_FIQ] && !cpsr.f) ||
(interrupts[INT_ABT] && !cpsr.a) ||
- (interrupts[INT_RST]));
+ (interrupts[INT_RST]) ||
+ (interrupts[INT_SEV]));
}
/**
ArmFault::AsynchronousExternalAbort);
if (interrupts[INT_RST])
return new Reset;
+ if (interrupts[INT_SEV])
+ return new ArmSev;
panic("intStatus and interrupts not in sync\n");
}
wfeCode = '''
#if FULL_SYSTEM
+ // WFE Sleeps if SevMailbox==0 and no unmasked interrupts are pending
if (SevMailbox == 1) {
SevMailbox = 0;
PseudoInst::quiesceSkip(xc->tcBase());
+ } else if (xc->tcBase()->getCpuPtr()->getInterruptController()->checkInterrupts(xc->tcBase())) {
+ PseudoInst::quiesceSkip(xc->tcBase());
} else {
PseudoInst::quiesce(xc->tcBase());
}
+#endif
+ '''
+ wfePredFixUpCode = '''
+#if FULL_SYSTEM
+ // WFE is predicated false, reset SevMailbox to reduce spurious sleeps
+ // and SEV interrupts
+ SevMailbox = 1;
#endif
'''
wfeIop = InstObjParams("wfe", "WfeInst", "PredOp", \
- { "code" : wfeCode, "predicate_test" : predicateTest },
+ { "code" : wfeCode,
+ "pred_fixup" : wfePredFixUpCode,
+ "predicate_test" : predicateTest },
["IsNonSpeculative", "IsQuiesce", "IsSerializeAfter"])
header_output += BasicDeclare.subst(wfeIop)
decoder_output += BasicConstructor.subst(wfeIop)
- exec_output += QuiescePredOpExecute.subst(wfeIop)
+ exec_output += QuiescePredOpExecuteWithFixup.subst(wfeIop)
wfiCode = '''
#if FULL_SYSTEM
exec_output += QuiescePredOpExecute.subst(wfiIop)
sevCode = '''
- // Need a way for O3 to not scoreboard these accesses as pipe flushes.
+#if FULL_SYSTEM
SevMailbox = 1;
System *sys = xc->tcBase()->getSystemPtr();
for (int x = 0; x < sys->numContexts(); x++) {
ThreadContext *oc = sys->getThreadContext(x);
if (oc == xc->tcBase())
continue;
- // Only wake if they were sleeping
+ // Wake CPU with interrupt if they were sleeping
if (oc->readMiscReg(MISCREG_SEV_MAILBOX) == 0) {
- oc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
- PseudoInst::wakeCPU(xc->tcBase(), x);
+ // Post Interrupt and wake cpu if needed
+ oc->getCpuPtr()->postInterrupt(INT_SEV, 0);
}
}
+#endif
'''
sevIop = InstObjParams("sev", "SevInst", "PredOp", \
{ "code" : sevCode, "predicate_test" : predicateTest },
}
}};
+def template QuiescePredOpExecuteWithFixup {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+ uint64_t resTemp = 0;
+ resTemp = resTemp;
+ %(op_decl)s;
+ %(op_rd)s;
+
+ if (%(predicate_test)s)
+ {
+ %(code)s;
+ if (fault == NoFault)
+ {
+ %(op_wb)s;
+ }
+ } else {
+ xc->setPredicate(false);
+ %(pred_fixup)s;
+#if FULL_SYSTEM
+ PseudoInst::quiesceSkip(xc->tcBase());
+#endif
+ }
+
+ return fault;
+ }
+}};
+
def template DataDecode {{
if (machInst.opcode4 == 0) {
if (machInst.sField == 0)
INT_ABT,
INT_IRQ,
INT_FIQ,
+ INT_SEV, // Special interrupt for recieving SEV's
NumInterruptTypes
};
} // namespace ArmISA
cpu->schedule(trap, curTick() + trapLatency);
trapInFlight[tid] = true;
+ thread[tid]->trapPending = true;
}
template <class Impl>
if (activateThreadEvent[tid].squashed())
reschedule(activateThreadEvent[tid],
nextCycle(curTick() + ticks(delay)));
- else if (!activateThreadEvent[tid].scheduled())
- schedule(activateThreadEvent[tid],
- nextCycle(curTick() + ticks(delay)));
+ else if (!activateThreadEvent[tid].scheduled()) {
+ Tick when = nextCycle(curTick() + ticks(delay));
+
+ // Check if the deallocateEvent is also scheduled, and make
+ // sure they do not happen at same time causing a sleep that
+ // is never woken from.
+ if (deallocateContextEvent[tid].scheduled() &&
+ deallocateContextEvent[tid].when() == when) {
+ when++;
+ }
+
+ schedule(activateThreadEvent[tid], when);
+ }
}
/** Unschedule actiavte thread event, regardless of its current state. */
template <class Impl>
void
-O3ThreadContext<Impl>::setMiscReg(int misc_reg,
- const MiscReg &val)
+O3ThreadContext<Impl>::setMiscReg(int misc_reg, const MiscReg &val)
{
cpu->setMiscReg(misc_reg, val, thread->threadId());