Formatting & doxygen docs for new syscall emulation code.
[gem5.git] / cpu / simple_cpu / simple_cpu.cc
index 8da4b1641fd404f45f180119e0dd6fce8687383e..476f28ea003aea0d207c1ce9f43a959bb7c0e3a5 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
 #include <iostream>
 #include <iomanip>
 #include <list>
 #include <sstream>
 #include <string>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "sim/host.hh"
 #include "base/cprintf.hh"
+#include "base/inifile.hh"
+#include "base/loader/symtab.hh"
 #include "base/misc.hh"
-#include "cpu/full_cpu/smt.hh"
-
-#include "sim/annotation.hh"
-#include "cpu/exec_context.hh"
+#include "base/pollevent.hh"
+#include "base/range.hh"
+#include "base/trace.hh"
 #include "cpu/base_cpu.hh"
-#include "sim/debug.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/full_cpu/smt.hh"
 #include "cpu/simple_cpu/simple_cpu.hh"
-#include "base/inifile.hh"
-#include "mem/mem_interface.hh"
-#include "mem/base_mem.hh"
 #include "cpu/static_inst.hh"
+#include "mem/base_mem.hh"
+#include "mem/mem_interface.hh"
+#include "sim/annotation.hh"
+#include "sim/builder.hh"
+#include "sim/debug.hh"
+#include "sim/host.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_object.hh"
+#include "sim/sim_stats.hh"
 
 #ifdef FULL_SYSTEM
+#include "base/remote_gdb.hh"
+#include "dev/alpha_access.h"
+#include "dev/pciareg.h"
 #include "mem/functional_mem/memory_control.hh"
 #include "mem/functional_mem/physical_memory.hh"
-#include "targetarch/alpha_memory.hh"
 #include "sim/system.hh"
+#include "targetarch/alpha_memory.hh"
+#include "targetarch/vtophys.hh"
 #else // !FULL_SYSTEM
-#include "mem/functional_mem/functional_memory.hh"
-#include "sim/prog.hh"
 #include "eio/eio.hh"
+#include "mem/functional_mem/functional_memory.hh"
 #endif // FULL_SYSTEM
 
-#include "cpu/exetrace.hh"
-#include "base/trace.hh"
-#include "sim/sim_events.hh"
-#include "base/pollevent.hh"
-#include "sim/sim_object.hh"
-#include "sim/sim_stats.hh"
+using namespace std;
 
-#include "base/range.hh"
-#include "base/loader/symtab.hh"
+SimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
+    : Event(&mainEventQueue, 100), cpu(c)
+{
+}
 
-#ifdef FULL_SYSTEM
-#include "targetarch/vtophys.hh"
-#include "dev/pciareg.h"
-#include "base/remote_gdb.hh"
-#include "dev/alpha_access.h"
-#endif
+void
+SimpleCPU::TickEvent::process()
+{
+    cpu->tick();
+}
 
+const char *
+SimpleCPU::TickEvent::description()
+{
+    return "SimpleCPU tick event";
+}
 
-using namespace std;
 
 SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
     : Event(&mainEventQueue),
@@ -96,7 +106,7 @@ void SimpleCPU::CacheCompletionEvent::process()
 const char *
 SimpleCPU::CacheCompletionEvent::description()
 {
-    return "cache completion event";
+    return "SimpleCPU cache completion event";
 }
 
 #ifdef FULL_SYSTEM
