add in an init() callback for CPU's so that no stats are accessed prior to the end...
[gem5.git] / cpu / simple_cpu / simple_cpu.cc
index aaf8a9dc58df8001e8d6aad3bf5a6fb64cbfcb63..721861dd5e881b6d2b09a5546613a85acca3e9c2 100644 (file)
@@ -75,7 +75,7 @@
 using namespace std;
 
 SimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
-    : Event(&mainEventQueue, 100), cpu(c)
+    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
 {
 }
 
@@ -120,7 +120,7 @@ SimpleCPU::SimpleCPU(const string &_name,
                      FunctionalMemory *mem,
                      MemInterface *icache_interface,
                      MemInterface *dcache_interface,
-                     Tick freq)
+                     bool _def_reg, Tick freq)
     : BaseCPU(_name, /* number_of_threads */ 1,
               max_insts_any_thread, max_insts_all_threads,
               max_loads_any_thread, max_loads_all_threads,
@@ -132,12 +132,14 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process,
                      Counter max_loads_any_thread,
                      Counter max_loads_all_threads,
                      MemInterface *icache_interface,
-                     MemInterface *dcache_interface)
+                     MemInterface *dcache_interface,
+                     bool _def_reg)
     : BaseCPU(_name, /* number_of_threads */ 1,
               max_insts_any_thread, max_insts_all_threads,
               max_loads_any_thread, max_loads_all_threads),
 #endif
