* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Lisa Hsu
*/
#ifndef __ARCH_SPARC_INTERRUPT_HH__
#define __ARCH_SPARC_INTERRUPT_HH__
#include "arch/sparc/faults.hh"
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/registers.hh"
#include "cpu/thread_context.hh"
+#include "debug/Interrupt.hh"
+#include "params/SparcInterrupts.hh"
+#include "sim/sim_object.hh"
namespace SparcISA
{
-enum interrupts_t {
- trap_level_zero,
- hstick_match,
- interrupt_vector,
- cpu_mondo,
- dev_mondo,
- resumable_error,
- soft_interrupt,
- num_interrupt_types
+enum InterruptTypes
+{
+ IT_TRAP_LEVEL_ZERO,
+ IT_HINTP,
+ IT_INT_VEC,
+ IT_CPU_MONDO,
+ IT_DEV_MONDO,
+ IT_RES_ERROR,
+ IT_SOFT_INT,
+ NumInterruptTypes
};
- class Interrupts
+class Interrupts : public SimObject
+{
+ private:
+ BaseCPU * cpu;
+
+ uint64_t interrupts[NumInterruptTypes];
+ uint64_t intStatus;
+
+ public:
+
+ void
+ setCPU(BaseCPU * _cpu)
{
+ cpu = _cpu;
+ }
- private:
+ typedef SparcInterruptsParams Params;
- bool interrupts[num_interrupt_types];
- int numPosted;
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
- public:
- Interrupts()
- {
- for (int i = 0; i < num_interrupt_types; ++i) {
- interrupts[i] = false;
- }
- numPosted = 0;
- }
+ Interrupts(Params * p) : SimObject(p), cpu(NULL)
+ {
+ clearAll();
+ }
- void post(int int_type)
- {
- if (int_type < 0 || int_type >= num_interrupt_types)
- panic("posting unknown interrupt!\n");
+ int
+ InterruptLevel(uint64_t softint)
+ {
+ if (softint & 0x10000 || softint & 0x1)
+ return 14;
- if (interrupts[int_type] == false) {
- interrupts[int_type] = true;
- ++numPosted;
- }
- }
+ int level = 15;
+ while (level > 0 && !(1 << level & softint))
+ level--;
+ if (1 << level & softint)
+ return level;
+ return 0;
+ }
- void post(int int_num, int index)
- {
+ void
+ post(int int_num, int index)
+ {
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+ assert(int_num >= 0 && int_num < NumInterruptTypes);
+ assert(index >= 0 && index < 64);
- }
+ interrupts[int_num] |= ULL(1) << index;
+ intStatus |= ULL(1) << int_num;
+ }
+
+ void
+ clear(int int_num, int index)
+ {
+ DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
+ assert(int_num >= 0 && int_num < NumInterruptTypes);
+ assert(index >= 0 && index < 64);
- void clear(int int_num, int index)
- {
+ interrupts[int_num] &= ~(ULL(1) << index);
+ if (!interrupts[int_num])
+ intStatus &= ~(ULL(1) << int_num);
+ }
+ void
+ clearAll()
+ {
+ for (int i = 0; i < NumInterruptTypes; ++i) {
+ interrupts[i] = 0;
}
+ intStatus = 0;
+ }
- void clear_all()
- {
+ bool
+ checkInterrupts(ThreadContext *tc) const
+ {
+ if (!intStatus)
+ return false;
- }
+ HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+ PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
- bool check_interrupts(ThreadContext * tc) const
- {
- if (numPosted)
+ // THESE ARE IN ORDER OF PRIORITY
+ // since there are early returns, and the highest
+ // priority interrupts should get serviced,
+ // it is v. important that new interrupts are inserted
+ // in the right order of processing
+ if (hpstate.hpriv) {
+ if (pstate.ie) {
+ if (interrupts[IT_HINTP]) {
+ // This will be cleaned by a HINTP write
+ return true;
+ }
+ if (interrupts[IT_INT_VEC]) {
+ // this will be cleared by an ASI read (or write)
+ return true;
+ }
+ }
+ } else {
+ if (interrupts[IT_TRAP_LEVEL_ZERO]) {
+ // this is cleared by deasserting HPSTATE::tlz
return true;
- else
- return false;
- }
+ }
+ // HStick matches always happen in priv mode (ie doesn't matter)
+ if (interrupts[IT_HINTP]) {
+ return true;
+ }
+ if (interrupts[IT_INT_VEC]) {
+ // this will be cleared by an ASI read (or write)
+ return true;
+ }
+ if (pstate.ie) {
+ if (interrupts[IT_CPU_MONDO]) {
+ return true;
+ }
+ if (interrupts[IT_DEV_MONDO]) {
+ return true;
+ }
+ if (interrupts[IT_SOFT_INT]) {
+ return true;
+ }
+
+ if (interrupts[IT_RES_ERROR]) {
+ return true;
+ }
+ } // !hpriv && pstate.ie
+ } // !hpriv
- Fault getInterrupt(ThreadContext * tc)
- {
- int hpstate = tc->readMiscReg(MISCREG_HPSTATE);
- int pstate = tc->readMiscReg(MISCREG_PSTATE);
- bool ie = pstate & PSTATE::ie;
-
- // THESE ARE IN ORDER OF PRIORITY
- // since there are early returns, and the highest
- // priority interrupts should get serviced,
- // it is v. important that new interrupts are inserted
- // in the right order of processing
- if (hpstate & HPSTATE::hpriv) {
- if (ie) {
- if (interrupts[hstick_match]) {
- if (tc->readMiscReg(MISCREG_HINTP) & 1) {
- interrupts[hstick_match] = false;
- --numPosted;
- return new HstickMatch;
- }
- }
- if (interrupts[interrupt_vector]) {
- interrupts[interrupt_vector] = false;
- --numPosted;
- //HAVEN'T IMPLed THIS YET
- return NoFault;
- }
- } else {
- if (interrupts[hstick_match]) {
- return NoFault;
- }
+ return false;
+ }
+ Fault
+ getInterrupt(ThreadContext *tc)
+ {
+ assert(checkInterrupts(tc));
+
+ HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
+ PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
+
+ // THESE ARE IN ORDER OF PRIORITY
+ // since there are early returns, and the highest
+ // priority interrupts should get serviced,
+ // it is v. important that new interrupts are inserted
+ // in the right order of processing
+ if (hpstate.hpriv) {
+ if (pstate.ie) {
+ if (interrupts[IT_HINTP]) {
+ // This will be cleaned by a HINTP write
+ return std::make_shared<HstickMatch>();
+ }
+ if (interrupts[IT_INT_VEC]) {
+ // this will be cleared by an ASI read (or write)
+ return std::make_shared<InterruptVector>();
+ }
+ }
+ } else {
+ if (interrupts[IT_TRAP_LEVEL_ZERO]) {
+ // this is cleared by deasserting HPSTATE::tlz
+ return std::make_shared<TrapLevelZero>();
+ }
+ // HStick matches always happen in priv mode (ie doesn't matter)
+ if (interrupts[IT_HINTP]) {
+ return std::make_shared<HstickMatch>();
+ }
+ if (interrupts[IT_INT_VEC]) {
+ // this will be cleared by an ASI read (or write)
+ return std::make_shared<InterruptVector>();
+ }
+ if (pstate.ie) {
+ if (interrupts[IT_CPU_MONDO]) {
+ return std::make_shared<CpuMondo>();
}
- } else {
- if (interrupts[trap_level_zero]) {
- if ((pstate & HPSTATE::tlz) && (tc->readMiscReg(MISCREG_TL) == 0)) {
- interrupts[trap_level_zero] = false;
- --numPosted;
- return new TrapLevelZero;
- }
+ if (interrupts[IT_DEV_MONDO]) {
+ return std::make_shared<DevMondo>();
}
- if (interrupts[hstick_match]) {
- if (tc->readMiscReg(MISCREG_HINTP) & 1) {
- interrupts[hstick_match] = false;
- --numPosted;
- return new HstickMatch;
- }
+ if (interrupts[IT_SOFT_INT]) {
+ int level = InterruptLevel(interrupts[IT_SOFT_INT]);
+ return std::make_shared<InterruptLevelN>(level);
}
- if (ie) {
- if (interrupts[cpu_mondo]) {
- interrupts[cpu_mondo] = false;
- --numPosted;
- return new CpuMondo;
- }
- if (interrupts[dev_mondo]) {
- interrupts[dev_mondo] = false;
- --numPosted;
- return new DevMondo;
- }
- if (interrupts[soft_interrupt]) {
- int il = InterruptLevel(tc->readMiscReg(MISCREG_SOFTINT));
- // it seems that interrupt vectors are right in
- // the middle of interrupt levels with regard to
- // priority, so have to check
- if ((il < 6) &&
- interrupts[interrupt_vector]) {
- // may require more details here since there
- // may be lots of interrupts embedded in an
- // platform interrupt vector
- interrupts[interrupt_vector] = false;
- --numPosted;
- //HAVEN'T IMPLed YET
- return NoFault;
- } else {
- if (il > tc->readMiscReg(MISCREG_PIL)) {
- uint64_t si = tc->readMiscReg(MISCREG_SOFTINT);
- uint64_t more = si & ~(1 << (il + 1));
- if (!InterruptLevel(more)) {
- interrupts[soft_interrupt] = false;
- --numPosted;
- }
- return new InterruptLevelN(il);
- }
- }
- }
- if (interrupts[resumable_error]) {
- interrupts[resumable_error] = false;
- --numPosted;
- return new ResumableError;
- }
+
+ if (interrupts[IT_RES_ERROR]) {
+ return std::make_shared<ResumableError>();
}
- }
- return NoFault;
- }
+ } // !hpriv && pstate.ie
+ } // !hpriv
+ return NoFault;
+ }
- void updateIntrInfo(ThreadContext * tc)
- {
+ void
+ updateIntrInfo(ThreadContext *tc)
+ {}
- }
+ uint64_t
+ get_vec(int int_num)
+ {
+ assert(int_num >= 0 && int_num < NumInterruptTypes);
+ return interrupts[int_num];
+ }
- void serialize(std::ostream &os)
- {
- }
+ void
+ serialize(CheckpointOut &cp) const override
+ {
+ SERIALIZE_ARRAY(interrupts,NumInterruptTypes);
+ SERIALIZE_SCALAR(intStatus);
+ }
- void unserialize(Checkpoint *cp, const std::string §ion)
- {
- }
- };
-}
+ void
+ unserialize(CheckpointIn &cp) override
+ {
+ UNSERIALIZE_ARRAY(interrupts,NumInterruptTypes);
+ UNSERIALIZE_SCALAR(intStatus);
+ }
+};
+} // namespace SPARC_ISA
#endif // __ARCH_SPARC_INTERRUPT_HH__