Merge from head.
[gem5.git] / src / cpu / base.cc
index 0b9c80591bc673eaa7029553f16cca779b0cc63c..cf007a06b21f4d1d5f062f3fea3f80e4687b0f23 100644 (file)
@@ -41,6 +41,7 @@
 #include "cpu/cpuevent.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/profile.hh"
+#include "sim/sim_exit.hh"
 #include "sim/param.hh"
 #include "sim/process.hh"
 #include "sim/sim_events.hh"
@@ -48,6 +49,9 @@
 
 #include "base/trace.hh"
 
+// Hack
+#include "sim/stat_control.hh"
+
 using namespace std;
 
 vector<BaseCPU *> BaseCPU::cpuList;
@@ -57,16 +61,52 @@ vector<BaseCPU *> BaseCPU::cpuList;
 // been initialized
 int maxThreadsPerCPU = 1;
 
+CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival,
+                                   BaseCPU *_cpu)
+    : Event(q, Event::Progress_Event_Pri), interval(ival),
+      lastNumInst(0), cpu(_cpu)
+{
+    if (interval)
+        schedule(curTick + interval);
+}
+
+void
+CPUProgressEvent::process()
+{
+    Counter temp = cpu->totalInstructions();
+#ifndef NDEBUG
+    double ipc = double(temp - lastNumInst) / (interval / cpu->cycles(1));
+
+    DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n",
+             cpu->name(), temp - lastNumInst, ipc);
+    ipc = 0.0;
+#else
+    cprintf("%lli: %s progress event, instructions committed: %lli\n",
+            curTick, cpu->name(), temp - lastNumInst);
+#endif
+    lastNumInst = temp;
+    schedule(curTick + interval);
+}
+
+const char *
+CPUProgressEvent::description()
+{
+    return "CPU Progress";
+}
+
 #if FULL_SYSTEM
 BaseCPU::BaseCPU(Params *p)
-    : SimObject(p->name), clock(p->clock), checkInterrupts(true),
-      params(p), number_of_threads(p->numberOfThreads), system(p->system)
+    : MemObject(p->name), clock(p->clock), instCnt(0),
+      params(p), number_of_threads(p->numberOfThreads), system(p->system),
+      phase(p->phase)
 #else
 BaseCPU::BaseCPU(Params *p)
-    : SimObject(p->name), clock(p->clock), params(p),
-      number_of_threads(p->numberOfThreads), system(p->system)
+    : MemObject(p->name), clock(p->clock), params(p),
+      number_of_threads(p->numberOfThreads), system(p->system),
+      phase(p->phase)
 #endif
 {
+//    currentTick = curTick;
     DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this);
 
     // add self to global list of CPUs
@@ -88,8 +128,9 @@ BaseCPU::BaseCPU(Params *p)
     //
     if (p->max_insts_any_thread != 0)
         for (int i = 0; i < number_of_threads; ++i)
-            new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
-                                 "a thread reached the max instruction count");
+            schedExitSimLoop("a thread reached the max instruction count",
+                             p->max_insts_any_thread, 0,
+                             comInstEventQueue[i]);
 
     if (p->max_insts_all_threads != 0) {
         // allocate & initialize shared downcounter: each event will
@@ -113,8 +154,9 @@ BaseCPU::BaseCPU(Params *p)
     //
     if (p->max_loads_any_thread != 0)
         for (int i = 0; i < number_of_threads; ++i)
-            new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
-                                 "a thread reached the max load count");
+            schedExitSimLoop("a thread reached the max load count",
+                             p->max_loads_any_thread, 0,
+                             comLoadEventQueue[i]);
 
     if (p->max_loads_all_threads != 0) {
         // allocate & initialize shared downcounter: each event will
@@ -128,11 +170,6 @@ BaseCPU::BaseCPU(Params *p)
                 p->max_loads_all_threads, *counter);
     }
 
-#if FULL_SYSTEM
-    memset(interrupts, 0, sizeof(interrupts));
-    intstatus = 0;
-#endif
-
     functionTracingEnabled = false;
     if (p->functionTrace) {
         functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
@@ -142,10 +179,9 @@ BaseCPU::BaseCPU(Params *p)
         if (p->functionTraceStart == 0) {
             functionTracingEnabled = true;
         } else {
-            Event *e =
-                new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
-                                                                         true);
-            e->schedule(p->functionTraceStart);
+            new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
+                                                                     p->functionTraceStart,
+                                                                     true);
         }
     }
 #if FULL_SYSTEM
@@ -153,7 +189,6 @@ BaseCPU::BaseCPU(Params *p)
     if (params->profile)
         profileEvent = new ProfileEvent(this, params->profile);
 #endif
-
 }
 
 BaseCPU::Params::Params()
@@ -188,6 +223,12 @@ BaseCPU::startup()
     if (!params->deferRegistration && profileEvent)
         profileEvent->schedule(curTick);
 #endif
+
+    if (params->progress_interval) {
+        new CPUProgressEvent(&mainEventQueue,
+                             cycles(params->progress_interval),
+                             this);
+    }
 }
 
 
