summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2012-08-28 14:30:31 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2012-08-28 14:30:31 -0400
commitd53d04473e0d6ca1765f1117072eec59187a7f7b (patch)
treed336db3bfb308b14ec5bba88e8f4ddee1dde8899
parentd14e5857c7e1ee053fb4eb448c4776d7c985c5b2 (diff)
downloadgem5-d53d04473e0d6ca1765f1117072eec59187a7f7b.tar.xz
Clock: Rework clocks to avoid tick-to-cycle transformations
This patch introduces the notion of a clock update function that aims to avoid costly divisions when turning the current tick into a cycle. Each clocked object advances a private (hidden) cycle member and a tick member and uses these to implement functions for getting the tick of the next cycle, or the tick of a cycle some time in the future. In the different modules using the clocks, changes are made to avoid counting in ticks only to later translate to cycles. There are a few oddities in how the O3 and inorder CPU count idle cycles, as seen by a few locations where a cycle is subtracted in the calculation. This is done such that the regression does not change any stats, but should be revisited in a future patch. Another, much needed, change that is not done as part of this patch is to introduce a new typedef uint64_t Cycle to be able to at least hint at the unit of the variables counting Ticks vs Cycles. This will be done as a follow-up patch. As an additional follow up, the thread context still uses ticks for the book keeping of last activate and last suspend and this should probably also be changed into cycles as well.
-rw-r--r--src/arch/arm/table_walker.cc2
-rw-r--r--src/arch/x86/mmapped_ipr.hh4
-rw-r--r--src/cpu/base.cc6
-rw-r--r--src/cpu/inorder/cpu.cc31
-rw-r--r--src/cpu/inorder/cpu.hh2
-rw-r--r--src/cpu/inorder/resource.cc2
-rw-r--r--src/cpu/inorder/resource_pool.cc4
-rw-r--r--src/cpu/o3/O3CPU.py4
-rw-r--r--src/cpu/o3/commit.hh2
-rw-r--r--src/cpu/o3/commit_impl.hh3
-rw-r--r--src/cpu/o3/cpu.cc24
-rw-r--r--src/cpu/o3/cpu.hh12
-rw-r--r--src/cpu/o3/fetch_impl.hh2
-rw-r--r--src/cpu/o3/inst_queue_impl.hh2
-rw-r--r--src/cpu/o3/lsq_unit.hh2
-rw-r--r--src/cpu/simple/atomic.cc10
-rw-r--r--src/cpu/simple/timing.cc42
-rw-r--r--src/cpu/simple/timing.hh2
-rw-r--r--src/cpu/testers/memtest/memtest.cc2
-rw-r--r--src/cpu/testers/networktest/networktest.cc2
-rw-r--r--src/dev/arm/pl111.cc16
-rw-r--r--src/dev/i8254xGBe.cc4
-rw-r--r--src/dev/ns_gige.cc6
-rw-r--r--src/sim/clocked_object.hh89
24 files changed, 165 insertions, 110 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index ea71e6f1c..ffa193fbe 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -758,7 +758,7 @@ void
TableWalker::nextWalk(ThreadContext *tc)
{
if (pendingQueue.size())
- schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick()+1));
+ schedule(doProcessEvent, tc->getCpuPtr()->clockEdge(1));
}
diff --git a/src/arch/x86/mmapped_ipr.hh b/src/arch/x86/mmapped_ipr.hh
index 4c3292388..f17b64cad 100644
--- a/src/arch/x86/mmapped_ipr.hh
+++ b/src/arch/x86/mmapped_ipr.hh
@@ -62,7 +62,7 @@ namespace X86ISA
// Make sure we don't trot off the end of data.
assert(offset + pkt->getSize() <= sizeof(MiscReg));
pkt->setData(((uint8_t *)&data) + offset);
- return xc->getCpuPtr()->ticks(1);
+ return 1;
}
inline Tick
@@ -76,7 +76,7 @@ namespace X86ISA
assert(offset + pkt->getSize() <= sizeof(MiscReg));
pkt->writeData(((uint8_t *)&data) + offset);
xc->setMiscReg(index, gtoh(data));
- return xc->getCpuPtr()->ticks(1);
+ return 1;
}
}
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
index ff832f562..98ddde293 100644
--- a/src/cpu/base.cc
+++ b/src/cpu/base.cc
@@ -91,7 +91,7 @@ CPUProgressEvent::process()
{
Counter temp = cpu->totalOps();
#ifndef NDEBUG
- double ipc = double(temp - lastNumInst) / (_interval / cpu->ticks(1));
+ double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod());
DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
"%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
@@ -261,9 +261,7 @@ BaseCPU::startup()
}
if (params()->progress_interval) {
- Tick num_ticks = ticks(params()->progress_interval);
-
- new CPUProgressEvent(this, num_ticks);
+ new CPUProgressEvent(this, params()->progress_interval);
}
}
diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc
index 4aff0c579..ec06f19f0 100644
--- a/src/cpu/inorder/cpu.cc
+++ b/src/cpu/inorder/cpu.cc
@@ -212,7 +212,7 @@ void
InOrderCPU::CPUEvent::scheduleEvent(int delay)
{
assert(!scheduled() || squashed());
- cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
+ cpu->reschedule(this, cpu->clockEdge(delay), true);
}
void
@@ -401,7 +401,7 @@ InOrderCPU::InOrderCPU(Params *params)
frontEndSked = createFrontEndSked();
faultSked = createFaultSked();
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
lockAddr = 0;
lockFlag = false;
@@ -761,17 +761,17 @@ InOrderCPU::tick()
if (!tickEvent.scheduled()) {
if (_status == SwitchedOut) {
// increment stat
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
} else if (!activityRec.active()) {
DPRINTF(InOrderCPU, "sleeping CPU.\n");
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
timesIdled++;
} else {
//Tick next_tick = curTick() + cycles(1);
//tickEvent.schedule(next_tick);
- schedule(&tickEvent, nextCycle(curTick() + 1));
+ schedule(&tickEvent, clockEdge(1));
DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n",
- nextCycle(curTick() + 1));
+ clockEdge(1));
}
}
@@ -959,15 +959,10 @@ InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault,
CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, inst,
event_pri);
- Tick sked_tick = nextCycle(curTick() + ticks(delay));
- if (delay >= 0) {
- DPRINTF(InOrderCPU, "Scheduling CPU Event (%s) for cycle %i, [tid:%i].\n",
- eventNames[c_event], curTick() + delay, tid);
- schedule(cpu_event, sked_tick);
- } else {
- cpu_event->process();
- cpuEventRemoveList.push(cpu_event);
- }
+ Tick sked_tick = clockEdge(delay);
+ DPRINTF(InOrderCPU, "Scheduling CPU Event (%s) for cycle %i, [tid:%i].\n",
+ eventNames[c_event], curTick() + delay, tid);
+ schedule(cpu_event, sked_tick);
// Broadcast event to the Resource Pool
// Need to reset tid just in case this is a dummy instruction
@@ -1696,7 +1691,9 @@ InOrderCPU::wakeCPU()
DPRINTF(Activity, "Waking up CPU\n");
- Tick extra_cycles = tickToCycles((curTick() - 1) - lastRunningCycle);
+ Tick extra_cycles = curCycle() - lastRunningCycle;
+ if (extra_cycles != 0)
+ --extra_cycles;
idleCycles += extra_cycles;
for (int stage_num = 0; stage_num < NumStages; stage_num++) {
@@ -1705,7 +1702,7 @@ InOrderCPU::wakeCPU()
numCycles += extra_cycles;
- schedule(&tickEvent, nextCycle(curTick()));
+ schedule(&tickEvent, nextCycle());
}
// Lots of copied full system code...place into BaseCPU class?
diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh
index 3103201dd..9a0a62c87 100644
--- a/src/cpu/inorder/cpu.hh
+++ b/src/cpu/inorder/cpu.hh
@@ -204,7 +204,7 @@ class InOrderCPU : public BaseCPU
void scheduleTickEvent(int delay)
{
assert(!tickEvent.scheduled() || tickEvent.squashed());
- reschedule(&tickEvent, nextCycle(curTick() + ticks(delay)), true);
+ reschedule(&tickEvent, clockEdge(delay), true);
}
/** Unschedule tick event, regardless of its current state. */
diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc
index 2ddce13c3..098a4e1b4 100644
--- a/src/cpu/inorder/resource.cc
+++ b/src/cpu/inorder/resource.cc
@@ -372,7 +372,7 @@ Resource::ticks(int num_cycles)
void
Resource::scheduleExecution(int slot_num)
{
- if (latency >= 1) {
+ if (latency > 0) {
scheduleEvent(slot_num, latency);
} else {
execute(slot_num);
diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc
index 4c01165b8..31511314e 100644
--- a/src/cpu/inorder/resource_pool.cc
+++ b/src/cpu/inorder/resource_pool.cc
@@ -238,7 +238,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
{
assert(delay >= 0);
- Tick when = cpu->nextCycle(curTick() + cpu->ticks(delay));
+ Tick when = cpu->clockEdge(delay);
switch ((int)e_type)
{
@@ -460,7 +460,7 @@ ResourcePool::ResPoolEvent::scheduleEvent(int delay)
{
InOrderCPU *cpu = resPool->cpu;
assert(!scheduled() || squashed());
- cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
+ cpu->reschedule(this, cpu->clockEdge(delay), true);
}
/** Unschedule resource event, regardless of its current state. */
diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py
index 3138aebbf..9306cb44e 100644
--- a/src/cpu/o3/O3CPU.py
+++ b/src/cpu/o3/O3CPU.py
@@ -76,8 +76,8 @@ class DerivO3CPU(BaseCPU):
renameToROBDelay = Param.Unsigned(1, "Rename to reorder buffer delay")
commitWidth = Param.Unsigned(8, "Commit width")
squashWidth = Param.Unsigned(8, "Squash width")
- trapLatency = Param.Tick(13, "Trap latency")
- fetchTrapLatency = Param.Tick(1, "Fetch trap latency")
+ trapLatency = Param.Unsigned(13, "Trap latency")
+ fetchTrapLatency = Param.Unsigned(1, "Fetch trap latency")
backComSize = Param.Unsigned(5, "Time buffer size for backwards communication")
forwardComSize = Param.Unsigned(5, "Time buffer size for forward communication")
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index b5539c702..1119e8b50 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -409,7 +409,7 @@ class DefaultCommit
/** The latency to handle a trap. Used when scheduling trap
* squash event.
*/
- Tick trapLatency;
+ uint trapLatency;
/** The interrupt fault. */
Fault interrupt;
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index 31398c3d9..66474c05f 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -374,7 +374,6 @@ DefaultCommit<Impl>::initStage()
cpu->activateStage(O3CPU::CommitIdx);
cpu->activityThisCycle();
- trapLatency = cpu->ticks(trapLatency);
}
template <class Impl>
@@ -509,7 +508,7 @@ DefaultCommit<Impl>::generateTrapEvent(ThreadID tid)
TrapEvent *trap = new TrapEvent(this, tid);
- cpu->schedule(trap, curTick() + trapLatency);
+ cpu->schedule(trap, cpu->clockEdge(trapLatency));
trapInFlight[tid] = true;
thread[tid]->trapPending = true;
}
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index 71d04740c..95683a77a 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -386,7 +386,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
// Setup the ROB for whichever stages need it.
commit.setROB(&rob);
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
lastActivatedCycle = 0;
#if 0
@@ -623,13 +623,13 @@ FullO3CPU<Impl>::tick()
getState() == SimObject::Drained) {
DPRINTF(O3CPU, "Switched out!\n");
// increment stat
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
} else if (!activityRec.active() || _status == Idle) {
DPRINTF(O3CPU, "Idle!\n");
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
timesIdled++;
} else {
- schedule(tickEvent, nextCycle(curTick() + ticks(1)));
+ schedule(tickEvent, clockEdge(1));
DPRINTF(O3CPU, "Scheduling next tick!\n");
}
}
@@ -762,7 +762,10 @@ FullO3CPU<Impl>::activateContext(ThreadID tid, int delay)
activityRec.activity();
fetch.wakeFromQuiesce();
- quiesceCycles += tickToCycles((curTick() - 1) - lastRunningCycle);
+ Tick cycles = curCycle() - lastRunningCycle;
+ if (cycles != 0)
+ --cycles;
+ quiesceCycles += cycles;
lastActivatedCycle = curTick();
@@ -801,7 +804,7 @@ FullO3CPU<Impl>::suspendContext(ThreadID tid)
unscheduleTickEvent();
DPRINTF(Quiesce, "Suspending Context\n");
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
_status = Idle;
}
@@ -1275,7 +1278,7 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
if (!tickEvent.scheduled())
schedule(tickEvent, nextCycle());
- lastRunningCycle = curTick();
+ lastRunningCycle = curCycle();
}
template <class Impl>
@@ -1669,8 +1672,11 @@ FullO3CPU<Impl>::wakeCPU()
DPRINTF(Activity, "Waking up CPU\n");
- idleCycles += tickToCycles((curTick() - 1) - lastRunningCycle);
- numCycles += tickToCycles((curTick() - 1) - lastRunningCycle);
+ Tick cycles = curCycle() - lastRunningCycle;
+ if (cycles != 0)
+ --cycles;
+ idleCycles += cycles;
+ numCycles += cycles;
schedule(tickEvent, nextCycle());
}
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index b1fd12a2e..5910f314d 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -214,9 +214,9 @@ class FullO3CPU : public BaseO3CPU
void scheduleTickEvent(int delay)
{
if (tickEvent.squashed())
- reschedule(tickEvent, nextCycle(curTick() + ticks(delay)));
+ reschedule(tickEvent, clockEdge(delay));
else if (!tickEvent.scheduled())
- schedule(tickEvent, nextCycle(curTick() + ticks(delay)));
+ schedule(tickEvent, clockEdge(delay));
}
/** Unschedule tick event, regardless of its current state. */
@@ -256,9 +256,9 @@ class FullO3CPU : public BaseO3CPU
// Schedule thread to activate, regardless of its current state.
if (activateThreadEvent[tid].squashed())
reschedule(activateThreadEvent[tid],
- nextCycle(curTick() + ticks(delay)));
+ clockEdge(delay));
else if (!activateThreadEvent[tid].scheduled()) {
- Tick when = nextCycle(curTick() + ticks(delay));
+ Tick when = clockEdge(delay);
// Check if the deallocateEvent is also scheduled, and make
// sure they do not happen at same time causing a sleep that
@@ -319,10 +319,10 @@ class FullO3CPU : public BaseO3CPU
// Schedule thread to activate, regardless of its current state.
if (deallocateContextEvent[tid].squashed())
reschedule(deallocateContextEvent[tid],
- nextCycle(curTick() + ticks(delay)));
+ clockEdge(delay));
else if (!deallocateContextEvent[tid].scheduled())
schedule(deallocateContextEvent[tid],
- nextCycle(curTick() + ticks(delay)));
+ clockEdge(delay));
}
/** Unschedule thread deallocation in CPU */
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
index caafa3fe3..9caf0c79b 100644
--- a/src/cpu/o3/fetch_impl.hh
+++ b/src/cpu/o3/fetch_impl.hh
@@ -646,7 +646,7 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
assert(!finishTranslationEvent.scheduled());
finishTranslationEvent.setFault(fault);
finishTranslationEvent.setReq(mem_req);
- cpu->schedule(finishTranslationEvent, cpu->nextCycle(curTick() + cpu->ticks(1)));
+ cpu->schedule(finishTranslationEvent, cpu->clockEdge(1));
return;
}
DPRINTF(Fetch, "[tid:%i] Got back req with addr %#x but expected %#x\n",
diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh
index ae5f93c38..b6c3bd239 100644
--- a/src/cpu/o3/inst_queue_impl.hh
+++ b/src/cpu/o3/inst_queue_impl.hh
@@ -828,7 +828,7 @@ InstructionQueue<Impl>::scheduleReadyInsts()
FUCompletion *execution = new FUCompletion(issuing_inst,
idx, this);
- cpu->schedule(execution, curTick() + cpu->ticks(op_latency - 1));
+ cpu->schedule(execution, cpu->clockEdge(op_latency - 1));
// @todo: Enforce that issue_latency == 1 or op_latency
if (issue_latency > 1) {
diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh
index b886a2259..c567341c7 100644
--- a/src/cpu/o3/lsq_unit.hh
+++ b/src/cpu/o3/lsq_unit.hh
@@ -632,7 +632,7 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
delete snd_data_pkt;
}
WritebackEvent *wb = new WritebackEvent(load_inst, data_pkt, this);
- cpu->schedule(wb, curTick() + delay);
+ cpu->schedule(wb, cpu->clockEdge(delay));
return NoFault;
}
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
index fc6724939..d1b0391fc 100644
--- a/src/cpu/simple/atomic.cc
+++ b/src/cpu/simple/atomic.cc
@@ -208,10 +208,10 @@ AtomicSimpleCPU::activateContext(ThreadID thread_num, int delay)
assert(!tickEvent.scheduled());
notIdleFraction++;
- numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
+ numCycles += tickToCycle(thread->lastActivate - thread->lastSuspend);
//Make sure ticks are still on multiples of cycles
- schedule(tickEvent, nextCycle(curTick() + ticks(delay)));
+ schedule(tickEvent, clockEdge(delay));
_status = Running;
}
@@ -518,7 +518,7 @@ AtomicSimpleCPU::tick()
stall_ticks += dcache_latency;
if (stall_ticks) {
- Tick stall_cycles = stall_ticks / ticks(1);
+ Tick stall_cycles = stall_ticks / clockPeriod();
Tick aligned_stall_ticks = ticks(stall_cycles);
if (aligned_stall_ticks < stall_ticks)
@@ -533,8 +533,8 @@ AtomicSimpleCPU::tick()
}
// instruction takes at least one cycle
- if (latency < ticks(1))
- latency = ticks(1);
+ if (latency < clockPeriod())
+ latency = clockPeriod();
if (_status != Idle)
schedule(tickEvent, curTick() + latency);
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index 9022845ce..5437e77aa 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -87,13 +87,11 @@ TimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this),
- dcachePort(this), fetchEvent(this)
+ dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0),
+ fetchEvent(this)
{
_status = Idle;
- ifetch_pkt = dcache_pkt = NULL;
- drainEvent = NULL;
- previousTick = 0;
changeState(SimObject::Running);
system->totalNumInsts = 0;
}
@@ -156,7 +154,7 @@ TimingSimpleCPU::switchOut()
{
assert(_status == Running || _status == Idle);
_status = SwitchedOut;
- numCycles += tickToCycles(curTick() - previousTick);
+ numCycles += curCycle() - previousCycle;
// If we've been scheduled to resume but are then told to switch out,
// we'll need to cancel it.
@@ -184,7 +182,7 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
_status = Idle;
}
assert(threadContexts.size() == 1);
- previousTick = curTick();
+ previousCycle = curCycle();
}
@@ -202,7 +200,7 @@ TimingSimpleCPU::activateContext(ThreadID thread_num, int delay)
_status = Running;
// kick things off by initiating the fetch of the next instruction
- schedule(fetchEvent, nextCycle(curTick() + ticks(delay)));
+ schedule(fetchEvent, clockEdge(delay));
}
@@ -231,9 +229,8 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
{
RequestPtr req = pkt->req;
if (req->isMmappedIpr()) {
- Tick delay;
- delay = TheISA::handleIprRead(thread->getTC(), pkt);
- new IprEvent(pkt, this, nextCycle(curTick() + delay));
+ Tick delay = TheISA::handleIprRead(thread->getTC(), pkt);
+ new IprEvent(pkt, this, clockEdge(delay));
_status = DcacheWaitResponse;
dcache_pkt = NULL;
} else if (!dcachePort.sendTimingReq(pkt)) {
@@ -322,8 +319,8 @@ TimingSimpleCPU::translationFault(Fault fault)
{
// fault may be NoFault in cases where a fault is suppressed,
// for instance prefetches.
- numCycles += tickToCycles(curTick() - previousTick);
- previousTick = curTick();
+ numCycles += curCycle() - previousCycle;
+ previousCycle = curCycle();
if (traceData) {
// Since there was a fault, we shouldn't trace this instruction.
@@ -446,9 +443,8 @@ TimingSimpleCPU::handleWritePacket()
{
RequestPtr req = dcache_pkt->req;
if (req->isMmappedIpr()) {
- Tick delay;
- delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
- new IprEvent(dcache_pkt, this, nextCycle(curTick() + delay));
+ Tick delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
+ new IprEvent(dcache_pkt, this, clockEdge(delay));
_status = DcacheWaitResponse;
dcache_pkt = NULL;
} else if (!dcachePort.sendTimingReq(dcache_pkt)) {
@@ -567,8 +563,8 @@ TimingSimpleCPU::fetch()
_status = IcacheWaitResponse;
completeIfetch(NULL);
- numCycles += tickToCycles(curTick() - previousTick);
- previousTick = curTick();
+ numCycles += curCycle() - previousCycle;
+ previousCycle = curCycle();
}
}
@@ -600,8 +596,8 @@ TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
advanceInst(fault);
}
- numCycles += tickToCycles(curTick() - previousTick);
- previousTick = curTick();
+ numCycles += curCycle() - previousCycle;
+ previousCycle = curCycle();
}
@@ -647,8 +643,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
_status = Running;
- numCycles += tickToCycles(curTick() - previousTick);
- previousTick = curTick();
+ numCycles += curCycle() - previousCycle;
+ previousCycle = curCycle();
if (getState() == SimObject::Draining) {
if (pkt) {
@@ -754,8 +750,8 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
assert(_status == DcacheWaitResponse || _status == DTBWaitResponse ||
pkt->req->getFlags().isSet(Request::NO_ACCESS));
- numCycles += tickToCycles(curTick() - previousTick);
- previousTick = curTick();
+ numCycles += curCycle() - previousCycle;
+ previousCycle = curCycle();
if (pkt->senderState) {
SplitFragmentSenderState * send_state =
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
index b6b78c5db..c4d1573af 100644
--- a/src/cpu/simple/timing.hh
+++ b/src/cpu/simple/timing.hh
@@ -234,7 +234,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
PacketPtr ifetch_pkt;
PacketPtr dcache_pkt;
- Tick previousTick;
+ Tick previousCycle;
protected:
diff --git a/src/cpu/testers/memtest/memtest.cc b/src/cpu/testers/memtest/memtest.cc
index 642af4677..f8a8b66bd 100644
--- a/src/cpu/testers/memtest/memtest.cc
+++ b/src/cpu/testers/memtest/memtest.cc
@@ -246,7 +246,7 @@ void
MemTest::tick()
{
if (!tickEvent.scheduled())
- schedule(tickEvent, curTick() + ticks(1));
+ schedule(tickEvent, clockEdge(1));
if (++noResponseCycles >= 500000) {
if (issueDmas) {
diff --git a/src/cpu/testers/networktest/networktest.cc b/src/cpu/testers/networktest/networktest.cc
index 5d0e8e0c9..05568b3c0 100644
--- a/src/cpu/testers/networktest/networktest.cc
+++ b/src/cpu/testers/networktest/networktest.cc
@@ -165,7 +165,7 @@ NetworkTest::tick()
exitSimLoop("Network Tester completed simCycles");
else {
if (!tickEvent.scheduled())
- schedule(tickEvent, curTick() + ticks(1));
+ schedule(tickEvent, clockEdge(1));
}
}
diff --git a/src/dev/arm/pl111.cc b/src/dev/arm/pl111.cc
index d79a1cf39..7990e02ed 100644
--- a/src/dev/arm/pl111.cc
+++ b/src/dev/arm/pl111.cc
@@ -440,7 +440,7 @@ Pl111::readFramebuffer()
schedule(intEvent, nextCycle());
curAddr = 0;
- startTime = curTick();
+ startTime = curCycle();
maxAddr = static_cast<Addr>(length * bytesPerPixel);
@@ -475,12 +475,12 @@ Pl111::fillFifo()
void
Pl111::dmaDone()
{
- Tick maxFrameTime = lcdTiming2.cpl * height * clock;
+ Tick maxFrameTime = lcdTiming2.cpl * height;
--dmaPendingNum;
if (maxAddr == curAddr && !dmaPendingNum) {
- if ((curTick() - startTime) > maxFrameTime) {
+ if ((curCycle() - startTime) > maxFrameTime) {
warn("CLCD controller buffer underrun, took %d cycles when should"
" have taken %d\n", curTick() - startTime, maxFrameTime);
lcdRis.underflow = 1;
@@ -498,11 +498,13 @@ Pl111::dmaDone()
pic->seekp(0);
bmp->write(pic);
- DPRINTF(PL111, "-- schedule next dma read event at %d tick \n",
- maxFrameTime + curTick());
-
+ // schedule the next read based on when the last frame started
+ // and the desired fps (i.e. maxFrameTime), we turn the
+ // argument into a relative number of cycles in the future by
+ // subtracting curCycle()
if (lcdControl.lcden)
- schedule(readEvent, nextCycle(startTime + maxFrameTime));
+ schedule(readEvent, clockEdge(startTime + maxFrameTime -
+ curCycle()));
}
if (dmaPendingNum > (maxOutstandingDma - waterMark))
diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc
index f7f6a1178..3ba140bce 100644
--- a/src/dev/i8254xGBe.cc
+++ b/src/dev/i8254xGBe.cc
@@ -2052,7 +2052,7 @@ IGbE::restartClock()
{
if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
getState() == SimObject::Running)
- schedule(tickEvent, (curTick() / ticks(1)) * ticks(1) + ticks(1));
+ schedule(tickEvent, clockEdge(1));
}
unsigned int
@@ -2434,7 +2434,7 @@ IGbE::tick()
if (rxTick || txTick || txFifoTick)
- schedule(tickEvent, curTick() + ticks(1));
+ schedule(tickEvent, curTick() + clockPeriod());
}
void
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
index 6a55516c5..583cdb140 100644
--- a/src/dev/ns_gige.cc
+++ b/src/dev/ns_gige.cc
@@ -1147,7 +1147,7 @@ NSGigE::rxKick()
}
// Go to the next state machine clock tick.
- rxKickTick = curTick() + ticks(1);
+ rxKickTick = curTick() + clockPeriod();
}
switch(rxDmaState) {
@@ -1594,7 +1594,7 @@ NSGigE::txKick()
}
// Go to the next state machine clock tick.
- txKickTick = curTick() + ticks(1);
+ txKickTick = curTick() + clockPeriod();
}
switch(txDmaState) {
@@ -2015,7 +2015,7 @@ NSGigE::transferDone()
DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
- reschedule(txEvent, curTick() + ticks(1), true);
+ reschedule(txEvent, curTick() + clockPeriod(), true);
}
bool
diff --git a/src/sim/clocked_object.hh b/src/sim/clocked_object.hh
index 8ab637772..050a15a74 100644
--- a/src/sim/clocked_object.hh
+++ b/src/sim/clocked_object.hh
@@ -58,6 +58,14 @@ class ClockedObject : public SimObject
private:
+ // the tick value of the next clock edge (>= curTick()) at the
+ // time of the last call to update()
+ mutable Tick tick;
+
+ // The cycle counter value corresponding to the current value of
+ // 'tick'
+ mutable Tick cycle;
+
/**
* Prevent inadvertent use of the copy constructor and assignment
* operator by making them private.
@@ -65,6 +73,34 @@ class ClockedObject : public SimObject
ClockedObject(ClockedObject&);
ClockedObject& operator=(ClockedObject&);
+ /**
+ * Align cycle and tick to the next clock edge if not already done.
+ */
+ void update() const
+ {
+ // both tick and cycle are up-to-date and we are done, note
+ // that the >= is important as it captures cases where tick
+ // has already passed curTick()
+ if (tick >= curTick())
+ return;
+
+ // optimise for the common case and see if the tick should be
+ // advanced by a single clock period
+ tick += clock;
+ ++cycle;
+
+ // see if we are done at this point
+ if (tick >= curTick())
+ return;
+
+ // if not, we have to recalculate the cycle and tick, we
+ // perform the calculations in terms of relative cycles to
+ // allow changes to the clock period in the future
+ Tick elapsedCycles = divCeil(curTick() - tick, clock);
+ cycle += elapsedCycles;
+ tick += elapsedCycles * clock;
+ }
+
protected:
// Clock period in ticks
@@ -74,7 +110,8 @@ class ClockedObject : public SimObject
* Create a clocked object and set the clock based on the
* parameters.
*/
- ClockedObject(const ClockedObjectParams* p) : SimObject(p), clock(p->clock)
+ ClockedObject(const ClockedObjectParams* p) :
+ SimObject(p), tick(0), cycle(0), clock(p->clock)
{ }
/**
@@ -85,33 +122,53 @@ class ClockedObject : public SimObject
public:
/**
- * Based on the clock of the object, determine the tick when the
- * next cycle begins, in other words, round the curTick() to the
- * next tick that is a multiple of the clock.
+ * Determine the tick when a cycle begins, by default the current
+ * one, but the argument also enables the caller to determine a
+ * future cycle.
*
- * @return The tick when the next cycle starts
+ * @param cycles The number of cycles into the future
+ *
+ * @return The tick when the clock edge occurs
*/
- Tick nextCycle() const
- { return divCeil(curTick(), clock) * clock; }
+ inline Tick clockEdge(int cycles = 0) const
+ {
+ // align tick to the next clock edge
+ update();
+
+ // figure out when this future cycle is
+ return tick + ticks(cycles);
+ }
/**
- * Determine the next cycle starting from a given tick instead of
- * curTick().
+ * Determine the current cycle, corresponding to a tick aligned to
+ * a clock edge.
*
- * @param begin_tick The tick to round to a clock edge
+ * @return The current cycle
+ */
+ inline Tick curCycle() const
+ {
+ // align cycle to the next clock edge.
+ update();
+
+ return cycle;
+ }
+
+ /**
+ * Based on the clock of the object, determine the tick when the
+ * next cycle begins, in other words, return the next clock edge.
*
- * @return The tick when the cycle after or on begin_tick starts
+ * @return The tick when the next cycle starts
*/
- Tick nextCycle(Tick begin_tick) const
- { return divCeil(begin_tick, clock) * clock; }
+ Tick nextCycle() const
+ { return clockEdge(); }
inline Tick frequency() const { return SimClock::Frequency / clock; }
- inline Tick ticks(int numCycles) const { return clock * numCycles; }
+ inline Tick ticks(int cycles) const { return clock * cycles; }
- inline Tick curCycle() const { return curTick() / clock; }
+ inline Tick clockPeriod() const { return clock; }
- inline Tick tickToCycles(Tick val) const { return val / clock; }
+ inline Tick tickToCycle(Tick tick) const { return tick / clock; }
};