@@ -104,80 +114,39 @@ SimpleCPU::SimpleCPU(const string &_name,
                      System *_system,
                      Counter max_insts_any_thread,
                      Counter max_insts_all_threads,
+                     Counter max_loads_any_thread,
+                     Counter max_loads_all_threads,
                      AlphaItb *itb, AlphaDtb *dtb,
                      FunctionalMemory *mem,
                      MemInterface *icache_interface,
                      MemInterface *dcache_interface,
-                     int cpu_id, Tick freq)
+                     Tick freq)
     : BaseCPU(_name, /* number_of_threads */ 1,
               max_insts_any_thread, max_insts_all_threads,
-              _system, cpu_id, freq),
+              max_loads_any_thread, max_loads_all_threads,
+              _system, freq),
 #else
 SimpleCPU::SimpleCPU(const string &_name, Process *_process,
                      Counter max_insts_any_thread,
                      Counter max_insts_all_threads,
+                     Counter max_loads_any_thread,
+                     Counter max_loads_all_threads,
                      MemInterface *icache_interface,
                      MemInterface *dcache_interface)
     : BaseCPU(_name, /* number_of_threads */ 1,
-              max_insts_any_thread, max_insts_all_threads),
+              max_insts_any_thread, max_insts_all_threads,
+              max_loads_any_thread, max_loads_all_threads),
 #endif
       tickEvent(this), xc(NULL), cacheCompletionEvent(this)
 {
+    _status = Idle;
 #ifdef FULL_SYSTEM
-    xc = new ExecContext(this, 0, system, itb, dtb, mem, cpu_id);
-
-    _status = Running;
-    if (cpu_id != 0) {
-
-       xc->setStatus(ExecContext::Unallocated);
-
-       //Open a GDB debug session on port (7000 + the cpu_id)
-       (new GDBListener(new RemoteGDB(system, xc), 7000 + cpu_id))->listen();
-
-       AlphaISA::init(system->physmem, &xc->regs);
-
-       fault = Reset_Fault;
-
-       IntReg *ipr = xc->regs.ipr;
-       ipr[TheISA::IPR_MCSR] = 0x6;
-
-       AlphaISA::swap_palshadow(&xc->regs, true);
-
-       xc->regs.pc =
-           ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
-       xc->regs.npc = xc->regs.pc + sizeof(MachInst);
-
-       _status = Idle;
-    }
-    else {
-      system->init(xc);
-
-      // Reset the system
-      //
-      AlphaISA::init(system->physmem, &xc->regs);
-
-      fault = Reset_Fault;
-
-      IntReg *ipr = xc->regs.ipr;
-      ipr[TheISA::IPR_MCSR] = 0x6;
-
-      AlphaISA::swap_palshadow(&xc->regs, true);
-
-      xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
-      xc->regs.npc = xc->regs.pc + sizeof(MachInst);
-
-       _status = Running;
-       tickEvent.schedule(0);
-    }
+    xc = new ExecContext(this, 0, system, itb, dtb, mem);
 
+    // initialize CPU, including PC
+    TheISA::initCPU(&xc->regs);
 #else
     xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
-    fault = No_Fault;
-    if (xc->status() == ExecContext::Active) {
-        _status = Running;
-       tickEvent.schedule(0);
-    } else
-        _status = Idle;
 #endif // !FULL_SYSTEM
 
     icacheInterface = icache_interface;
@@ -186,22 +155,69 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process,
     memReq = new MemReq();
     memReq->xc = xc;
     memReq->asid = 0;
+    memReq->data = new uint8_t[64];
 
     numInst = 0;
-    last_idle = 0;
+    startNumInst = 0;
+    numLoad = 0;
+    startNumLoad = 0;
     lastIcacheStall = 0;
     lastDcacheStall = 0;
 
-    contexts.push_back(xc);
+    execContexts.push_back(xc);
 }
 
 SimpleCPU::~SimpleCPU()
 {
 }
 
+void
+SimpleCPU::switchOut()
+{
+    _status = SwitchedOut;
+    if (tickEvent.scheduled())
+        tickEvent.squash();
+}
+
+
+void
+SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+    BaseCPU::takeOverFrom(oldCPU);
+
+    assert(!tickEvent.scheduled());
+
+    // if any of this CPU's ExecContexts are active, mark the CPU as
+    // running and schedule its tick event.
+    for (int i = 0; i < execContexts.size(); ++i) {
+        ExecContext *xc = execContexts[i];
+        if (xc->status() == ExecContext::Active && _status != Running) {
+            _status = Running;
+            tickEvent.schedule(curTick);
+        }
+    }
+
+    oldCPU->switchOut();
+}
+
+
+void
+SimpleCPU::execCtxStatusChg(int thread_num) {
+    assert(thread_num == 0);
+    assert(xc);
+
+    if (xc->status() == ExecContext::Active)
+        setStatus(Running);
+    else
+        setStatus(Idle);
+}
+
+
 void
 SimpleCPU::regStats()
 {
+    using namespace Statistics;
+
     BaseCPU::regStats();
 
     numInsts
@@ -214,11 +230,6 @@ SimpleCPU::regStats()
         .desc("Number of memory references")
         ;
 
-    idleCycles
-        .name(name() + ".idle_cycles")
-        .desc("Number of idle cycles")
-        ;
-
     idleFraction
         .name(name() + ".idle_fraction")
         .desc("Percentage of idle cycles")
@@ -236,60 +247,38 @@ SimpleCPU::regStats()
         .prereq(dcacheStallCycles)
         ;
 
-    idleFraction = idleCycles / simTicks;
-
-    numInsts = Statistics::scalar(numInst);
+    numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst);
     simInsts += numInsts;
 }
 
 void
