X86: Implement the media floating point max instructions.
[gem5.git] / src / arch / x86 / interrupts.hh
index c4760dc0f4964c9b913c5d3ad68bf60c88dce734..e1bd676dbfa705f2eb56bac5aa33a2e7aa183db0 100644 (file)
@@ -60,6 +60,8 @@
 
 #include "arch/x86/apicregs.hh"
 #include "arch/x86/faults.hh"
+#include "arch/x86/intmessage.hh"
+#include "base/bitfield.hh"
 #include "cpu/thread_context.hh"
 #include "dev/io_device.hh"
 #include "dev/x86/intdev.hh"
 #include "sim/eventq.hh"
 
 class ThreadContext;
+class BaseCPU;
 
-namespace X86ISA
-{
+namespace X86ISA {
 
 class Interrupts : public BasicPioDevice, IntDev
 {
   protected:
+    // Storage for the APIC registers
     uint32_t regs[NUM_APIC_REGS];
+
+    BitUnion32(LVTEntry)
+        Bitfield<7, 0> vector;
+        Bitfield<10, 8> deliveryMode;
+        Bitfield<12> status;
+        Bitfield<13> polarity;
+        Bitfield<14> remoteIRR;
+        Bitfield<15> trigger;
+        Bitfield<16> masked;
+        Bitfield<17> periodic;
+    EndBitUnion(LVTEntry)
+
+    /*
+     * Timing related stuff.
+     */
     Tick latency;
     Tick clock;
 
     class ApicTimerEvent : public Event
     {
+      private:
+        Interrupts *localApic;
       public:
-        ApicTimerEvent() : Event()
+        ApicTimerEvent(Interrupts *_localApic) :
+            Event(), localApic(_localApic)
         {}
 
         void process()
         {
-            warn("Local APIC timer event doesn't do anything!\n");
+            assert(localApic);
+            if (localApic->triggerTimerInterrupt()) {
+                localApic->setReg(APIC_INITIAL_COUNT,
+                        localApic->readReg(APIC_INITIAL_COUNT));
+            }
         }
     };
 
     ApicTimerEvent apicTimerEvent;
 
-  public:
-    typedef X86LocalApicParams Params;
+    /*
+     * A set of variables to keep track of interrupts that don't go through
+     * the IRR.
+     */
+    bool pendingSmi;
+    uint8_t smiVector;
+    bool pendingNmi;
+    uint8_t nmiVector;
+    bool pendingExtInt;
+    uint8_t extIntVector;
+    bool pendingInit;
+    uint8_t initVector;
+    bool pendingStartup;
+    uint8_t startupVector;
+    bool startedUp;
+
+    // This is a quick check whether any of the above (except ExtInt) are set.
+    bool pendingUnmaskableInt;
+
+    // A count of how many IPIs are in flight.
+    int pendingIPIs;
+
+    /*
+     * IRR and ISR maintenance.
+     */
+    uint8_t IRRV;
+    uint8_t ISRV;
 
-    void setClock(Tick newClock)
+    int
+    findRegArrayMSB(ApicRegIndex base)
     {
-        clock = newClock;
+        int offset = 7;
+        do {
+            if (regs[base + offset] != 0) {
+                return offset * 32 + findMsbSet(regs[base + offset]);
+            }
+        } while (offset--);
+        return 0;
     }
 
-    const Params *
-    params() const
+    void
+    updateIRRV()
     {
-        return dynamic_cast<const Params *>(_params);
+        IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE);
     }
 
-    Tick read(PacketPtr pkt);
-    Tick write(PacketPtr pkt);
-    Tick recvMessage(PacketPtr pkt);
-
-    void addressRanges(AddrRangeList &range_list)
+    void
+    updateISRV()
     {
-        range_list.clear();
-        range_list.push_back(RangeEx(x86LocalAPICAddress(0, 0),
-                                     x86LocalAPICAddress(0, 0) + PageBytes));
+        ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE);
     }
 
-    void getIntAddrRange(AddrRangeList &range_list)
+    void
+    setRegArrayBit(ApicRegIndex base, uint8_t vector)
     {
-        range_list.clear();
-        range_list.push_back(RangeEx(x86InterruptAddress(0, 0),
-                    x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize));
+        regs[base + (vector / 32)] |= (1 << (vector % 32));
     }
 
-    uint32_t readReg(ApicRegIndex miscReg);
-    void setReg(ApicRegIndex reg, uint32_t val);
-    void setRegNoEffect(ApicRegIndex reg, uint32_t val)
+    void
+    clearRegArrayBit(ApicRegIndex base, uint8_t vector)
     {
-        regs[reg] = val;
+        regs[base + (vector / 32)] &= ~(1 << (vector % 32));
     }
 
-    Interrupts(Params * p) : BasicPioDevice(p), IntDev(this),
-                             latency(p->pio_latency), clock(0)
+    bool
+    getRegArrayBit(ApicRegIndex base, uint8_t vector)
     {
-        pioSize = PageBytes;
-        //Set the local apic DFR to the flat model.
-        regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
-        memset(regs, 0, sizeof(regs));
-        clear_all();
+        return bits(regs[base + (vector / 32)], vector % 5);
     }
 
-    Port *getPort(const std::string &if_name, int idx = -1)
+    void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);
+
+    BaseCPU *cpu;
+
+    int initialApicId;
+
+  public:
+    /*
+     * Params stuff.
+     */
+    typedef X86LocalApicParams Params;
+
+    void setCPU(BaseCPU * newCPU);
+
+    void
+    setClock(Tick newClock)
     {
-        if (if_name == "int_port")
-            return intPort;
-        return BasicPioDevice::getPort(if_name, idx);
+        clock = newClock;
     }
 
