/*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <string>
-#include "base_cpu.hh"
-#include "exec_context.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
-#ifdef FULL_SYSTEM
-#include "system.hh"
+#if FULL_SYSTEM
+#include "base/callback.hh"
+#include "base/cprintf.hh"
+#include "base/output.hh"
+#include "cpu/profile.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_exit.hh"
+#include "sim/system.hh"
+#include "targetarch/stacktrace.hh"
#else
-#include "prog.hh"
+#include "sim/process.hh"
#endif
using namespace std;
// constructor
-#ifdef FULL_SYSTEM
+#if FULL_SYSTEM
ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
- AlphaItb *_itb, AlphaDtb *_dtb,
- FunctionalMemory *_mem, int _cpu_id)
- : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), mem(_mem),
- itb(_itb), dtb(_dtb), cpu_id(_cpu_id), system(_sys),
- memCtrl(_sys->memCtrl), physmem(_sys->physmem)
+ AlphaITB *_itb, AlphaDTB *_dtb,
+ FunctionalMemory *_mem)
+ : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num),
+ cpu_id(-1), mem(_mem), itb(_itb), dtb(_dtb), system(_sys),
+ memctrl(_sys->memctrl), physmem(_sys->physmem),
+ kernelBinning(system->kernelBinning), bin(kernelBinning->bin),
+ fnbin(kernelBinning->fnbin), profile(NULL),
+ func_exe_inst(0), storeCondFailures(0)
{
+ kernelStats = new Kernel::Statistics(this);
memset(®s, 0, sizeof(RegFile));
- _status = Active;
- func_exe_insn = 0;
- storeCondFailures = 0;
- system->registerExecContext(this);
+
+ if (cpu->params->profile) {
+ profile = new FunctionProfile(system->kernelSymtab);
+ Callback *cb =
+ new MakeCallback<ExecContext, &ExecContext::dumpFuncProfile>(this);
+ registerExitCallback(cb);
+ }
+
+ // let's fill with a dummy node for now so we don't get a segfault
+ // on the first cycle when there's no node available.
+ static ProfileNode dummyNode;
+ profileNode = &dummyNode;
+ profilePC = 3;
}
#else
ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
Process *_process, int _asid)
- : cpu(_cpu), thread_num(_thread_num), process(_process), asid (_asid)
+ : _status(ExecContext::Unallocated),
+ cpu(_cpu), thread_num(_thread_num), cpu_id(-1),
+ process(_process), mem(process->getMemory()), asid(_asid),
+ func_exe_inst(0), storeCondFailures(0)
+{
+ memset(®s, 0, sizeof(RegFile));
+}
+
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ FunctionalMemory *_mem, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid),
+ func_exe_inst(0), storeCondFailures(0)
+{
+ memset(®s, 0, sizeof(RegFile));
+}
+#endif
+
+ExecContext::~ExecContext()
+{
+#if FULL_SYSTEM
+ delete kernelStats;
+#endif
+}
+
+#if FULL_SYSTEM
+void
+ExecContext::dumpFuncProfile()
{
+ std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
+ profile->dump(this, *os);
+}
+#endif
- // Register with process object. Our 'active' will be set by the
- // process iff we're the initial context. Others are reserved for
- // dynamically created threads.
- process->registerExecContext(this);
+void
+ExecContext::takeOverFrom(ExecContext *oldContext)
+{
+ // some things should already be set up
+ assert(mem == oldContext->mem);
+#if FULL_SYSTEM
+ assert(system == oldContext->system);
+#else
+ assert(process == oldContext->process);
+#endif
- mem = process->getMemory();
+ // copy over functional state
+ _status = oldContext->_status;
+ regs = oldContext->regs;
+ cpu_id = oldContext->cpu_id;
+ func_exe_inst = oldContext->func_exe_inst;
- func_exe_insn = 0;
storeCondFailures = 0;
+
+ oldContext->_status = ExecContext::Unallocated;
}
-ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
- FunctionalMemory *_mem, int _asid)
- : cpu(_cpu), thread_num(_thread_num), process(NULL), mem(_mem),
- asid(_asid)
+void
+ExecContext::serialize(ostream &os)
{
+ SERIALIZE_ENUM(_status);
+ regs.serialize(os);
+ // thread_num and cpu_id are deterministic from the config
+ SERIALIZE_SCALAR(func_exe_inst);
+ SERIALIZE_SCALAR(inst);
+
+#if FULL_SYSTEM
+ kernelStats->serialize(os);
+#endif
}
+
+
+void
+ExecContext::unserialize(Checkpoint *cp, const std::string §ion)
+{
+ UNSERIALIZE_ENUM(_status);
+ regs.unserialize(cp, section);
+ // thread_num and cpu_id are deterministic from the config
+ UNSERIALIZE_SCALAR(func_exe_inst);
+ UNSERIALIZE_SCALAR(inst);
+
+#if FULL_SYSTEM
+ kernelStats->unserialize(cp, section);
#endif
+}
+
void
-ExecContext::setStatus(Status new_status)
+ExecContext::activate(int delay)
{
-#ifdef FULL_SYSTEM
- if (status() == new_status)
+ if (status() == Active)
return;
+ _status = Active;
+ cpu->activateContext(thread_num, delay);
+}
+
+void
+ExecContext::suspend()
+{
+ if (status() == Suspended)
+ return;
+
+#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
- if (new_status == Suspended && cpu->check_interrupts()) {
+ if (cpu->check_interrupts()) {
assert(status() == Active);
return;
}
#endif
- _status = new_status;
- cpu->execCtxStatusChg();
+ _status = Suspended;
+ cpu->suspendContext(thread_num);
}
+void
+ExecContext::deallocate()
+{
+ if (status() == Unallocated)
+ return;
+
+ _status = Unallocated;
+ cpu->deallocateContext(thread_num);
+}
+
+void
+ExecContext::halt()
+{
+ if (status() == Halted)
+ return;
+
+ _status = Halted;
+ cpu->haltContext(thread_num);
+}
+
+
void
ExecContext::regStats(const string &name)
{
-#ifdef FULL_SYSTEM
- kernelStats.regStats(name + ".kern");
+#if FULL_SYSTEM
+ kernelStats->regStats(name + ".kern");
+#endif
+}
+
+void
+ExecContext::trap(Fault fault)
+{
+ //TheISA::trap(fault); //One possible way to do it...
+
+ /** @todo: Going to hack it for now. Do a true fixup later. */
+#if FULL_SYSTEM
+ ev5_trap(fault);
+#else
+ fatal("fault (%d) detected @ PC 0x%08p", fault, readPC());
#endif
}