undo simple CPU changes
[gem5.git] / cpu / simple_cpu / simple_cpu.cc
index aaf8a9dc58df8001e8d6aad3bf5a6fb64cbfcb63..d48f936638eb3bc86972c8f36aab579816b7aedf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
 #include "base/pollevent.hh"
 #include "base/range.hh"
 #include "base/trace.hh"
+#include "base/stats/events.hh"
 #include "cpu/base_cpu.hh"
 #include "cpu/exec_context.hh"
 #include "cpu/exetrace.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"
+#include "sim/stats.hh"
 
 #ifdef FULL_SYSTEM
 #include "base/remote_gdb.hh"
 using namespace std;
 
 SimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
-    : Event(&mainEventQueue, 100), cpu(c)
+    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), multiplier(1)
 {
 }
 
 void
 SimpleCPU::TickEvent::process()
 {
-    cpu->tick();
+    int count = multiplier;
+    do {
+        cpu->tick();
+    } while (--count > 0 && cpu->status() == Running);
 }
 
 const char *
@@ -116,15 +119,16 @@ SimpleCPU::SimpleCPU(const string &_name,
                      Counter max_insts_all_threads,
                      Counter max_loads_any_thread,
                      Counter max_loads_all_threads,
-                     AlphaItb *itb, AlphaDtb *dtb,
+                     AlphaITB *itb, AlphaDTB *dtb,
                      FunctionalMemory *mem,
                      MemInterface *icache_interface,
                      MemInterface *dcache_interface,
-                     Tick freq)
-    : BaseCPU(_name, /* number_of_threads */ 1,
+                     bool _def_reg, Tick freq,
+                     bool _function_trace, Tick _function_trace_start)
+    : BaseCPU(_name, /* number_of_threads */ 1, _def_reg,
               max_insts_any_thread, max_insts_all_threads,
               max_loads_any_thread, max_loads_all_threads,
-              _system, freq),
+              _system, freq, _function_trace, _function_trace_start),
 #else
 SimpleCPU::SimpleCPU(const string &_name, Process *_process,
                      Counter max_insts_any_thread,
@@ -132,10 +136,13 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process,
                      Counter max_loads_any_thread,
                      Counter max_loads_all_threads,
                      MemInterface *icache_interface,
-                     MemInterface *dcache_interface)
-    : BaseCPU(_name, /* number_of_threads */ 1,
+                     MemInterface *dcache_interface,
+                     bool _def_reg,
+                     bool _function_trace, Tick _function_trace_start)
+    : BaseCPU(_name, /* number_of_threads */ 1, _def_reg,
               max_insts_any_thread, max_insts_all_threads,
-              max_loads_any_thread, max_loads_all_threads),
+              max_loads_any_thread, max_loads_all_threads,
+              _function_trace, _function_trace_start),
 #endif
       tickEvent(this), xc(NULL), cacheCompletionEvent(this)
 {
@@ -202,78 +209,51 @@ 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()
 {
-    using namespace Statistics;
+    using namespace Stats;
 
     BaseCPU::regStats();
 
@@ -287,6 +267,11 @@ SimpleCPU::regStats()
         .desc("Number of memory references")
         ;
 
+    notIdleFraction
+        .name(name() + ".not_idle_fraction")
+        .desc("Percentage of non-idle cycles")
+        ;
+
     idleFraction
         .name(name() + ".idle_fraction")
         .desc("Percentage of idle cycles")
@@ -305,8 +290,6 @@ SimpleCPU::regStats()
         ;
 
     idleFraction = constant(1.0) - notIdleFraction;
-    numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst);
-    simInsts += numInsts;
 }
 
 void
