TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this),
dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0),
- fetchEvent(this)
+ fetchEvent(this), drainManager(NULL)
{
_status = Idle;
- setDrainState(Drainable::Running);
system->totalNumInsts = 0;
}
{
}
-void
-TimingSimpleCPU::serialize(ostream &os)
-{
- Drainable::State so_state(getDrainState());
- SERIALIZE_ENUM(so_state);
- BaseSimpleCPU::serialize(os);
-}
-
-void
-TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion)
-{
- Drainable::State so_state;
- UNSERIALIZE_ENUM(so_state);
- BaseSimpleCPU::unserialize(cp, section);
-}
-
unsigned int
TimingSimpleCPU::drain(DrainManager *drain_manager)
{
- // TimingSimpleCPU is ready to drain if it's not waiting for
- // an access to complete.
if (_status == Idle ||
- _status == BaseSimpleCPU::Running ||
+ (_status == BaseSimpleCPU::Running && isDrained()) ||
_status == SwitchedOut) {
- setDrainState(Drainable::Drained);
+ assert(!fetchEvent.scheduled());
+ DPRINTF(Drain, "No need to drain.\n");
return 0;
} else {
- setDrainState(Drainable::Draining);
drainManager = drain_manager;
- DPRINTF(Drain, "CPU not drained\n");
+ DPRINTF(Drain, "Requesting drain: %s\n", pcState());
+
+ // The fetch event can become descheduled if a drain didn't
+ // 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 && !isDrained() &&
+ !fetchEvent.scheduled()) {
+ schedule(fetchEvent, nextCycle());
+ }
+
return 1;
}
}
void
TimingSimpleCPU::drainResume()
{
+ assert(!fetchEvent.scheduled());
+
DPRINTF(SimpleCPU, "Resume\n");
if (_status != SwitchedOut && _status != Idle) {
if (system->getMemoryMode() != Enums::timing) {
"'timing' mode.\n");
}
- if (fetchEvent.scheduled())
- deschedule(fetchEvent);
-
schedule(fetchEvent, nextCycle());
}
+}
+
+bool
+TimingSimpleCPU::tryCompleteDrain()
+{
+ if (!drainManager)
+ return false;
+
+ DPRINTF(Drain, "tryCompleteDrain: %s\n", pcState());
+ if (!isDrained())
+ return false;
+
+ DPRINTF(Drain, "CPU done draining, processing drain event\n");
+ drainManager->signalDrainDone();
+ drainManager = NULL;
- setDrainState(Drainable::Running);
+ return true;
}
void
{
BaseSimpleCPU::switchOut();
+ assert(!fetchEvent.scheduled());
assert(_status == BaseSimpleCPU::Running || _status == Idle);
+ assert(!stayAtPC);
+ assert(microPC() == 0);
+
_status = SwitchedOut;
numCycles += curCycle() - previousCycle;
-
- // If we've been scheduled to resume but are then told to switch out,
- // we'll need to cancel it.
- if (fetchEvent.scheduled())
- deschedule(fetchEvent);
}
postExecute();
- if (getDrainState() == Drainable::Draining) {
- advancePC(fault);
- completeDrain();
- } else {
- advanceInst(fault);
- }
+ advanceInst(fault);
}
void
void
TimingSimpleCPU::advanceInst(Fault fault)
{
-
if (_status == Faulting)
return;
if (!stayAtPC)
advancePC(fault);
+ if (tryCompleteDrain())
+ return;
+
if (_status == BaseSimpleCPU::Running) {
// kick off fetch of next instruction... callback from icache
// response will cause that instruction to be executed,
numCycles += curCycle() - previousCycle;
previousCycle = curCycle();
- if (getDrainState() == Drainable::Draining) {
- if (pkt) {
- delete pkt->req;
- delete pkt;
- }
-
- completeDrain();
- return;
- }
-
preExecute();
if (curStaticInst && curStaticInst->isMemRef()) {
// load or store: just send to dcache
postExecute();
- if (getDrainState() == Drainable::Draining) {
- advancePC(fault);
- completeDrain();
-
- return;
- }
-
advanceInst(fault);
}
-
-void
-TimingSimpleCPU::completeDrain()
-{
- DPRINTF(Drain, "CPU done draining, processing drain event\n");
- setDrainState(Drainable::Drained);
- drainManager->signalDrainDone();
-}
-
bool
TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt)
{
/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
virtual void init();
- public:
- DrainManager *drainManager;
-
private:
/*
public:
- virtual void serialize(std::ostream &os);
- virtual void unserialize(Checkpoint *cp, const std::string §ion);
-
unsigned int drain(DrainManager *drain_manager);
void drainResume();
virtual const char *description() const;
};
- void completeDrain();
+ /**
+ * Check if a system is in a drained state.
+ *
+ * We need to drain if:
+ * <ul>
+ * <li>We are in the middle of a microcode sequence as some CPUs
+ * (e.g., HW accelerated CPUs) can't be started in the middle
+ * of a gem5 microcode sequence.
+ *
+ * <li>Stay at PC is true.
+ * </ul>
+ */
+ bool isDrained() {
+ return microPC() == 0 &&
+ !stayAtPC;
+ }
+
+ /**
+ * Try to complete a drain request.
+ *
+ * @returns true if the CPU is drained, false otherwise.
+ */
+ bool tryCompleteDrain();
+
+ /**
+ * Drain manager to use when signaling drain completion
+ *
+ * This pointer is non-NULL when draining and NULL otherwise.
+ */
+ DrainManager *drainManager;
};
#endif // __CPU_SIMPLE_TIMING_HH__