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.
This commit is contained in:
parent
d14e5857c7
commit
d53d04473e
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -234,7 +234,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
|||
PacketPtr ifetch_pkt;
|
||||
PacketPtr dcache_pkt;
|
||||
|
||||
Tick previousTick;
|
||||
Tick previousCycle;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ void
|
|||
MemTest::tick()
|
||||
{
|
||||
if (!tickEvent.scheduled())
|
||||
schedule(tickEvent, curTick() + ticks(1));
|
||||
schedule(tickEvent, clockEdge(1));
|
||||
|
||||
if (++noResponseCycles >= 500000) {
|
||||
if (issueDmas) {
|
||||
|
|
|
@ -165,7 +165,7 @@ NetworkTest::tick()
|
|||
exitSimLoop("Network Tester completed simCycles");
|
||||
else {
|
||||
if (!tickEvent.scheduled())
|
||||
schedule(tickEvent, curTick() + ticks(1));
|
||||
schedule(tickEvent, clockEdge(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{ }
|
||||
|
||||
/**
|
||||
|
@ -84,34 +121,54 @@ class ClockedObject : public SimObject
|
|||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Determine the tick when a cycle begins, by default the current
|
||||
* one, but the argument also enables the caller to determine a
|
||||
* future cycle.
|
||||
*
|
||||
* @param cycles The number of cycles into the future
|
||||
*
|
||||
* @return The tick when the clock edge occurs
|
||||
*/
|
||||
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 current cycle, corresponding to a tick aligned 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, round the curTick() to the
|
||||
* next tick that is a multiple of the clock.
|
||||
* next cycle begins, in other words, return the next clock edge.
|
||||
*
|
||||
* @return The tick when the next cycle starts
|
||||
*/
|
||||
Tick nextCycle() const
|
||||
{ return divCeil(curTick(), clock) * clock; }
|
||||
|
||||
/**
|
||||
* Determine the next cycle starting from a given tick instead of
|
||||
* curTick().
|
||||
*
|
||||
* @param begin_tick The tick to round to a clock edge
|
||||
*
|
||||
* @return The tick when the cycle after or on begin_tick starts
|
||||
*/
|
||||
Tick nextCycle(Tick begin_tick) const
|
||||
{ return divCeil(begin_tick, clock) * clock; }
|
||||
{ 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; }
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue