Merge zizzer.eecs.umich.edu:/bk/newmem
[gem5.git] / src / cpu / simple / timing.cc
index fe6775ea4d158cf478e75be30c4092b296764e0d..45da7c3ebd283fd657f066f162899a6d8cfa79ca 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "arch/locked_mem.hh"
 #include "arch/utility.hh"
+#include "base/bigint.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/simple/timing.hh"
 #include "mem/packet.hh"
@@ -82,8 +83,13 @@ TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
 void
 TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
 {
-    if (status == RangeChange)
+    if (status == RangeChange) {
+        if (!snoopRangeSent) {
+            snoopRangeSent = true;
+            sendStatusChange(Port::RangeChange);
+        }
         return;
+    }
 
     panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
 }
@@ -101,6 +107,10 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
       cpu_id(p->cpu_id)
 {
     _status = Idle;
+
+    icachePort.snoopRangeSent = false;
+    dcachePort.snoopRangeSent = false;
+
     ifetch_pkt = dcache_pkt = NULL;
     drainEvent = NULL;
     fetchEvent = NULL;
@@ -160,7 +170,7 @@ TimingSimpleCPU::resume()
 
         fetchEvent =
             new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
-        fetchEvent->schedule(curTick);
+        fetchEvent->schedule(nextCycle());
     }
 
     changeState(SimObject::Running);
@@ -184,7 +194,7 @@ TimingSimpleCPU::switchOut()
 void
 TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
 {
-    BaseCPU::takeOverFrom(oldCPU);
+    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
 
     // if any of this CPU's ThreadContexts are active, mark the CPU as
     // running and schedule its tick event.
@@ -199,23 +209,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
     if (_status != Running) {
         _status = Idle;
     }
-
-    Port *peer;
-    if (icachePort.getPeer() == NULL) {
-        peer = oldCPU->getPort("icache_port")->getPeer();
-        icachePort.setPeer(peer);
-    } else {
-        peer = icachePort.getPeer();
-    }
-    peer->setPeer(&icachePort);
-
-    if (dcachePort.getPeer() == NULL) {
-        peer = oldCPU->getPort("dcache_port")->getPeer();
-        dcachePort.setPeer(peer);
-    } else {
-        peer = dcachePort.getPeer();
-    }
-    peer->setPeer(&dcachePort);
 }
 
 
@@ -229,10 +222,11 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
 
     notIdleFraction++;
     _status = Running;
+
     // kick things off by initiating the fetch of the next instruction
     fetchEvent =
         new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
-    fetchEvent->schedule(curTick + cycles(delay));
+    fetchEvent->schedule(nextCycle(curTick + cycles(delay)));
 }
 
 
@@ -270,7 +264,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
     // Now do the access.
     if (fault == NoFault) {
         PacketPtr pkt =
-            new Packet(req, Packet::ReadReq, Packet::Broadcast);
+            new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
         pkt->dataDynamic<T>(new T);
 
         if (!dcachePort.sendTiming(pkt)) {
@@ -281,17 +275,27 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
             // memory system takes ownership of packet
             dcache_pkt = NULL;
         }
-    }
 
-    // This will need a new way to tell if it has a dcache attached.
-    if (req->isUncacheable())
-        recordEvent("Uncached Read");
+        // This will need a new way to tell if it has a dcache attached.
+        if (req->isUncacheable())
+            recordEvent("Uncached Read");
+    } else {
+        delete req;
+    }
 
     return fault;
 }
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 
+template
+Fault
+TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
+
+template
+Fault
+TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
+
 template
 Fault
 TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
@@ -341,13 +345,20 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
         new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
                     cpu_id, /* thread ID */ 0);
 
+    if (traceData) {
+        traceData->setAddr(req->getVaddr());
+    }
+
     // translate to physical address
     Fault fault = thread->translateDataWriteReq(req);
 
     // Now do the access.
     if (fault == NoFault) {
         assert(dcache_pkt == NULL);
-        dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
+        if (req->isSwap())
+            dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast);
+        else
+            dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
         dcache_pkt->allocate();
         dcache_pkt->set(data);
 
@@ -356,6 +367,10 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
         if (req->isLocked()) {
             do_access = TheISA::handleLockedWrite(thread, req);
         }
+        if (req->isCondSwap()) {
+             assert(res);
+             req->setExtraData(*res);
+        }
 
         if (do_access) {
             if (!dcachePort.sendTiming(dcache_pkt)) {
@@ -366,11 +381,13 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
                 dcache_pkt = NULL;
             }
         }
+        // This will need a new way to tell if it's hooked up to a cache or not.
+        if (req->isUncacheable())
+            recordEvent("Uncached Write");
+    } else {
+        delete req;
     }
 
-    // This will need a new way to tell if it's hooked up to a cache or not.
-    if (req->isUncacheable())
-        recordEvent("Uncached Write");
 
     // If the write needs to have a fault on the access, consider calling
     // changeStatus() and changing it to "bad addr write" or something.
@@ -379,6 +396,16 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+TimingSimpleCPU::write(Twin32_t data, Addr addr,
+                       unsigned flags, uint64_t *res);
+
+template
+Fault
+TimingSimpleCPU::write(Twin64_t data, Addr addr,
+                       unsigned flags, uint64_t *res);
+
 template
 Fault
 TimingSimpleCPU::write(uint64_t data, Addr addr,
@@ -434,7 +461,7 @@ TimingSimpleCPU::fetch()
     ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0);
     Fault fault = setupFetchRequest(ifetch_req);
 
