mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / x86 / interrupts.cc
index 045b095164f811dc2bff8f13d595ee93e42dea31..b447216d9d88dec974813e0116b925904ee550fb 100644 (file)
  * Authors: Gabe Black
  */
 
+#include "arch/x86/interrupts.hh"
+
+#include <list>
 #include <memory>
 
-#include "arch/x86/regs/apic.hh"
-#include "arch/x86/interrupts.hh"
 #include "arch/x86/intmessage.hh"
+#include "arch/x86/regs/apic.hh"
 #include "cpu/base.hh"
 #include "debug/LocalApic.hh"
 #include "dev/x86/i82094aa.hh"
 #include "dev/x86/pc.hh"
 #include "dev/x86/south_bridge.hh"
 #include "mem/packet_access.hh"
-#include "sim/system.hh"
 #include "sim/full_system.hh"
+#include "sim/system.hh"
 
 int
 divideFromConf(uint32_t conf)
@@ -112,58 +114,34 @@ decodeAddr(Addr paddr)
         regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
         break;
       case 0x100:
-      case 0x108:
       case 0x110:
-      case 0x118:
       case 0x120:
-      case 0x128:
       case 0x130:
-      case 0x138:
       case 0x140:
-      case 0x148:
       case 0x150:
-      case 0x158:
       case 0x160:
-      case 0x168:
       case 0x170:
-      case 0x178:
-        regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
+        regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x10);
         break;
       case 0x180:
-      case 0x188:
       case 0x190:
-      case 0x198:
       case 0x1A0:
-      case 0x1A8:
       case 0x1B0:
-      case 0x1B8:
       case 0x1C0:
-      case 0x1C8:
       case 0x1D0:
-      case 0x1D8:
       case 0x1E0:
-      case 0x1E8:
       case 0x1F0:
-      case 0x1F8:
-        regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
+        regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x10);
         break;
       case 0x200:
-      case 0x208:
       case 0x210:
-      case 0x218:
       case 0x220:
-      case 0x228:
       case 0x230:
-      case 0x238:
       case 0x240:
-      case 0x248:
       case 0x250:
-      case 0x258:
       case 0x260:
-      case 0x268:
       case 0x270:
-      case 0x278:
-        regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
+        regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x10);
         break;
       case 0x280:
         regNum = APIC_ERROR_STATUS;
@@ -214,11 +192,11 @@ Tick
 X86ISA::Interrupts::read(PacketPtr pkt)
 {
     Addr offset = pkt->getAddr() - pioAddr;
-    //Make sure we're at least only accessing one register.
+    // Make sure we're at least only accessing one register.
     if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
         panic("Accessed more than one register at a time in the APIC!\n");
     ApicRegIndex reg = decodeAddr(offset);
-    uint32_t val = htog(readReg(reg));
+    uint32_t val = htole(readReg(reg));
     DPRINTF(LocalApic,
             "Reading Local APIC register %d at offset %#x as %#x.\n",
             reg, offset, val);
@@ -231,7 +209,7 @@ Tick
 X86ISA::Interrupts::write(PacketPtr pkt)
 {
     Addr offset = pkt->getAddr() - pioAddr;
-    //Make sure we're at least only accessing one register.
+    // Make sure we're at least only accessing one register.
     if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
         panic("Accessed more than one register at a time in the APIC!\n");
     ApicRegIndex reg = decodeAddr(offset);
@@ -239,8 +217,8 @@ X86ISA::Interrupts::write(PacketPtr pkt)
     pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
     DPRINTF(LocalApic,
             "Writing Local APIC register %d at offset %#x as %#x.\n",
-            reg, offset, gtoh(val));
-    setReg(reg, gtoh(val));
+            reg, offset, letoh(val));
+    setReg(reg, letoh(val));
     pkt->makeAtomicResponse();
     return pioDelay;
 }
@@ -290,7 +268,7 @@ X86ISA::Interrupts::requestInterrupt(uint8_t vector,
         }
     }
     if (FullSystem)
-        cpu->wakeup();
+        cpu->wakeup(0);
 }
 
 
@@ -312,17 +290,13 @@ X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
 void
 X86ISA::Interrupts::init()
 {
-    //
-    // The local apic must register its address ranges on both its pio
-    // port via the basicpiodevice(piodevice) init() function and its
-    // int port that it inherited from IntDevice.  Note IntDevice is
-    // not a SimObject itself.
-    //
-    BasicPioDevice::init();
-    IntDevice::init();
-
-    // the slave port has a range so inform the connected master
+    panic_if(!intMasterPort.isConnected(),
+            "Int port not connected to anything!");
+    panic_if(!pioPort.isConnected(),
+            "Pio port of %s not connected to anything!", name());
+
     intSlavePort.sendRangeChange();
+    pioPort.sendRangeChange();
 }
 
 