@@ -319,6 +302,7 @@ SimpleCPU::resetStats()
 void
 SimpleCPU::serialize(ostream &os)
 {
+    BaseCPU::serialize(os);
     SERIALIZE_ENUM(_status);
     SERIALIZE_SCALAR(inst);
     nameOut(os, csprintf("%s.xc", name()));
@@ -332,6 +316,7 @@ SimpleCPU::serialize(ostream &os)
 void
 SimpleCPU::unserialize(Checkpoint *cp, const string &section)
 {
+    BaseCPU::unserialize(cp, section);
     UNSERIALIZE_ENUM(_status);
     UNSERIALIZE_SCALAR(inst);
     xc->unserialize(cp, csprintf("%s.xc", section));
@@ -345,10 +330,89 @@ change_thread_state(int thread_number, int activate, int priority)
 {
 }
 
+Fault
+SimpleCPU::copySrcTranslate(Addr src)
+{
+    static bool no_warn = true;
+    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+    // Only support block sizes of 64 atm.
+    assert(blk_size == 64);
+    int offset = src & (blk_size - 1);
+
+    // Make sure block doesn't span page
+    if (no_warn &&
+        (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
+        (src >> 40) != 0xfffffc) {
+        warn("Copied block source spans pages %x.", src);
+        no_warn = false;
+    }
+
+    memReq->reset(src & ~(blk_size - 1), blk_size);
+
+    // translate to physical address
+    Fault fault = xc->translateDataReadReq(memReq);
+
+    assert(fault != Alignment_Fault);
+
+    if (fault == No_Fault) {
+        xc->copySrcAddr = src;
+        xc->copySrcPhysAddr = memReq->paddr + offset;
+    } else {
+        xc->copySrcAddr = 0;
+        xc->copySrcPhysAddr = 0;
+    }
+    return fault;
+}
+
+Fault
+SimpleCPU::copy(Addr dest)
+{
+    static bool no_warn = true;
+    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+    // Only support block sizes of 64 atm.
+    assert(blk_size == 64);
+    uint8_t data[blk_size];
+    //assert(xc->copySrcAddr);
+    int offset = dest & (blk_size - 1);
+
+    // Make sure block doesn't span page
+    if (no_warn &&
+        (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
+        (dest >> 40) != 0xfffffc) {
+        no_warn = false;
+        warn("Copied block destination spans pages %x. ", dest);
+    }
+
+    memReq->reset(dest & ~(blk_size -1), blk_size);
+    // translate to physical address
+    Fault fault = xc->translateDataWriteReq(memReq);
+
+    assert(fault != Alignment_Fault);
+
+    if (fault == No_Fault) {
+        Addr dest_addr = memReq->paddr + offset;
+        // Need to read straight from memory since we have more than 8 bytes.
+        memReq->paddr = xc->copySrcPhysAddr;
+        xc->mem->read(memReq, data);
+        memReq->paddr = dest_addr;
+        xc->mem->write(memReq, data);
+        if (dcacheInterface) {
+            memReq->cmd = Copy;
+            memReq->completionEvent = NULL;
+            memReq->paddr = xc->copySrcPhysAddr;
+            memReq->dest = dest_addr;
+            memReq->size = 64;
+            memReq->time = curTick;
+            dcacheInterface->access(memReq);
+        }
+    }
+    return fault;
+}
+
 // 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,18 +434,22 @@ 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;
         }
     }
 
+    if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+        recordEvent("Uncached Read");
+
     return fault;
 }
 
@@ -389,32 +457,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 +490,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,21 +519,25 @@ 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;
         }
     }
 
     if (res && (fault == No_Fault))
         *res = memReq->result;
 
+    if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+        recordEvent("Uncached Write");
+
     return fault;
 }
 
@@ -529,11 +601,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,8 +628,7 @@ SimpleCPU::post_interrupt(int int_num, int index)
 
     if (xc->status() == ExecContext::Suspended) {
                 DPRINTF(IPI,"Suspended Processor awoke\n");
-        xc->setStatus(ExecContext::Active);
-        Annotate::Resume(xc);
+        xc->activate();
     }
 }
 #endif // FULL_SYSTEM