-    ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
+    ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
     ifetch_pkt->dataStatic(&inst);
 
     if (fault == NoFault) {
@@ -448,6 +475,8 @@ TimingSimpleCPU::fetch()
             ifetch_pkt = NULL;
         }
     } else {
+        delete ifetch_req;
+        delete ifetch_pkt;
         // fetch fault: advance directly to next instruction (fault handler)
         advanceInst(fault);
     }
@@ -481,13 +510,13 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
 
     _status = Running;
 
-    delete pkt->req;
-    delete pkt;
-
     numCycles += curTick - previousTick;
     previousTick = curTick;
 
     if (getState() == SimObject::Draining) {
+        delete pkt->req;
+        delete pkt;
+
         completeDrain();
         return;
     }
@@ -519,6 +548,9 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
         postExecute();
         advanceInst(fault);
     }
+
+    delete pkt->req;
+    delete pkt;
 }
 
 void
@@ -532,14 +564,13 @@ TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
 {
     if (pkt->isResponse()) {
         // delay processing of returned data until next CPU clock edge
-        Tick time = pkt->req->getTime();
-        while (time < curTick)
-            time += lat;
+        Tick mem_time = pkt->req->getTime();
+        Tick next_tick = cpu->nextCycle(mem_time);
 
-        if (time == curTick)
+        if (next_tick == curTick)
             cpu->completeIfetch(pkt);
         else
-            tickEvent.schedule(pkt, time);
+            tickEvent.schedule(pkt, next_tick);
 
         return true;
     }
@@ -605,19 +636,30 @@ TimingSimpleCPU::completeDrain()
     drainEvent->process();
 }
 
+void
+TimingSimpleCPU::DcachePort::setPeer(Port *port)
+{
+    Port::setPeer(port);
+
+#if FULL_SYSTEM
+    // Update the ThreadContext's memory ports (Functional/Virtual
+    // Ports)
+    cpu->tcBase()->connectMemPorts();
+#endif
+}
+
 bool
 TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
 {
     if (pkt->isResponse()) {
         // delay processing of returned data until next CPU clock edge
-        Tick time = pkt->req->getTime();
-        while (time < curTick)
-            time += lat;
+        Tick mem_time = pkt->req->getTime();
+        Tick next_tick = cpu->nextCycle(mem_time);
 
-        if (time == curTick)
+        if (next_tick == curTick)
             cpu->completeDataAccess(pkt);
         else
-            tickEvent.schedule(pkt, time);
+            tickEvent.schedule(pkt, next_tick);
 
         return true;
     }
@@ -660,19 +702,23 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     Param<Counter> max_loads_any_thread;
     Param<Counter> max_loads_all_threads;
     Param<Tick> progress_interval;
-    SimObjectParam<MemObject *> mem;
     SimObjectParam<System *> system;
     Param<int> cpu_id;
 
 #if FULL_SYSTEM
-    SimObjectParam<AlphaITB *> itb;
-    SimObjectParam<AlphaDTB *> dtb;
+    SimObjectParam<TheISA::ITB *> itb;
+    SimObjectParam<TheISA::DTB *> dtb;
     Param<Tick> profile;
+
+    Param<bool> do_quiesce;
+    Param<bool> do_checkpoint_insts;
+    Param<bool> do_statistics_insts;
 #else
     SimObjectParam<Process *> workload;
 #endif // FULL_SYSTEM
 
     Param<int> clock;
+    Param<int> phase;
 
     Param<bool> defer_registration;
     Param<int> width;
@@ -693,7 +739,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     INIT_PARAM(max_loads_all_threads,
                "terminate when all threads have reached this load count"),
     INIT_PARAM(progress_interval, "Progress interval"),
-    INIT_PARAM(mem, "memory"),
     INIT_PARAM(system, "system object"),
     INIT_PARAM(cpu_id, "processor ID"),
 
@@ -701,11 +746,15 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     INIT_PARAM(itb, "Instruction TLB"),
     INIT_PARAM(dtb, "Data TLB"),
     INIT_PARAM(profile, ""),
+    INIT_PARAM(do_quiesce, ""),
+    INIT_PARAM(do_checkpoint_insts, ""),
+    INIT_PARAM(do_statistics_insts, ""),
 #else
     INIT_PARAM(workload, "processes to run"),
 #endif // FULL_SYSTEM
 
     INIT_PARAM(clock, "clock speed"),
+    INIT_PARAM_DFLT(phase, "clock phase", 0),
     INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
     INIT_PARAM(width, "cpu width"),
     INIT_PARAM(function_trace, "Enable function trace"),
@@ -727,9 +776,9 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
     params->progress_interval = progress_interval;
     params->deferRegistration = defer_registration;
     params->clock = clock;
+    params->phase = phase;
     params->functionTrace = function_trace;
     params->functionTraceStart = function_trace_start;
-    params->mem = mem;
     params->system = system;
     params->cpu_id = cpu_id;
 
@@ -737,6 +786,9 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
     params->itb = itb;
     params->dtb = dtb;
     params->profile = profile;
+    params->do_quiesce = do_quiesce;
+    params->do_checkpoint_insts = do_checkpoint_insts;
+    params->do_statistics_insts = do_statistics_insts;
 #else
     params->process = workload;
 #endif