-    int InterruptLevel(uint64_t softint)
+    const Params *
+    params() const
     {
-        panic("Interrupts::InterruptLevel unimplemented!\n");
-        return 0;
+        return dynamic_cast<const Params *>(_params);
     }
 
-    void post(int int_num, int index)
+    /*
+     * Initialize this object by registering it with the IO APIC.
+     */
+    void init();
+
+    /*
+     * Functions to interact with the interrupt port from IntDev.
+     */
+    Tick read(PacketPtr pkt);
+    Tick write(PacketPtr pkt);
+    Tick recvMessage(PacketPtr pkt);
+    Tick recvResponse(PacketPtr pkt);
+
+    bool
+    triggerTimerInterrupt()
     {
-        panic("Interrupts::post unimplemented!\n");
+        LVTEntry entry = regs[APIC_LVT_TIMER];
+        if (!entry.masked)
+            requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger);
+        return entry.periodic;
     }
 
-    void clear(int int_num, int index)
+    void addressRanges(AddrRangeList &range_list);
+    void getIntAddrRange(AddrRangeList &range_list);
+
+    Port *getPort(const std::string &if_name, int idx = -1)
     {
-        warn("Interrupts::clear unimplemented!\n");
+        if (if_name == "int_port")
+            return intPort;
+        return BasicPioDevice::getPort(if_name, idx);
     }
 
-    void clear_all()
+    /*
+     * Functions to access and manipulate the APIC's registers.
+     */
+
+    uint32_t readReg(ApicRegIndex miscReg);
+    void setReg(ApicRegIndex reg, uint32_t val);
+    void
+    setRegNoEffect(ApicRegIndex reg, uint32_t val)
     {
-        warn("Interrupts::clear_all unimplemented!\n");
+        regs[reg] = val;
     }
 
-    bool check_interrupts(ThreadContext * tc) const
+    /*
+     * Constructor.
+     */
+
+    Interrupts(Params * p);
+
+    /*
+     * Functions for retrieving interrupts for the CPU to handle.
+     */
+
+    bool checkInterrupts(ThreadContext *tc) const;
+    Fault getInterrupt(ThreadContext *tc);
+    void updateIntrInfo(ThreadContext *tc);
+
+    /*
+     * Serialization.
+     */
+
+    void
+    serialize(std::ostream &os)
     {
-        return false;
+        panic("Interrupts::serialize unimplemented!\n");
     }
 
-    Fault getInterrupt(ThreadContext * tc)
+    void
+    unserialize(Checkpoint *cp, const std::string &section)
     {
-        return NoFault;
+        panic("Interrupts::unserialize unimplemented!\n");
     }
 
-    void updateIntrInfo(ThreadContext * tc)
+    /*
+     * Old functions needed for compatability but which will be phased out
+     * eventually.
+     */
+    void
+    post(int int_num, int index)
     {
-        panic("Interrupts::updateIntrInfo unimplemented!\n");
+        panic("Interrupts::post unimplemented!\n");
     }
 
-    void serialize(std::ostream & os)
+    void
+    clear(int int_num, int index)
     {
-        panic("Interrupts::serialize unimplemented!\n");
+        panic("Interrupts::clear unimplemented!\n");
     }
 
-    void unserialize(Checkpoint * cp, const std::string & section)
+    void
+    clearAll()
     {
-        panic("Interrupts::unserialize unimplemented!\n");
+        panic("Interrupts::clearAll unimplemented!\n");
     }
 };
 
-};
+} // namespace X86ISA
 
 #endif // __ARCH_X86_INTERRUPTS_HH__