-SimpleCPU::serialize()
+SimpleCPU::resetStats()
 {
-    nameOut();
-
-#ifdef FULL_SYSTEM
-#if 0
-    // do we need this anymore?? egh
-    childOut("itb", xc->itb);
-    childOut("dtb", xc->dtb);
-    childOut("physmem", physmem);
-#endif
-#endif
-
-    for (int i = 0; i < NumIntRegs; i++) {
-        stringstream buf;
-        ccprintf(buf, "R%02d", i);
-        paramOut(buf.str(), xc->regs.intRegFile[i]);
-    }
-    for (int i = 0; i < NumFloatRegs; i++) {
-        stringstream buf;
-        ccprintf(buf, "F%02d", i);
-        paramOut(buf.str(), xc->regs.floatRegFile.d[i]);
-    }
-    // CPUTraitsType::serializeSpecialRegs(getProxy(), xc->regs);
+    startNumInst = numInst;
 }
 
 void
-SimpleCPU::unserialize(IniFile &db, const string &category, ConfigNode *node)
+SimpleCPU::serialize(ostream &os)
 {
-    string data;
-
-    for (int i = 0; i < NumIntRegs; i++) {
-        stringstream buf;
-        ccprintf(buf, "R%02d", i);
-        db.findDefault(category, buf.str(), data);
-        to_number(data,xc->regs.intRegFile[i]);
-    }
-    for (int i = 0; i < NumFloatRegs; i++) {
-        stringstream buf;
-        ccprintf(buf, "F%02d", i);
-        db.findDefault(category, buf.str(), data);
-        xc->regs.floatRegFile.d[i] = strtod(data.c_str(),NULL);
-    }
-
-    // Read in Special registers
+    SERIALIZE_ENUM(_status);
+    SERIALIZE_SCALAR(inst);
+    nameOut(os, csprintf("%s.xc", name()));
+    xc->serialize(os);
+    nameOut(os, csprintf("%s.tickEvent", name()));
+    tickEvent.serialize(os);
+    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
+    cacheCompletionEvent.serialize(os);
+}
 
-    // CPUTraitsType::unserializeSpecialRegs(db,category,node,xc->regs);
+void
+SimpleCPU::unserialize(Checkpoint *cp, const string &section)
+{
+    UNSERIALIZE_ENUM(_status);
+    UNSERIALIZE_SCALAR(inst);
+    xc->unserialize(cp, csprintf("%s.xc", section));
+    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
+    cacheCompletionEvent
+        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
 }
 
 void