-      tickEvent(this), xc(NULL), cacheCompletionEvent(this)
+      tickEvent(this), xc(NULL), defer_registration(_def_reg),
+      cacheCompletionEvent(this)
 {
     _status = Idle;
 #ifdef FULL_SYSTEM
@@ -171,6 +173,13 @@ SimpleCPU::~SimpleCPU()
 {
 }
 
+void SimpleCPU::init()
+{
+    if (!defer_registration) {
+        this->registerExecContexts();
+    }
+}
+
 void
 SimpleCPU::switchOut()
 {
@@ -202,74 +211,47 @@ SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
 
 
 void
-SimpleCPU::execCtxStatusChg(int thread_num) {
+SimpleCPU::activateContext(int thread_num, int delay)
+{
     assert(thread_num == 0);
     assert(xc);
 
-    if (xc->status() == ExecContext::Active)
-        setStatus(Running);
-    else
-        setStatus(Idle);
+    assert(_status == Idle);
+    notIdleFraction++;
+    scheduleTickEvent(delay);
+    _status = Running;
 }
 
+
 void
-SimpleCPU::setStatus(Status new_status)
+SimpleCPU::suspendContext(int thread_num)
 {
-    Status old_status = status();
-
-    // We should never even get here if the CPU has been switched out.
-    assert(old_status != SwitchedOut);
-
-    _status = new_status;
-
-    switch (status()) {
-      case IcacheMissStall:
-        assert(old_status == Running);
-        lastIcacheStall = curTick;
-        if (tickEvent.scheduled())
-            tickEvent.squash();
-        break;
+    assert(thread_num == 0);
+    assert(xc);
 
-      case IcacheMissComplete:
-        assert(old_status == IcacheMissStall);
-        if (tickEvent.squashed())
-            tickEvent.reschedule(curTick + 1);
-        else if (!tickEvent.scheduled())
-            tickEvent.schedule(curTick + 1);
-        break;
+    assert(_status == Running);
+    notIdleFraction--;
+    unscheduleTickEvent();
+    _status = Idle;
+}
 
-      case DcacheMissStall:
-        assert(old_status == Running);
-        lastDcacheStall = curTick;
-        if (tickEvent.scheduled())
-            tickEvent.squash();
-        break;
 
-      case Idle:
-        assert(old_status == Running);
-        notIdleFraction--;
-        if (tickEvent.scheduled())
-            tickEvent.squash();
-        break;
+void
+SimpleCPU::deallocateContext(int thread_num)
+{
+    // for now, these are equivalent
+    suspendContext(thread_num);
+}
 
-      case Running:
-        assert(old_status == Idle ||
-               old_status == DcacheMissStall ||
-               old_status == IcacheMissComplete);
-        if (old_status == Idle)
-            notIdleFraction++;
-
-        if (tickEvent.squashed())
-            tickEvent.reschedule(curTick + 1);
-        else if (!tickEvent.scheduled())
-            tickEvent.schedule(curTick + 1);
-        break;
 
-      default:
-        panic("can't get here");
-    }
+void
+SimpleCPU::haltContext(int thread_num)
+{
+    // for now, these are equivalent
+    suspendContext(thread_num);
 }
 
+
 void
 SimpleCPU::regStats()
 {
@@ -348,7 +330,7 @@ change_thread_state(int thread_number, int activate, int priority)
 // precise architected memory state accessor macros
 template <class T>
 Fault
-SimpleCPU::read(Addr addr, Tdata, unsigned flags)
+SimpleCPU::read(Addr addr, T &data, unsigned flags)
 {
     memReq->reset(addr, sizeof(T), flags);
 
@@ -370,15 +352,16 @@ SimpleCPU::read(Addr addr, T& data, unsigned flags)
         memReq->cmd = Read;
         memReq->completionEvent = NULL;
         memReq->time = curTick;
-        memReq->flags &= ~UNCACHEABLE;
         MemAccessResult result = dcacheInterface->access(memReq);
 
         // Ugly hack to get an event scheduled *only* if the access is
         // a miss.  We really should add first-class support for this
         // at some point.
-        if (result != MA_HIT && dcacheInterface->doEvents) {
+        if (result != MA_HIT && dcacheInterface->doEvents()) {
             memReq->completionEvent = &cacheCompletionEvent;
-            setStatus(DcacheMissStall);
+            lastDcacheStall = curTick;
+            unscheduleTickEvent();
+            _status = DcacheMissStall;
         }
     }
 
@@ -389,32 +372,32 @@ SimpleCPU::read(Addr addr, T& data, unsigned flags)
 
 template
 Fault
-SimpleCPU::read(Addr addr, uint64_tdata, unsigned flags);
+SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
 
 template
 Fault
-SimpleCPU::read(Addr addr, uint32_tdata, unsigned flags);
+SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
 
 template
 Fault
-SimpleCPU::read(Addr addr, uint16_tdata, unsigned flags);
+SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
 
 template
 Fault
-SimpleCPU::read(Addr addr, uint8_tdata, unsigned flags);
+SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
 
 #endif //DOXYGEN_SHOULD_SKIP_THIS
 
 template<>
 Fault
-SimpleCPU::read(Addr addr, doubledata, unsigned flags)
+SimpleCPU::read(Addr addr, double &data, unsigned flags)
 {
     return read(addr, *(uint64_t*)&data, flags);
 }
 
 template<>
 Fault
-SimpleCPU::read(Addr addr, floatdata, unsigned flags)
+SimpleCPU::read(Addr addr, float &data, unsigned flags)
 {
     return read(addr, *(uint32_t*)&data, flags);
 }
@@ -422,7 +405,7 @@ SimpleCPU::read(Addr addr, float& data, unsigned flags)
 
 template<>
 Fault
-SimpleCPU::read(Addr addr, int32_tdata, unsigned flags)
+SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
 {
     return read(addr, (uint32_t&)data, flags);
 }
@@ -451,15 +434,16 @@ SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
         memcpy(memReq->data,(uint8_t *)&data,memReq->size);
         memReq->completionEvent = NULL;
         memReq->time = curTick;
-        memReq->flags &= ~UNCACHEABLE;
         MemAccessResult result = dcacheInterface->access(memReq);
 
         // Ugly hack to get an event scheduled *only* if the access is
         // a miss.  We really should add first-class support for this
         // at some point.
-        if (result != MA_HIT && dcacheInterface->doEvents) {
+        if (result != MA_HIT && dcacheInterface->doEvents()) {
             memReq->completionEvent = &cacheCompletionEvent;
-            setStatus(DcacheMissStall);
+            lastDcacheStall = curTick;
+            unscheduleTickEvent();
+            _status = DcacheMissStall;
         }
     }
 
@@ -529,11 +513,13 @@ SimpleCPU::processCacheCompletion()
     switch (status()) {
       case IcacheMissStall:
         icacheStallCycles += curTick - lastIcacheStall;
-        setStatus(IcacheMissComplete);
+        _status = IcacheMissComplete;
+        scheduleTickEvent(1);
         break;
       case DcacheMissStall:
         dcacheStallCycles += curTick - lastDcacheStall;
-        setStatus(Running);
+        _status = Running;
+        scheduleTickEvent(1);
         break;
       case SwitchedOut:
         // If this CPU has been switched out due to sampling/warm-up,
@@ -554,7 +540,7 @@ SimpleCPU::post_interrupt(int int_num, int index)
 
     if (xc->status() == ExecContext::Suspended) {
                 DPRINTF(IPI,"Suspended Processor awoke\n");
-        xc->setStatus(ExecContext::Active);
+        xc->activate();
         Annotate::Resume(xc);
     }
 }
@@ -623,7 +609,9 @@ SimpleCPU::tick()
         // We've already fetched an instruction and were stalled on an
         // I-cache miss.  No need to fetch it again.
 
-        setStatus(Running);
+        // Set status to running; tick event will get rescheduled if
+        // necessary at end of tick() function.
+        _status = Running;
     }
     else {
         // Try to fetch an instruction
@@ -648,15 +636,16 @@ SimpleCPU::tick()
             memReq->completionEvent = NULL;
 
             memReq->time = curTick;
-            memReq->flags &= ~UNCACHEABLE;
             MemAccessResult result = icacheInterface->access(memReq);
 
             // Ugly hack to get an event scheduled *only* if the access is
             // a miss.  We really should add first-class support for this
             // at some point.
-            if (result != MA_HIT && icacheInterface->doEvents) {
+            if (result != MA_HIT && icacheInterface->doEvents()) {
                 memReq->completionEvent = &cacheCompletionEvent;
-                setStatus(IcacheMissStall);
+                lastIcacheStall = curTick;
+                unscheduleTickEvent();
+                _status = IcacheMissStall;
                 return;
             }
         }
@@ -670,7 +659,7 @@ SimpleCPU::tick()
         numInst++;
 
         // check for instruction-count-based events
-        comInsnEventQueue[0]->serviceEvents(numInst);
+        comInstEventQueue[0]->serviceEvents(numInst);
 
         // decode the instruction
         StaticInstPtr<TheISA> si(inst);
@@ -683,7 +672,7 @@ SimpleCPU::tick()
         xc->regs.ra = (inst >> 21) & 0x1f;
 #endif // FULL_SYSTEM
 
-        xc->func_exe_insn++;
+        xc->func_exe_inst++;
 
         fault = si->execute(this, xc, traceData);
 #ifdef FS_MEASURE
@@ -787,10 +776,10 @@ END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
 
     INIT_PARAM_DFLT(max_insts_any_thread,
-                    "terminate when any thread reaches this insn count",
+                    "terminate when any thread reaches this inst count",
                     0),
     INIT_PARAM_DFLT(max_insts_all_threads,
-                    "terminate when all threads have reached this insn count",
+                    "terminate when all threads have reached this inst count",
                     0),
     INIT_PARAM_DFLT(max_loads_any_thread,
                     "terminate when any thread reaches this load count",
@@ -830,6 +819,7 @@ CREATE_SIM_OBJECT(SimpleCPU)
                         itb, dtb, mem,
                         (icache) ? icache->getInterface() : NULL,
                         (dcache) ? dcache->getInterface() : NULL,
+                        defer_registration,
                         ticksPerSecond * mult);
 #else
 
@@ -837,15 +827,17 @@ CREATE_SIM_OBJECT(SimpleCPU)
                         max_insts_any_thread, max_insts_all_threads,
                         max_loads_any_thread, max_loads_all_threads,
                         (icache) ? icache->getInterface() : NULL,
-                        (dcache) ? dcache->getInterface() : NULL);
+                        (dcache) ? dcache->getInterface() : NULL,
+                        defer_registration);
 
 #endif // FULL_SYSTEM
-
+#if 0
     if (!defer_registration) {
         cpu->registerExecContexts();
     }
-
+#endif
     return cpu;
 }
 
 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
+