Merge zizzer.eecs.umich.edu:/bk/newmem
[gem5.git] / src / cpu / simple / timing.cc
index 33f673cbcf23823c859bf5304445553d2908a84e..45da7c3ebd283fd657f066f162899a6d8cfa79ca 100644 (file)
 
 #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_impl.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
 #include "sim/builder.hh"
 #include "sim/system.hh"
 
@@ -65,14 +67,14 @@ TimingSimpleCPU::init()
 }
 
 Tick
-TimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt)
+TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
 {
     panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
     return curTick;
 }
 
 void
-TimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt)
+TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
 {
     //No internal storage to update, jusst return
     return;
@@ -81,15 +83,20 @@ TimingSimpleCPU::CpuPort::recvFunctional(Packet *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!");
 }
 
 
 void
-TimingSimpleCPU::CpuPort::TickEvent::schedule(Packet *_pkt, Tick t)
+TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
 {
     pkt = _pkt;
     Event::schedule(t);
@@ -100,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;
@@ -147,6 +158,8 @@ void
 TimingSimpleCPU::resume()
 {
     if (_status != SwitchedOut && _status != Idle) {
+        assert(system->getMemoryMode() == System::Timing);
+
         // Delete the old event if it existed.
         if (fetchEvent) {
             if (fetchEvent->scheduled())
@@ -157,10 +170,9 @@ TimingSimpleCPU::resume()
 
         fetchEvent =
             new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
-        fetchEvent->schedule(curTick);
+        fetchEvent->schedule(nextCycle());
     }
 
-    assert(system->getMemoryMode() == System::Timing);
     changeState(SimObject::Running);
     previousTick = curTick;
 }
@@ -182,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.
@@ -197,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);
 }
 
 
@@ -227,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)));
 }
 
 
@@ -267,8 +263,8 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
 
     // Now do the access.
     if (fault == NoFault) {
-        Packet *pkt =
-            new Packet(req, Packet::ReadReq, Packet::Broadcast);
+        PacketPtr pkt =
+            new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
         pkt->dataDynamic<T>(new T);
 
         if (!dcachePort.sendTiming(pkt)) {
@@ -279,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);
@@ -339,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);
 
@@ -354,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)) {
@@ -364,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.
@@ -377,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,
@@ -425,13 +454,14 @@ TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
 void
 TimingSimpleCPU::fetch()
 {
-    checkForInterrupts();
+    if (!curStaticInst || !curStaticInst->isDelayedCommit())
+        checkForInterrupts();
 
     Request *ifetch_req = new Request();
     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) {
@@ -445,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);
     }
@@ -469,7 +501,7 @@ TimingSimpleCPU::advanceInst(Fault fault)
 
 
 void
-TimingSimpleCPU::completeIfetch(Packet *pkt)
+TimingSimpleCPU::completeIfetch(PacketPtr pkt)
 {
     // received a response from the icache: execute the received
     // instruction
@@ -478,13 +510,13 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
 
     _status = Running;
 
-    delete pkt->req;
-    delete pkt;
-
     numCycles += curTick - previousTick;
     previousTick = curTick;
 
     if (getState() == SimObject::Draining) {
+        delete pkt->req;
+        delete pkt;
+
         completeDrain();
         return;
     }
@@ -516,6 +548,9 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
         postExecute();
         advanceInst(fault);
     }
+
+    delete pkt->req;
+    delete pkt;
 }
 
 void
@@ -525,19 +560,24 @@ TimingSimpleCPU::IcachePort::ITickEvent::process()
 }
 
 bool
-TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt)
+TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
 {
-    // delay processing of returned data until next CPU clock edge
-    Tick time = pkt->req->getTime();
-    while (time < curTick)
-        time += lat;
+    if (pkt->isResponse()) {
+        // delay processing of returned data until next CPU clock edge
+        Tick mem_time = pkt->req->getTime();
+        Tick next_tick = cpu->nextCycle(mem_time);
 
-    if (time == curTick)
-        cpu->completeIfetch(pkt);
-    else
-        tickEvent.schedule(pkt, time);
+        if (next_tick == curTick)
+            cpu->completeIfetch(pkt);
+        else
+            tickEvent.schedule(pkt, next_tick);
 
-    return true;
+        return true;
+    }
+    else {
+        //Snooping a Coherence Request, do nothing
+        return true;
+    }
 }
 
 void
@@ -547,7 +587,7 @@ TimingSimpleCPU::IcachePort::recvRetry()
     // waiting to transmit
     assert(cpu->ifetch_pkt != NULL);
     assert(cpu->_status == IcacheRetry);
-    Packet *tmp = cpu->ifetch_pkt;
+    PacketPtr tmp = cpu->ifetch_pkt;
     if (sendTiming(tmp)) {
         cpu->_status = IcacheWaitResponse;
         cpu->ifetch_pkt = NULL;
@@ -555,7 +595,7 @@ TimingSimpleCPU::IcachePort::recvRetry()
 }
 
 void
-TimingSimpleCPU::completeDataAccess(Packet *pkt)
+TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
 {
     // received a response from the dcache: complete the load or store
     // instruction
@@ -596,20 +636,37 @@ 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(Packet *pkt)
+TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
 {
-    // delay processing of returned data until next CPU clock edge
-    Tick time = pkt->req->getTime();
-    while (time < curTick)
-        time += lat;
+    if (pkt->isResponse()) {
+        // delay processing of returned data until next CPU clock edge
+        Tick mem_time = pkt->req->getTime();
+        Tick next_tick = cpu->nextCycle(mem_time);
 
-    if (time == curTick)
-        cpu->completeDataAccess(pkt);
-    else
-        tickEvent.schedule(pkt, time);
+        if (next_tick == curTick)
+            cpu->completeDataAccess(pkt);
+        else
+            tickEvent.schedule(pkt, next_tick);
 
-    return true;
+        return true;
+    }
+    else {
+        //Snooping a coherence req, do nothing
+        return true;
+    }
 }
 
 void
@@ -625,7 +682,7 @@ TimingSimpleCPU::DcachePort::recvRetry()
     // waiting to transmit
     assert(cpu->dcache_pkt != NULL);
     assert(cpu->_status == DcacheRetry);
-    Packet *tmp = cpu->dcache_pkt;
+    PacketPtr tmp = cpu->dcache_pkt;
     if (sendTiming(tmp)) {
         cpu->_status = DcacheWaitResponse;
         // memory system takes ownership of packet
@@ -645,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;
@@ -678,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"),
 
@@ -686,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"),
@@ -712,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;
 
@@ -722,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