sim: separate nextCycle() and clockEdge() in clockedObjects
authorDam Sunwoo <dam.sunwoo@arm.com>
Mon, 22 Apr 2013 17:20:31 +0000 (13:20 -0400)
committerDam Sunwoo <dam.sunwoo@arm.com>
Mon, 22 Apr 2013 17:20:31 +0000 (13:20 -0400)
Previously, nextCycle() could return the *current* cycle if the current tick was
already aligned with the clock edge. This behavior is not only confusing (not
quite what the function name implies), but also caused problems in the
drainResume() function. When exiting/re-entering the sim loop (e.g., to take
checkpoints), the CPUs will drain and resume. Due to the previous behavior of
nextCycle(), the CPU tick events were being rescheduled in the same ticks that
were already processed before draining. This caused divergence from runs that
did not exit/re-entered the sim loop. (Initially a cycle difference, but a
significant impact later on.)

This patch separates out the two behaviors (nextCycle() and clockEdge()),
uses nextCycle() in drainResume, and uses clockEdge() everywhere else.
Nothing (other than name) should change except for the drainResume timing.

src/cpu/inorder/cpu.cc
src/cpu/o3/cpu.cc
src/cpu/simple/timing.cc
src/dev/arm/hdlcd.cc
src/dev/arm/pl111.cc
src/mem/bridge.cc
src/mem/bus.cc
src/mem/ruby/system/RubyMemoryControl.cc
src/sim/clocked_object.hh

index 5c07621e32213e6ef12ca061d9b9b649d3c92768..2c6b49d82a284c73f96c84462f19f9d4c93cc318 100644 (file)
@@ -1715,7 +1715,7 @@ InOrderCPU::wakeCPU()
 
     numCycles += extra_cycles;
 
-    schedule(&tickEvent, nextCycle());
+    schedule(&tickEvent, clockEdge());
 }
 
 // Lots of copied full system code...place into BaseCPU class?
index 9caa49ad6efca349f679116ffa155a5eeb24f63d..99beaa176773b9f7f615b4b88ba1e674319703c0 100644 (file)
@@ -1720,7 +1720,7 @@ FullO3CPU<Impl>::wakeCPU()
     idleCycles += cycles;
     numCycles += cycles;
 
-    schedule(tickEvent, nextCycle());
+    schedule(tickEvent, clockEdge());
 }
 
 template <class Impl>
index ab4ea9256f11cde1bf621aeed4b70dd01e7dab51..1f453ca639193a2630c18e567b6ea840e0f03e6d 100644 (file)
@@ -120,7 +120,7 @@ TimingSimpleCPU::drain(DrainManager *drain_manager)
         // succeed on the first attempt. We need to reschedule it if
         // the CPU is waiting for a microcode routine to complete.
         if (_status == BaseSimpleCPU::Running && !fetchEvent.scheduled())
-            schedule(fetchEvent, nextCycle());
+            schedule(fetchEvent, clockEdge());
 
         return 1;
     }
@@ -616,7 +616,7 @@ TimingSimpleCPU::advanceInst(Fault fault)
     if (fault != NoFault) {
         advancePC(fault);
         DPRINTF(SimpleCPU, "Fault occured, scheduling fetch event\n");
-        reschedule(fetchEvent, nextCycle(), true);
+        reschedule(fetchEvent, clockEdge(), true);
         _status = Faulting;
         return;
     }
@@ -715,7 +715,7 @@ TimingSimpleCPU::IcachePort::recvTimingResp(PacketPtr pkt)
 {
     DPRINTF(SimpleCPU, "Received timing response %#x\n", pkt->getAddr());
     // delay processing of returned data until next CPU clock edge
-    Tick next_tick = cpu->nextCycle();
+    Tick next_tick = cpu->clockEdge();
 
     if (next_tick == curTick())
         cpu->completeIfetch(pkt);
@@ -807,7 +807,7 @@ bool
 TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt)
 {
     // delay processing of returned data until next CPU clock edge
-    Tick next_tick = cpu->nextCycle();
+    Tick next_tick = cpu->clockEdge();
 
     if (next_tick == curTick()) {
         cpu->completeDataAccess(pkt);
index 14128c73049061c7d6d76572512e894069f30120..c5daebc9be6bcc952c999548602fca8424b9533d 100644 (file)
@@ -282,7 +282,7 @@ HDLcd::write(PacketPtr pkt)
             if (new_command.enable) {
                 doUpdateParams = true;
                 if (!frameUnderway) {
-                    schedule(startFrameEvent, nextCycle());
+                    schedule(startFrameEvent, clockEdge());
                 }
             }
         }
@@ -514,7 +514,7 @@ HDLcd::renderPixel()
             frameUnderrun = true;
             int_rawstat.underrun = 1;
             if (!intEvent.scheduled())
-                schedule(intEvent, nextCycle());
+                schedule(intEvent, clockEdge());
         } else {
             // emulate the pixel read from the internal buffer
             pixelBufferSize -= bytesPerPixel() * count;
@@ -524,7 +524,7 @@ HDLcd::renderPixel()
     // the DMA may have previously stalled due to the buffer being full;
     //   give it a kick; it knows not to fill if at end of frame, underrun, etc
     if (!fillPixelBufferEvent.scheduled())
-        schedule(fillPixelBufferEvent, nextCycle());
+        schedule(fillPixelBufferEvent, clockEdge());
 
     // schedule the next pixel read according to where it is in the frame
     pixelIndex += count;
@@ -597,7 +597,7 @@ HDLcd::dmaDone(DmaDoneEvent *event)
     if ((dmaCurAddr < dmaMaxAddr) &&
         (bytesFreeInPixelBuffer() + targetTransSize < PIXEL_BUFFER_CAPACITY) &&
         !fillPixelBufferEvent.scheduled()) {
-        schedule(fillPixelBufferEvent, nextCycle());
+        schedule(fillPixelBufferEvent, clockEdge());
     }
 }
 