@@ -330,12 +304,12 @@ Tick
 X86ISA::Interrupts::recvMessage(PacketPtr pkt)
 {
     Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
-    assert(pkt->cmd == MemCmd::MessageReq);
+    assert(pkt->cmd == MemCmd::WriteReq);
     switch(offset)
     {
       case 0:
         {
-            TriggerIntMessage message = pkt->get<TriggerIntMessage>();
+            TriggerIntMessage message = pkt->getRaw<TriggerIntMessage>();
             DPRINTF(LocalApic,
                     "Got Trigger Interrupt message with vector %#x.\n",
                     message.vector);
@@ -354,11 +328,9 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
 }
 
 
-Tick
-X86ISA::Interrupts::recvResponse(PacketPtr pkt)
+void
+X86ISA::Interrupts::completeIPI(PacketPtr pkt)
 {
-    assert(!pkt->isError());
-    assert(pkt->cmd == MemCmd::MessageResp);
     if (--pendingIPIs == 0) {
         InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
         // Record that the ICR is now idle.
@@ -366,7 +338,17 @@ X86ISA::Interrupts::recvResponse(PacketPtr pkt)
         regs[APIC_INTERRUPT_COMMAND_LOW] = low;
     }
     DPRINTF(LocalApic, "ICR is now idle.\n");
-    return 0;
+    delete pkt;
+}
+
+
+AddrRangeList
+X86ISA::Interrupts::getAddrRanges() const
+{
+    assert(cpu);
+    AddrRangeList ranges;
+    ranges.push_back(RangeSize(pioAddr, PageBytes));
+    return ranges;
 }
 
 
@@ -491,8 +473,6 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
             }
             low = val;
             InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
-            // Record that an IPI is being sent.
-            low.deliveryStatus = 1;
             TriggerIntMessage message = 0;
             message.destination = high.destination;
             message.vector = low.vector;
@@ -500,10 +480,7 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
             message.destMode = low.destMode;
             message.level = low.level;
             message.trigger = low.trigger;
-            bool timing(sys->isTimingMode());
-            // Be careful no updates of the delivery status bit get lost.
-            regs[APIC_INTERRUPT_COMMAND_LOW] = low;
-            ApicList apics;
+            std::list<int> apics;
             int numContexts = sys->numContexts();
             switch (low.destShorthand) {
               case 0:
@@ -558,8 +535,17 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
                 }
                 break;
             }
-            pendingIPIs += apics.size();
-            intMasterPort.sendMessage(apics, message, timing);
+            // Record that an IPI is being sent if one actually is.
+            if (apics.size()) {
+                low.deliveryStatus = 1;
+                pendingIPIs += apics.size();
+            }
+            regs[APIC_INTERRUPT_COMMAND_LOW] = low;
+            for (auto id: apics) {
+                PacketPtr pkt = buildIntTriggerPacket(id, message);
+                intMasterPort.sendMessage(pkt, sys->isTimingMode(),
+                        [this](PacketPtr pkt) { completeIPI(pkt); });
+            }
             newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
         }
         break;
@@ -610,8 +596,8 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
 
 
 X86ISA::Interrupts::Interrupts(Params * p)
-    : BasicPioDevice(p, PageBytes), IntDevice(this, p->int_latency),
-      apicTimerEvent(this),
+    : BaseInterrupts(p), sys(p->system), clockDomain(*p->clk_domain),
+      apicTimerEvent([this]{ processApicTimerEvent(); }, name()),
       pendingSmi(false), smiVector(0),
       pendingNmi(false), nmiVector(0),
       pendingExtInt(false), extIntVector(0),
@@ -619,13 +605,17 @@ X86ISA::Interrupts::Interrupts(Params * p)
       pendingStartup(false), startupVector(0),
       startedUp(false), pendingUnmaskableInt(false),
       pendingIPIs(0), cpu(NULL),
-      intSlavePort(name() + ".int_slave", this, this)
+      intSlavePort(name() + ".int_slave", this, this),
+      intMasterPort(name() + ".int_master", this, this, p->int_latency),
+      pioPort(this), pioDelay(p->pio_latency)
 {
     memset(regs, 0, sizeof(regs));
     //Set the local apic DFR to the flat model.
     regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
     ISRV = 0;
     IRRV = 0;
+
+    regs[APIC_VERSION] = (5 << 16) | 0x14;
 }
 
 
@@ -729,7 +719,7 @@ X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
 }
 
 void
-X86ISA::Interrupts::serialize(std::ostream &os)
+X86ISA::Interrupts::serialize(CheckpointOut &cp) const
 {
     SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
     SERIALIZE_SCALAR(pendingSmi);
@@ -754,7 +744,7 @@ X86ISA::Interrupts::serialize(std::ostream &os)
 }
 
 void
-X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section)
+X86ISA::Interrupts::unserialize(CheckpointIn &cp)
 {
     UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
     UNSERIALIZE_SCALAR(pendingSmi);
@@ -790,3 +780,9 @@ X86LocalApicParams::create()
 {
     return new X86ISA::Interrupts(this);
 }
+
+void
+X86ISA::Interrupts::processApicTimerEvent() {
+    if (triggerTimerInterrupt())
+        setReg(APIC_INITIAL_COUNT, readReg(APIC_INITIAL_COUNT));
+}