using namespace std;
SimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
- : Event(&mainEventQueue, 100), cpu(c)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
{
}
FunctionalMemory *mem,
MemInterface *icache_interface,
MemInterface *dcache_interface,
- Tick freq)
+ bool _def_reg, Tick freq)
: BaseCPU(_name, /* number_of_threads */ 1,
max_insts_any_thread, max_insts_all_threads,
max_loads_any_thread, max_loads_all_threads,
Counter max_loads_any_thread,
Counter max_loads_all_threads,
MemInterface *icache_interface,
- MemInterface *dcache_interface)
+ MemInterface *dcache_interface,
+ bool _def_reg)
: BaseCPU(_name, /* number_of_threads */ 1,
max_insts_any_thread, max_insts_all_threads,
max_loads_any_thread, max_loads_all_threads),
#endif
- tickEvent(this), xc(NULL), cacheCompletionEvent(this)
+ tickEvent(this), xc(NULL), defer_registration(_def_reg),
+ cacheCompletionEvent(this)
{
_status = Idle;
#ifdef FULL_SYSTEM
{
}
+void SimpleCPU::init()
+{
+ if (!defer_registration) {
+ this->registerExecContexts();
+ }
+}
+
void
SimpleCPU::switchOut()
{
ExecContext *xc = execContexts[i];
if (xc->status() == ExecContext::Active && _status != Running) {
_status = Running;
- // the CpuSwitchEvent has a low priority, so it's
- // scheduled *after* the current cycle's tick event. Thus
- // the first tick event for the new context should take
- // place on the *next* cycle.
- tickEvent.schedule(curTick+1);
+ tickEvent.schedule(curTick);
}
}
void
-SimpleCPU::execCtxStatusChg(int thread_num) {
+SimpleCPU::activateContext(int thread_num, int delay)
+{
+ assert(thread_num == 0);
+ assert(xc);
+
+ assert(_status == Idle);
+ notIdleFraction++;
+ scheduleTickEvent(delay);
+ _status = Running;
+}
+
+
+void
+SimpleCPU::suspendContext(int thread_num)
+{
assert(thread_num == 0);
assert(xc);
- if (xc->status() == ExecContext::Active)
- setStatus(Running);
- else
- setStatus(Idle);
+ assert(_status == Running);
+ notIdleFraction--;
+ unscheduleTickEvent();
+ _status = Idle;
+}
+
+
+void
+SimpleCPU::deallocateContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+
+void
+SimpleCPU::haltContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
}
.prereq(dcacheStallCycles)
;
+ idleFraction = constant(1.0) - notIdleFraction;
numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst);
simInsts += numInsts;
}
SimpleCPU::resetStats()
{
startNumInst = numInst;
+ notIdleFraction = (_status != Idle);
}
void
// precise architected memory state accessor macros
template <class T>
Fault
-SimpleCPU::read(Addr addr, T& data, unsigned flags)
+SimpleCPU::read(Addr addr, T &data, unsigned flags)
{
memReq->reset(addr, sizeof(T), flags);
memReq->cmd = Read;
memReq->completionEvent = NULL;
memReq->time = curTick;
- memReq->flags &= ~UNCACHEABLE;
MemAccessResult result = dcacheInterface->access(memReq);
// Ugly hack to get an event scheduled *only* if the access is
// a miss. We really should add first-class support for this
// at some point.
- if (result != MA_HIT && dcacheInterface->doEvents) {
+ if (result != MA_HIT && dcacheInterface->doEvents()) {
memReq->completionEvent = &cacheCompletionEvent;
- setStatus(DcacheMissStall);
+ lastDcacheStall = curTick;
+ unscheduleTickEvent();
+ _status = DcacheMissStall;
}
}
template
Fault
-SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags);
+SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
template
Fault
-SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags);
+SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
template
Fault
-SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags);
+SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
template
Fault
-SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags);
+SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
#endif //DOXYGEN_SHOULD_SKIP_THIS
template<>
Fault
-SimpleCPU::read(Addr addr, double& data, unsigned flags)
+SimpleCPU::read(Addr addr, double &data, unsigned flags)
{
return read(addr, *(uint64_t*)&data, flags);
}
template<>
Fault
-SimpleCPU::read(Addr addr, float& data, unsigned flags)
+SimpleCPU::read(Addr addr, float &data, unsigned flags)
{
return read(addr, *(uint32_t*)&data, flags);
}
template<>
Fault
-SimpleCPU::read(Addr addr, int32_t& data, unsigned flags)
+SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
{
return read(addr, (uint32_t&)data, flags);
}
memcpy(memReq->data,(uint8_t *)&data,memReq->size);
memReq->completionEvent = NULL;
memReq->time = curTick;
- memReq->flags &= ~UNCACHEABLE;
MemAccessResult result = dcacheInterface->access(memReq);
// Ugly hack to get an event scheduled *only* if the access is
// a miss. We really should add first-class support for this
// at some point.
- if (result != MA_HIT && dcacheInterface->doEvents) {
+ if (result != MA_HIT && dcacheInterface->doEvents()) {
memReq->completionEvent = &cacheCompletionEvent;
- setStatus(DcacheMissStall);
+ lastDcacheStall = curTick;
+ unscheduleTickEvent();
+ _status = DcacheMissStall;
}
}
switch (status()) {
case IcacheMissStall:
icacheStallCycles += curTick - lastIcacheStall;
- setStatus(IcacheMissComplete);
+ _status = IcacheMissComplete;
+ scheduleTickEvent(1);
break;
case DcacheMissStall:
dcacheStallCycles += curTick - lastDcacheStall;
- setStatus(Running);
+ _status = Running;
+ scheduleTickEvent(1);
break;
case SwitchedOut:
// If this CPU has been switched out due to sampling/warm-up,
if (xc->status() == ExecContext::Suspended) {
DPRINTF(IPI,"Suspended Processor awoke\n");
- xc->setStatus(ExecContext::Active);
+ xc->activate();
Annotate::Resume(xc);
}
}
// We've already fetched an instruction and were stalled on an
// I-cache miss. No need to fetch it again.
- setStatus(Running);
+ // Set status to running; tick event will get rescheduled if
+ // necessary at end of tick() function.
+ _status = Running;
}
else {
// Try to fetch an instruction
memReq->completionEvent = NULL;
memReq->time = curTick;
- memReq->flags &= ~UNCACHEABLE;
MemAccessResult result = icacheInterface->access(memReq);
// Ugly hack to get an event scheduled *only* if the access is
// a miss. We really should add first-class support for this
// at some point.
- if (result != MA_HIT && icacheInterface->doEvents) {
+ if (result != MA_HIT && icacheInterface->doEvents()) {
memReq->completionEvent = &cacheCompletionEvent;
- setStatus(IcacheMissStall);
+ lastIcacheStall = curTick;
+ unscheduleTickEvent();
+ _status = IcacheMissStall;
return;
}
}
numInst++;
// check for instruction-count-based events
- comInsnEventQueue[0]->serviceEvents(numInst);
+ comInstEventQueue[0]->serviceEvents(numInst);
// decode the instruction
StaticInstPtr<TheISA> si(inst);
xc->regs.ra = (inst >> 21) & 0x1f;
#endif // FULL_SYSTEM
- xc->func_exe_insn++;
+ xc->func_exe_inst++;
fault = si->execute(this, xc, traceData);
#ifdef FS_MEASURE
BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
INIT_PARAM_DFLT(max_insts_any_thread,
- "terminate when any thread reaches this insn count",
+ "terminate when any thread reaches this inst count",
0),
INIT_PARAM_DFLT(max_insts_all_threads,
- "terminate when all threads have reached this insn count",
+ "terminate when all threads have reached this inst count",
0),
INIT_PARAM_DFLT(max_loads_any_thread,
"terminate when any thread reaches this load count",
itb, dtb, mem,
(icache) ? icache->getInterface() : NULL,
(dcache) ? dcache->getInterface() : NULL,
+ defer_registration,
ticksPerSecond * mult);
#else
max_insts_any_thread, max_insts_all_threads,
max_loads_any_thread, max_loads_all_threads,
(icache) ? icache->getInterface() : NULL,
- (dcache) ? dcache->getInterface() : NULL);
+ (dcache) ? dcache->getInterface() : NULL,
+ defer_registration);
#endif // FULL_SYSTEM
-
+#if 0
if (!defer_registration) {
cpu->registerExecContexts();
}
-
+#endif
return cpu;
}