index 8460010f6364fb8aafa091de80a7711a46ad2621..5929da07cc779ec7697fdde903a258705cae9713 100644 (file)
@@ -441,7 +441,7 @@ Pl111::readFramebuffer()
     // Updating base address, interrupt if we're supposed to
     lcdRis.baseaddr = 1;
     if (!intEvent.scheduled())
-        schedule(intEvent, nextCycle());
+        schedule(intEvent, clockEdge());
 
     curAddr = 0;
     startTime = curTick();
@@ -492,7 +492,7 @@ Pl111::dmaDone()
                  " have taken %d\n", curTick() - startTime, maxFrameTime);
             lcdRis.underflow = 1;
             if (!intEvent.scheduled())
-                schedule(intEvent, nextCycle());
+                schedule(intEvent, clockEdge());
         }
 
         assert(!readEvent.scheduled());
@@ -522,7 +522,7 @@ Pl111::dmaDone()
         return;
 
     if (!fillFifoEvent.scheduled())
-        schedule(fillFifoEvent, nextCycle());
+        schedule(fillFifoEvent, clockEdge());
 }
 
 void
index 1a8437aa156b58b799a87ae75baf451b1a57424a..91bef27570d6e7fc006a88aed60f4652251c8e87 100644 (file)
@@ -277,7 +277,7 @@ Bridge::BridgeMasterPort::trySendTiming()
             req = transmitList.front();
             DPRINTF(Bridge, "Scheduling next send\n");
             bridge.schedule(sendEvent, std::max(req.tick,
-                                                bridge.nextCycle()));
+                                                bridge.clockEdge()));
         }
 
         // if we have stalled a request due to a full request queue,
@@ -318,7 +318,7 @@ Bridge::BridgeSlavePort::trySendTiming()
             resp = transmitList.front();
             DPRINTF(Bridge, "Scheduling next send\n");
             bridge.schedule(sendEvent, std::max(resp.tick,
-                                                bridge.nextCycle()));
+                                                bridge.clockEdge()));
         }
 
         // if there is space in the request queue and we were stalling
index 368d49c8635aa892be76373edb0088139bdb6710..8546df565365a098f31d3aca54aa8d32d73ae77b 100644 (file)
@@ -135,7 +135,7 @@ BaseBus::calcPacketTiming(PacketPtr pkt)
     // the bus will be called at a time that is not necessarily
     // coinciding with its own clock, so start by determining how long
     // until the next clock edge (could be zero)
-    Tick offset = nextCycle() - curTick();
+    Tick offset = clockEdge() - curTick();
 
     // determine how many cycles are needed to send the data
     unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
index 75e6e1b06eea9ae86f822465750e21a21b39b6fc..5ffc60e2b26b18bb33f5fef67d7b72a73fb04a76 100644 (file)
@@ -307,7 +307,7 @@ RubyMemoryControl::enqueueMemRef(MemoryNode& memRef)
     m_input_queue.push_back(memRef);
 
     if (!m_event.scheduled()) {
-        schedule(m_event, nextCycle());
+        schedule(m_event, clockEdge());
     }
 }
 
index bf132bee13d07085fb5435dca19172d9bf14ecf2..d836c48cc1276358b994bf4b440a39452e25a90e 100644 (file)
@@ -172,13 +172,14 @@ class ClockedObject : public SimObject
     }
 
     /**
-     * Based on the clock of the object, determine the tick when the
-     * next cycle begins, in other words, return the next clock edge.
+     * Based on the clock of the object, determine the tick when the next
+     * cycle begins, in other words, return the next clock edge.
+     * (This can never be the current tick.)
      *
      * @return The tick when the next cycle starts
      */
     Tick nextCycle() const
-    { return clockEdge(); }
+    { return clockEdge(Cycles(1)); }
 
     inline uint64_t frequency() const { return SimClock::Frequency / clock; }