/*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <iostream>
#include <string>
#include <sstream>
-#include <iostream>
-#include "base_cpu.hh"
-#include "cprintf.hh"
-#include "exec_context.hh"
-#include "misc.hh"
-#include "sim_events.hh"
+#include "base/cprintf.hh"
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "cpu/base_cpu.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/sampling_cpu/sampling_cpu.hh"
+#include "sim/param.hh"
+#include "sim/sim_events.hh"
using namespace std;
int maxThreadsPerCPU = 1;
#ifdef FULL_SYSTEM
-BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
- Counter max_insts_any_thread,
- Counter max_insts_all_threads,
- System *_system, int num, Tick freq)
- : SimObject(_name), number(num), frequency(freq),
- number_of_threads(_number_of_threads), system(_system)
+BaseCPU::BaseCPU(Params *p)
+ : SimObject(p->name), frequency(p->freq), checkInterrupts(true),
+ params(p), number_of_threads(p->numberOfThreads), system(p->system)
#else
-BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
- Counter max_insts_any_thread,
- Counter max_insts_all_threads)
- : SimObject(_name), number_of_threads(_number_of_threads)
+BaseCPU::BaseCPU(Params *p)
+ : SimObject(p->name), params(p), number_of_threads(p->numberOfThreads)
#endif
{
// add self to global list of CPUs
maxThreadsPerCPU = number_of_threads;
// allocate per-thread instruction-based event queues
- comInsnEventQueue = new (EventQueue *)[number_of_threads];
+ comInstEventQueue = new EventQueue *[number_of_threads];
for (int i = 0; i < number_of_threads; ++i)
- comInsnEventQueue[i] = new EventQueue("instruction-based event queue");
+ comInstEventQueue[i] = new EventQueue("instruction-based event queue");
//
// set up instruction-count-based termination events, if any
//
- if (max_insts_any_thread != 0)
+ if (p->max_insts_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i)
- new SimExitEvent(comInsnEventQueue[i], max_insts_any_thread,
+ new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
"a thread reached the max instruction count");
- if (max_insts_all_threads != 0) {
+ if (p->max_insts_all_threads != 0) {
// allocate & initialize shared downcounter: each event will
// decrement this when triggered; simulation will terminate
// when counter reaches 0
int *counter = new int;
*counter = number_of_threads;
for (int i = 0; i < number_of_threads; ++i)
- new CountedExitEvent(comInsnEventQueue[i],
+ new CountedExitEvent(comInstEventQueue[i],
"all threads reached the max instruction count",
- max_insts_all_threads, *counter);
+ p->max_insts_all_threads, *counter);
+ }
+
+ // allocate per-thread load-based event queues
+ comLoadEventQueue = new EventQueue *[number_of_threads];
+ for (int i = 0; i < number_of_threads; ++i)
+ comLoadEventQueue[i] = new EventQueue("load-based event queue");
+
+ //
+ // set up instruction-count-based termination events, if any
+ //
+ if (p->max_loads_any_thread != 0)
+ for (int i = 0; i < number_of_threads; ++i)
+ new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
+ "a thread reached the max load count");
+
+ if (p->max_loads_all_threads != 0) {
+ // allocate & initialize shared downcounter: each event will
+ // decrement this when triggered; simulation will terminate
+ // when counter reaches 0
+ int *counter = new int;
+ *counter = number_of_threads;
+ for (int i = 0; i < number_of_threads; ++i)
+ new CountedExitEvent(comLoadEventQueue[i],
+ "all threads reached the max load count",
+ p->max_loads_all_threads, *counter);
}
#ifdef FULL_SYSTEM
memset(interrupts, 0, sizeof(interrupts));
intstatus = 0;
#endif
+
+ functionTracingEnabled = false;
+ if (p->functionTrace) {
+ functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
+ currentFunctionStart = currentFunctionEnd = 0;
+ functionEntryTick = p->functionTraceStart;
+
+ if (p->functionTraceStart == 0) {
+ functionTracingEnabled = true;
+ } else {
+ Event *e =
+ new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
+ true);
+ e->schedule(p->functionTraceStart);
+ }
+ }
+}
+
+
+void
+BaseCPU::enableFunctionTrace()
+{
+ functionTracingEnabled = true;
+}
+
+BaseCPU::~BaseCPU()
+{
+}
+
+void
+BaseCPU::init()
+{
+ if (!params->deferRegistration)
+ registerExecContexts();
}
void
BaseCPU::regStats()
{
- int size = contexts.size();
+ using namespace Stats;
+
+ numCycles
+ .name(name() + ".numCycles")
+ .desc("number of cpu cycles simulated")
+ ;
+
+ int size = execContexts.size();
if (size > 1) {
for (int i = 0; i < size; ++i) {
stringstream namestr;
ccprintf(namestr, "%s.ctx%d", name(), i);
- contexts[i]->regStats(namestr.str());
+ execContexts[i]->regStats(namestr.str());
}
} else if (size == 1)
- contexts[0]->regStats(name());
+ execContexts[0]->regStats(name());
+}
+
+
+void
+BaseCPU::registerExecContexts()
+{
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+ int cpu_id;
+
+#ifdef FULL_SYSTEM
+ cpu_id = system->registerExecContext(xc);
+#else
+ cpu_id = xc->process->registerExecContext(xc);
+#endif
+
+ xc->cpu_id = cpu_id;
+ }
+}
+
+
+void
+BaseCPU::switchOut(SamplingCPU *sampler)
+{
+ // default: do nothing, signal done
+ sampler->signalSwitched();
+}
+
+void
+BaseCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+ assert(execContexts.size() == oldCPU->execContexts.size());
+
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *newXC = execContexts[i];
+ ExecContext *oldXC = oldCPU->execContexts[i];
+
+ newXC->takeOverFrom(oldXC);
+ assert(newXC->cpu_id == oldXC->cpu_id);
+#ifdef FULL_SYSTEM
+ system->replaceExecContext(newXC, newXC->cpu_id);
+#else
+ assert(newXC->process == oldXC->process);
+ newXC->process->replaceExecContext(newXC, newXC->cpu_id);
+#endif
+ }
+
+#ifdef FULL_SYSTEM
+ for (int i = 0; i < NumInterruptLevels; ++i)
+ interrupts[i] = oldCPU->interrupts[i];
+ intstatus = oldCPU->intstatus;
+#endif
}
+
#ifdef FULL_SYSTEM
void
BaseCPU::post_interrupt(int int_num, int index)
if (int_num < 0 || int_num >= NumInterruptLevels)
panic("int_num out of bounds\n");
- if (index < 0 || index >= sizeof(uint8_t) * 8)
+ if (index < 0 || index >= sizeof(uint64_t) * 8)
panic("int_num out of bounds\n");
- AlphaISA::check_interrupts = 1;
+ checkInterrupts = true;
interrupts[int_num] |= 1 << index;
intstatus |= (ULL(1) << int_num);
}
if (int_num < 0 || int_num >= NumInterruptLevels)
panic("int_num out of bounds\n");
- if (index < 0 || index >= sizeof(uint8_t) * 8)
+ if (index < 0 || index >= sizeof(uint64_t) * 8)
panic("int_num out of bounds\n");
interrupts[int_num] &= ~(1 << index);
intstatus = 0;
}
+
+void
+BaseCPU::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(interrupts, NumInterruptLevels);
+ SERIALIZE_SCALAR(intstatus);
+}
+
+void
+BaseCPU::unserialize(Checkpoint *cp, const std::string §ion)
+{
+ UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels);
+ UNSERIALIZE_SCALAR(intstatus);
+}
+
#endif // FULL_SYSTEM
+void
+BaseCPU::traceFunctionsInternal(Addr pc)
+{
+ if (!debugSymbolTable)
+ return;
+
+ // if pc enters different function, print new function symbol and
+ // update saved range. Otherwise do nothing.
+ if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
+ string sym_str;
+ bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
+ currentFunctionStart,
+ currentFunctionEnd);
+
+ if (!found) {
+ // no symbol found: use addr as label
+ sym_str = csprintf("0x%x", pc);
+ currentFunctionStart = pc;
+ currentFunctionEnd = pc + 1;
+ }
+
+ ccprintf(*functionTraceStream, " (%d)\n%d: %s",
+ curTick - functionEntryTick, curTick, sym_str);
+ functionEntryTick = curTick;
+ }
+}
+
+
DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)