@@ -215,6 +256,26 @@ BaseCPU::regStats()
 #endif
 }
 
+Tick
+BaseCPU::nextCycle()
+{
+    Tick next_tick = curTick - phase + clock - 1;
+    next_tick -= (next_tick % clock);
+    next_tick += phase;
+    return next_tick;
+}
+
+Tick
+BaseCPU::nextCycle(Tick begin_tick)
+{
+    Tick next_tick = begin_tick;
+    if (next_tick % clock != 0)
+        next_tick = next_tick - (next_tick % clock) + clock;
+    next_tick += phase;
+
+    assert(next_tick >= curTick);
+    return next_tick;
+}
 
 void
 BaseCPU::registerThreadContexts()
@@ -235,14 +296,28 @@ BaseCPU::registerThreadContexts()
 }
 
 
+int
+BaseCPU::findContext(ThreadContext *tc)
+{
+    for (int i = 0; i < threadContexts.size(); ++i) {
+        if (tc == threadContexts[i])
+            return i;
+    }
+    return 0;
+}
+
 void
 BaseCPU::switchOut()
 {
-    panic("This CPU doesn't support sampling!");
+//    panic("This CPU doesn't support sampling!");
+#if FULL_SYSTEM
+    if (profileEvent && profileEvent->scheduled())
+        profileEvent->deschedule();
+#endif
 }
 
 void
-BaseCPU::takeOverFrom(BaseCPU *oldCPU)
+BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
 {
     assert(threadContexts.size() == oldCPU->threadContexts.size());
 
@@ -261,19 +336,40 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
         assert(newTC->getProcessPtr() == oldTC->getProcessPtr());
         newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId());
 #endif
+
+//    TheISA::compareXCs(oldXC, newXC);
     }
 
 #if FULL_SYSTEM
-    for (int i = 0; i < TheISA::NumInterruptLevels; ++i)
-        interrupts[i] = oldCPU->interrupts[i];
-    intstatus = oldCPU->intstatus;
+    interrupts = oldCPU->interrupts;
 
     for (int i = 0; i < threadContexts.size(); ++i)
         threadContexts[i]->profileClear();
 
-    if (profileEvent)
-        profileEvent->schedule(curTick);
+    // The Sampler must take care of this!
+//    if (profileEvent)
+//        profileEvent->schedule(curTick);
 #endif
+
+    // Connect new CPU to old CPU's memory only if new CPU isn't
+    // connected to anything.  Also connect old CPU's memory to new
+    // CPU.
+    Port *peer;
+    if (ic->getPeer() == NULL) {
+        peer = oldCPU->getPort("icache_port")->getPeer();
+        ic->setPeer(peer);
+    } else {
+        peer = ic->getPeer();
+    }
+    peer->setPeer(ic);
+
+    if (dc->getPeer() == NULL) {
+        peer = oldCPU->getPort("dcache_port")->getPeer();
+        dc->setPeer(peer);
+    } else {
+        peer = dc->getPeer();
+    }
+    peer->setPeer(dc);
 }
 
 
@@ -296,57 +392,39 @@ BaseCPU::ProfileEvent::process()
 void
 BaseCPU::post_interrupt(int int_num, int index)
 {
-    DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
-
-    if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
-        panic("int_num out of bounds\n");
-
-    if (index < 0 || index >= sizeof(uint64_t) * 8)
-        panic("int_num out of bounds\n");
-
-    checkInterrupts = true;
-    interrupts[int_num] |= 1 << index;
-    intstatus |= (ULL(1) << int_num);
+    interrupts.post(int_num, index);
 }
 
 void
 BaseCPU::clear_interrupt(int int_num, int index)
 {
-    DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
-
-    if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
-        panic("int_num out of bounds\n");
-
-    if (index < 0 || index >= sizeof(uint64_t) * 8)
-        panic("int_num out of bounds\n");
-
-    interrupts[int_num] &= ~(1 << index);
-    if (interrupts[int_num] == 0)
-        intstatus &= ~(ULL(1) << int_num);
+    interrupts.clear(int_num, index);
 }
 
 void
 BaseCPU::clear_interrupts()
 {
-    DPRINTF(Interrupt, "Interrupts all cleared\n");
-
-    memset(interrupts, 0, sizeof(interrupts));
-    intstatus = 0;
+    interrupts.clear_all();
 }
 
+uint64_t
+BaseCPU::get_interrupts(int int_num)
+{
+    return interrupts.get_vec(int_num);
+}
 
 void
 BaseCPU::serialize(std::ostream &os)
 {
-    SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
-    SERIALIZE_SCALAR(intstatus);
+    SERIALIZE_SCALAR(instCnt);
+    interrupts.serialize(os);
 }
 
 void
 BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
 {
-    UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
-    UNSERIALIZE_SCALAR(intstatus);
+    UNSERIALIZE_SCALAR(instCnt);
+    interrupts.unserialize(cp, section);
 }
 
 #endif // FULL_SYSTEM