@@ -564,18 +637,18 @@ SimpleCPU::post_interrupt(int int_num, int index)
 void
 SimpleCPU::tick()
 {
+    numCycles++;
+
     traceData = NULL;
 
     Fault fault = No_Fault;
 
 #ifdef FULL_SYSTEM
-    if (AlphaISA::check_interrupts &&
-        xc->cpu->check_interrupts() &&
-        !PC_PAL(xc->regs.pc) &&
+    if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
         status() != IcacheMissComplete) {
         int ipl = 0;
         int summary = 0;
-        AlphaISA::check_interrupts = 0;
+        checkInterrupts = false;
         IntReg *ipr = xc->regs.ipr;
 
         if (xc->regs.ipr[TheISA::IPR_SIRR]) {
@@ -623,7 +696,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 +723,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;
             }
         }
@@ -668,50 +744,31 @@ SimpleCPU::tick()
 
         // keep an instruction count
         numInst++;
+        numInsts++;
 
         // check for instruction-count-based events
-        comInsnEventQueue[0]->serviceEvents(numInst);
+        comInstEventQueue[0]->serviceEvents(numInst);
 
         // decode the instruction
+    inst = htoa(inst);
         StaticInstPtr<TheISA> si(inst);
 
         traceData = Trace::getInstRecord(curTick, xc, this, si,
                                          xc->regs.pc);
 
 #ifdef FULL_SYSTEM
-        xc->regs.opcode = (inst >> 26) & 0x3f;
-        xc->regs.ra = (inst >> 21) & 0x1f;
+        xc->setInst(inst);
 #endif // FULL_SYSTEM
 
-        xc->func_exe_insn++;
+        xc->func_exe_inst++;
 
-        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--;
-                    }
-                }
-            }
-        }
+        fault = si->execute(this, traceData);
+
+#ifdef FULL_SYSTEM
+        if (xc->fnbin)
+            xc->execute(si.get());
 #endif
+
         if (si->isMemRef()) {
             numMemRefs++;
         }
@@ -724,6 +781,8 @@ SimpleCPU::tick()
         if (traceData)
             traceData->finalize();
 
+        traceFunctions(xc->regs.pc);
+
     }  // if (fault == No_Fault)
 
     if (fault != No_Fault) {
@@ -768,8 +827,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
     Param<Counter> max_loads_all_threads;
 
 #ifdef FULL_SYSTEM
-    SimObjectParam<AlphaItb *> itb;
-    SimObjectParam<AlphaDtb *> dtb;
+    SimObjectParam<AlphaITB *> itb;
+    SimObjectParam<AlphaDTB *> dtb;
     SimObjectParam<FunctionalMemory *> mem;
     SimObjectParam<System *> system;
     Param<int> mult;
@@ -781,16 +840,19 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
     SimObjectParam<BaseMem *> dcache;
 
     Param<bool> defer_registration;
+    Param<int> multiplier;
+    Param<bool> function_trace;
+    Param<Tick> function_trace_start;
 
 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",
@@ -812,7 +874,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
     INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
     INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
     INIT_PARAM_DFLT(defer_registration, "defer registration with system "
-                    "(for sampling)", false)
+                    "(for sampling)", false),
+
+    INIT_PARAM_DFLT(multiplier, "clock multiplier", 1),
+    INIT_PARAM_DFLT(function_trace, "Enable function trace", false),
+    INIT_PARAM_DFLT(function_trace_start, "Cycle to start function trace", 0)
 
 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
 
@@ -830,22 +896,25 @@ CREATE_SIM_OBJECT(SimpleCPU)
                         itb, dtb, mem,
                         (icache) ? icache->getInterface() : NULL,
                         (dcache) ? dcache->getInterface() : NULL,
-                        ticksPerSecond * mult);
+                        defer_registration,
+                        ticksPerSecond * mult,
+                        function_trace, function_trace_start);
 #else
 
     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);
+                        (dcache) ? dcache->getInterface() : NULL,
+                        defer_registration,
+                        function_trace, function_trace_start);
 
 #endif // FULL_SYSTEM
 
-    if (!defer_registration) {
-        cpu->registerExecContexts();
-    }
+    cpu->setTickMultiplier(multiplier);
 
     return cpu;
 }
 
 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
+