@@ -400,7 +389,7 @@ SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 
     if (fault == No_Fault && dcacheInterface) {
         memReq->cmd = Write;
-        memReq->data = (uint8_t *)&data;
+        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
         memReq->completionEvent = NULL;
         memReq->time = curTick;
         memReq->flags &= ~UNCACHEABLE;
@@ -487,6 +476,11 @@ SimpleCPU::processCacheCompletion()
         dcacheStallCycles += curTick - lastDcacheStall;
         setStatus(Running);
         break;
+      case SwitchedOut:
+        // If this CPU has been switched out due to sampling/warm-up,
+        // ignore any further status changes (e.g., due to cache
+        // misses outstanding at the time of the switch).
+        return;
       default:
         panic("SimpleCPU::processCacheCompletion: bad state");
         break;
@@ -513,8 +507,10 @@ SimpleCPU::tick()
 {
     traceData = NULL;
 
+    Fault fault = No_Fault;
+
 #ifdef FULL_SYSTEM
-    if (fault == No_Fault && AlphaISA::check_interrupts &&
+    if (AlphaISA::check_interrupts &&
         xc->cpu->check_interrupts() &&
         !PC_PAL(xc->regs.pc) &&
         status() != IcacheMissComplete) {
@@ -535,7 +531,7 @@ SimpleCPU::tick()
         }
 
         uint64_t interrupts = xc->cpu->intr_status();
-        for(int i = TheISA::INTLEVEL_EXTERNAL_MIN;
+        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
             i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
             if (interrupts & (ULL(1) << i)) {
                 // See table 4-19 of 21164 hardware reference
@@ -631,11 +627,41 @@ SimpleCPU::tick()
         xc->func_exe_insn++;
 
         fault = si->execute(this, xc, traceData);
-
+#ifdef FS_MEASURE
+        if (!(xc->misspeculating()) && (xc->system->bin)) {
+            SWContext *ctx = xc->swCtx;
+            if (ctx && !ctx->callStack.empty()) {
+                if (si->isCall()) {
+                    ctx->calls++;
+                }
+                if (si->isReturn()) {
+                     if (ctx->calls == 0) {
+                        fnCall *top = ctx->callStack.top();
+                        DPRINTF(TCPIP, "Removing %s from callstack.\n", top->name);
+                        delete top;
+                        ctx->callStack.pop();
+                        if (ctx->callStack.empty())
+                            xc->system->nonPath->activate();
+                        else
+                            ctx->callStack.top()->myBin->activate();
+
+                        xc->system->dumpState(xc);
+                    } else {
+                        ctx->calls--;
+                    }
+                }
+            }
+        }
+#endif
         if (si->isMemRef()) {
             numMemRefs++;
         }
 
+        if (si->isLoad()) {
+            ++numLoad;
+            comLoadEventQueue[0]->serviceEvents(numLoad);
+        }
+
         if (traceData)
             traceData->finalize();
 
@@ -679,13 +705,14 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
 
     Param<Counter> max_insts_any_thread;
     Param<Counter> max_insts_all_threads;
+    Param<Counter> max_loads_any_thread;
+    Param<Counter> max_loads_all_threads;
 
 #ifdef FULL_SYSTEM
     SimObjectParam<AlphaItb *> itb;
     SimObjectParam<AlphaDtb *> dtb;
     SimObjectParam<FunctionalMemory *> mem;
     SimObjectParam<System *> system;
-    Param<int> cpu_id;
     Param<int> mult;
 #else
     SimObjectParam<Process *> workload;
@@ -694,6 +721,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
     SimObjectParam<BaseMem *> icache;
     SimObjectParam<BaseMem *> dcache;
 
+    Param<bool> defer_registration;
+
 END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
 
 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
@@ -704,43 +733,60 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
     INIT_PARAM_DFLT(max_insts_all_threads,
                     "terminate when all threads have reached this insn count",
                     0),
+    INIT_PARAM_DFLT(max_loads_any_thread,
+                    "terminate when any thread reaches this load count",
+                    0),
+    INIT_PARAM_DFLT(max_loads_all_threads,
+                    "terminate when all threads have reached this load count",
+                    0),
 
 #ifdef FULL_SYSTEM
     INIT_PARAM(itb, "Instruction TLB"),
     INIT_PARAM(dtb, "Data TLB"),
     INIT_PARAM(mem, "memory"),
     INIT_PARAM(system, "system object"),
-    INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0),
     INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
 #else
     INIT_PARAM(workload, "processes to run"),
 #endif // FULL_SYSTEM
 
     INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
-    INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL)
+    INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
+    INIT_PARAM_DFLT(defer_registration, "defer registration with system "
+                    "(for sampling)", false)
 
 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
 
 
 CREATE_SIM_OBJECT(SimpleCPU)
 {
+    SimpleCPU *cpu;
 #ifdef FULL_SYSTEM
     if (mult != 1)
         panic("processor clock multiplier must be 1\n");
 
-    return new SimpleCPU(getInstanceName(), system,
-                         max_insts_any_thread, max_insts_all_threads,
-                         itb, dtb, mem,
-                         (icache) ? icache->getInterface() : NULL,
-                         (dcache) ? dcache->getInterface() : NULL,
-                         cpu_id, ticksPerSecond * mult);
+    cpu = new SimpleCPU(getInstanceName(), system,
+                        max_insts_any_thread, max_insts_all_threads,
+                        max_loads_any_thread, max_loads_all_threads,
+                        itb, dtb, mem,
+                        (icache) ? icache->getInterface() : NULL,
+                        (dcache) ? dcache->getInterface() : NULL,
+                        ticksPerSecond * mult);
 #else
 
-    return new SimpleCPU(getInstanceName(), workload,
-                         max_insts_any_thread, max_insts_all_threads,
-                         icache->getInterface(), dcache->getInterface());
+    cpu = new SimpleCPU(getInstanceName(), workload,
+                        max_insts_any_thread, max_insts_all_threads,
+                        max_loads_any_thread, max_loads_all_threads,
+                        (icache) ? icache->getInterface() : NULL,
+                        (dcache) ? dcache->getInterface() : NULL);
 
 #endif // FULL_SYSTEM
+
+    if (!defer_registration) {
+        cpu->registerExecContexts();
+    }
+
+    return cpu;
 }
 
 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)