From f5da73b6881991a28844ed59e8dcc1d154ddae7e Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Thu, 23 Oct 2003 19:07:52 -0700 Subject: [PATCH] Initial support for CPU switching. New SamplingCPU object encompasses a set of CPUs that get switched round-robin (though currently we're only shooting for two CPUs and one switch event, and even that doesn't quite work yet). Registration of ExecContexts with System/Process object factored out so we can create two CPUs but only register one of them at a time. Also worked at making behavior and naming in System and Process objects more consistent. arch/alpha/ev5.cc: Rename ipr_init to initIPRs and get rid of unused mem arg. arch/alpha/fake_syscall.cc: Process:numCpus is now a function (not a data member). base/remote_gdb.hh: Support for ExecContext switching. cpu/base_cpu.cc: cpu/base_cpu.hh: cpu/exec_context.cc: cpu/exec_context.hh: cpu/simple_cpu/simple_cpu.hh: Support for ExecContext switching. Renamed contexts array to execContexts to be consistent with Process. CPU ID now auto-assigned by system object. cpu/simple_cpu/simple_cpu.cc: Support for ExecContext switching. Renamed contexts array to execContexts to be consistent with Process. CPU ID now auto-assigned by system object. Cleaned up MP full-system initialization a bit. dev/alpha_console.cc: Renamed xcvec array to execContexts to be consistent with Process. kern/tru64/tru64_system.cc: kern/tru64/tru64_system.hh: Support for ExecContext switching. CPU ID now auto-assigned by system object. sim/prog.cc: sim/prog.hh: Support for ExecContext switching. Process:numCpus is now a function (not a data member). sim/system.cc: sim/system.hh: Support for ExecContext switching. Renamed xcvec array to execContexts to be consistent with Process. --HG-- extra : convert_revision : 79649cffad5bf3e83de8df44236941907926d791 --- arch/alpha/ev5.cc | 6 +- arch/alpha/fake_syscall.cc | 35 ++++---- base/remote_gdb.hh | 2 + cpu/base_cpu.cc | 64 +++++++++++++-- cpu/base_cpu.hh | 16 +++- cpu/exec_context.cc | 58 ++++++++----- cpu/exec_context.hh | 20 +++-- cpu/simple_cpu/simple_cpu.cc | 152 ++++++++++++++++++++--------------- cpu/simple_cpu/simple_cpu.hh | 15 +++- dev/alpha_console.cc | 2 +- kern/tru64/tru64_system.cc | 40 ++++++--- kern/tru64/tru64_system.hh | 11 +-- sim/prog.cc | 36 ++++++--- sim/prog.hh | 18 +++-- sim/system.cc | 20 +++-- sim/system.hh | 8 +- 16 files changed, 334 insertions(+), 169 deletions(-) diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index e4a9a09e3..cc33f6890 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -44,9 +44,9 @@ AlphaISA::swap_palshadow(RegFile *regs, bool use_shadow) // Machine dependent functions // void -AlphaISA::init(void *mem, RegFile *regs) +AlphaISA::initCPU(RegFile *regs) { - ipr_init(mem, regs); + initIPRs(regs); } void @@ -91,7 +91,7 @@ const int AlphaISA::reg_redir[AlphaISA::NumIntRegs] = { // // void -AlphaISA::ipr_init(void *mem, RegFile *regs) +AlphaISA::initIPRs(RegFile *regs) { uint64_t *ipr = regs->ipr; diff --git a/arch/alpha/fake_syscall.cc b/arch/alpha/fake_syscall.cc index 584b07801..b2e42daaf 100644 --- a/arch/alpha/fake_syscall.cc +++ b/arch/alpha/fake_syscall.cc @@ -511,14 +511,14 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, case OSF::GSI_MAX_CPU: { TypedBufferArg max_cpu(getArg(xc, 1)); - *max_cpu = process->numCpus; + *max_cpu = process->numCpus(); max_cpu.copyOut(xc->mem); return 1; } case OSF::GSI_CPUS_IN_BOX: { TypedBufferArg cpus_in_box(getArg(xc, 1)); - *cpus_in_box = process->numCpus; + *cpus_in_box = process->numCpus(); cpus_in_box.copyOut(xc->mem); return 1; } @@ -534,10 +534,10 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, TypedBufferArg infop(getArg(xc, 1)); infop->current_cpu = 0; - infop->cpus_in_box = process->numCpus; + infop->cpus_in_box = process->numCpus(); infop->cpu_type = 57; - infop->ncpus = process->numCpus; - int cpumask = (1 << process->numCpus) - 1; + infop->ncpus = process->numCpus(); + int cpumask = (1 << process->numCpus()) - 1; infop->cpus_present = infop->cpus_running = cpumask; infop->cpu_binding = 0; infop->cpu_ex_binding = 0; @@ -743,7 +743,7 @@ tableFunc(SyscallDesc *desc, int callnum, Process *process, elp->si_hz = clk_hz; elp->si_phz = clk_hz; elp->si_boottime = seconds_since_epoch; // seconds since epoch? - elp->si_max_procs = process->numCpus; + elp->si_max_procs = process->numCpus(); elp.copyOut(xc->mem); return 0; } @@ -1141,20 +1141,20 @@ nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, cur_addr += sizeof(OSF::nxm_config_info); // next comes the per-cpu state vector Addr slot_state_addr = cur_addr; - int slot_state_size = process->numCpus * sizeof(OSF::nxm_slot_state_t); + int slot_state_size = process->numCpus() * sizeof(OSF::nxm_slot_state_t); cur_addr += slot_state_size; // now the per-RAD state struct (we only support one RAD) cur_addr = 0x14000; // bump up addr for alignment Addr rad_state_addr = cur_addr; int rad_state_size = (sizeof(OSF::nxm_shared) - + (process->numCpus-1) * sizeof(OSF::nxm_sched_state)); + + (process->numCpus()-1) * sizeof(OSF::nxm_sched_state)); cur_addr += rad_state_size; // now initialize a config_info struct and copy it out to user space TypedBufferArg config(config_addr); - config->nxm_nslots_per_rad = process->numCpus; + config->nxm_nslots_per_rad = process->numCpus(); config->nxm_nrads = 1; // only one RAD in our system! config->nxm_slot_state = slot_state_addr; config->nxm_rad[0] = rad_state_addr; @@ -1164,7 +1164,7 @@ nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, // initialize the slot_state array and copy it out TypedBufferArg slot_state(slot_state_addr, slot_state_size); - for (int i = 0; i < process->numCpus; ++i) { + for (int i = 0; i < process->numCpus(); ++i) { // CPU 0 is bound to the calling process; all others are available slot_state[i] = (i == 0) ? OSF::NXM_SLOT_BOUND : OSF::NXM_SLOT_AVAIL; } @@ -1180,7 +1180,7 @@ nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, rad_state->nxm_callback = attrp->nxm_callback; rad_state->nxm_version = attrp->nxm_version; rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; - for (int i = 0; i < process->numCpus; ++i) { + for (int i = 0; i < process->numCpus(); ++i) { OSF::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; ssp->nxm_u.sigmask = 0; ssp->nxm_u.sig = 0; @@ -1250,7 +1250,7 @@ nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, abort(); } - if (thread_index < 0 | thread_index > process->numCpus) { + if (thread_index < 0 | thread_index > process->numCpus()) { cerr << "nxm_thread_create: bad thread index " << thread_index << endl; abort(); @@ -1262,7 +1262,7 @@ nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, // back out again. int rad_state_size = (sizeof(OSF::nxm_shared) + - (process->numCpus-1) * sizeof(OSF::nxm_sched_state)); + (process->numCpus()-1) * sizeof(OSF::nxm_sched_state)); TypedBufferArg rad_state(0x14000, rad_state_size); @@ -1294,7 +1294,7 @@ nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, rad_state.copyOut(xc->mem); Addr slot_state_addr = 0x12000 + sizeof(OSF::nxm_config_info); - int slot_state_size = process->numCpus * sizeof(OSF::nxm_slot_state_t); + int slot_state_size = process->numCpus() * sizeof(OSF::nxm_slot_state_t); TypedBufferArg slot_state(slot_state_addr, slot_state_size); @@ -1312,11 +1312,8 @@ nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, slot_state.copyOut(xc->mem); // Find a free simulator execution context. - list &ecList = process->execContexts; - list::iterator i = ecList.begin(); - list::iterator end = ecList.end(); - for (; i != end; ++i) { - ExecContext *xc = *i; + for (int i = 0; i < process->numCpus(); ++i) { + ExecContext *xc = process->execContexts[i]; if (xc->status() == ExecContext::Unallocated) { // inactive context... grab it diff --git a/base/remote_gdb.hh b/base/remote_gdb.hh index d8e09909a..62fd52856 100644 --- a/base/remote_gdb.hh +++ b/base/remote_gdb.hh @@ -90,6 +90,8 @@ class RemoteGDB RemoteGDB(System *system, ExecContext *context); ~RemoteGDB(); + void replaceExecContext(ExecContext *xc) { context = xc; } + void attach(int fd); void detach(); bool isattached(); diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc index 90e090d5e..74d2ceada 100644 --- a/cpu/base_cpu.cc +++ b/cpu/base_cpu.cc @@ -52,8 +52,8 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - System *_system, int num, Tick freq) - : SimObject(_name), number(num), frequency(freq), + System *_system, Tick freq) + : SimObject(_name), frequency(freq), number_of_threads(_number_of_threads), system(_system) #else BaseCPU::BaseCPU(const string &_name, int _number_of_threads, @@ -120,27 +120,73 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, max_loads_all_threads, *counter); } - #ifdef FULL_SYSTEM memset(interrupts, 0, sizeof(interrupts)); intstatus = 0; #endif } + void BaseCPU::regStats() { - int size = contexts.size(); + 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() +{ + // default: do nothing } +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->cpu_id, newXC); +#else + assert(newXC->process == oldXC->process); + newXC->process->replaceExecContext(newXC->cpu_id, newXC); +#endif + } +} + + #ifdef FULL_SYSTEM void BaseCPU::post_interrupt(int int_num, int index) @@ -185,4 +231,10 @@ BaseCPU::clear_interrupts() #endif // FULL_SYSTEM +// +// This declaration is not needed now that SamplingCPU provides a +// BaseCPUBuilder object. +// +#if 0 DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) +#endif diff --git a/cpu/base_cpu.hh b/cpu/base_cpu.hh index e5d9df6de..5a20aaa54 100644 --- a/cpu/base_cpu.hh +++ b/cpu/base_cpu.hh @@ -47,7 +47,6 @@ class BaseCPU : public SimObject { #ifdef FULL_SYSTEM protected: - int number; Tick frequency; uint8_t interrupts[NumInterruptLevels]; uint64_t intstatus; @@ -71,7 +70,7 @@ class BaseCPU : public SimObject #endif protected: - std::vector contexts; + std::vector execContexts; public: virtual void execCtxStatusChg() {} @@ -82,8 +81,7 @@ class BaseCPU : public SimObject BaseCPU(const std::string &_name, int _number_of_threads, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - System *_system, - int num, Tick freq); + System *_system, Tick freq); #else BaseCPU(const std::string &_name, int _number_of_threads, Counter max_insts_any_thread = 0, @@ -96,6 +94,16 @@ class BaseCPU : public SimObject virtual void regStats(); + virtual void registerExecContexts(); + + /// Prepare for another CPU to take over execution. Called by + /// takeOverFrom() on its argument. + virtual void switchOut(); + + /// Take over execution from the given CPU. Used for warm-up and + /// sampling. + virtual void takeOverFrom(BaseCPU *); + /** * Number of threads we're actually simulating (<= SMT_MAX_THREADS). * This is a constant for the duration of the simulation. diff --git a/cpu/exec_context.cc b/cpu/exec_context.cc index 87f7283aa..6c24500cc 100644 --- a/cpu/exec_context.cc +++ b/cpu/exec_context.cc @@ -43,42 +43,62 @@ using namespace std; #ifdef 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) + FunctionalMemory *_mem) + : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), + cpu_id(-1), mem(_mem), itb(_itb), dtb(_dtb), system(_sys), + memCtrl(_sys->memCtrl), physmem(_sys->physmem), + func_exe_insn(0), storeCondFailures(0) { memset(®s, 0, sizeof(RegFile)); - _status = Active; - func_exe_insn = 0; - storeCondFailures = 0; - system->registerExecContext(this); + setStatus(ExecContext::Unallocated); } #else ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(_process), asid (_asid) + : cpu(_cpu), thread_num(_thread_num), cpu_id(-1), + process(_process), asid (_asid), + func_exe_insn(0), storeCondFailures(0) { - - // 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); + setStatus(ExecContext::Unallocated); mem = process->getMemory(); - - func_exe_insn = 0; - storeCondFailures = 0; } ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(NULL), mem(_mem), - asid(_asid) + : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid), + func_exe_insn(0), storeCondFailures(0) { } #endif + +void +ExecContext::takeOverFrom(ExecContext *oldContext) +{ + // some things should already be set up + assert(mem == oldContext->mem); +#ifdef FULL_SYSTEM + assert(system == oldContext->system); +#else + assert(process == oldContext->process); +#endif + + // copy over functional state + _status = oldContext->_status; +#ifdef FULL_SYSTEM + kernelStats = oldContext->kernelStats; +#endif + regs = oldContext->regs; + cpu_id = oldContext->cpu_id; + func_exe_insn = oldContext->func_exe_insn; + + storeCondFailures = 0; + + oldContext->_status = ExecContext::Unallocated; +} + + void ExecContext::setStatus(Status new_status) { diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh index 4a2688f1c..817c72b3b 100644 --- a/cpu/exec_context.hh +++ b/cpu/exec_context.hh @@ -67,6 +67,11 @@ class ExecContext public: Status status() const { return _status; } + + // Unlike setStatus(), initStatus() has no side effects other than + // setting the _status variable. + void initStatus(Status init_status) { _status = init_status; } + void setStatus(Status new_status); #ifdef FULL_SYSTEM @@ -83,12 +88,15 @@ class ExecContext // Index of hardware thread context on the CPU that this represents. int thread_num; + // ID of this context w.r.t. the System or Process object to which + // it belongs. For full-system mode, this is the system CPU ID. + int cpu_id; + #ifdef FULL_SYSTEM FunctionalMemory *mem; AlphaItb *itb; AlphaDtb *dtb; - int cpu_id; System *system; // the following two fields are redundant, since we can always @@ -124,8 +132,7 @@ class ExecContext // constructor: initialize context from given process structure #ifdef FULL_SYSTEM ExecContext(BaseCPU *_cpu, int _thread_num, System *_system, - AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem, - int _cpu_id); + AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem); #else ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, @@ -133,6 +140,8 @@ class ExecContext #endif virtual ~ExecContext() {} + virtual void takeOverFrom(ExecContext *oldContext); + void regStats(const std::string &name); #ifdef FULL_SYSTEM @@ -156,7 +165,6 @@ class ExecContext return dtb->translate(req, true); } - #else bool validInstAddr(Addr addr) { return process->validInstAddr(addr); } @@ -244,8 +252,8 @@ class ExecContext // and all other stores (WH64?). Unsuccessful Store // Conditionals would have returned above, and wouldn't fall // through. - for (int i = 0; i < system->xcvec.size(); i++){ - cregs = &system->xcvec[i]->regs.miscRegs; + for (int i = 0; i < system->execContexts.size(); i++){ + cregs = &system->execContexts[i]->regs.miscRegs; if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) { cregs->lock_flag = false; } diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index 3c9be172f..c96e31cb0 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -103,11 +103,11 @@ SimpleCPU::SimpleCPU(const string &_name, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, - int cpu_id, Tick freq) + Tick freq) : BaseCPU(_name, /* number_of_threads */ 1, max_insts_any_thread, max_insts_all_threads, max_loads_any_thread, max_loads_all_threads, - _system, cpu_id, freq), + _system, freq), #else SimpleCPU::SimpleCPU(const string &_name, Process *_process, Counter max_insts_any_thread, @@ -122,61 +122,23 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process, #endif tickEvent(this), xc(NULL), cacheCompletionEvent(this) { + _status = Idle; #ifdef FULL_SYSTEM - xc = new ExecContext(this, 0, system, itb, dtb, mem, cpu_id); + xc = new ExecContext(this, 0, system, itb, dtb, mem); - _status = Running; - if (cpu_id != 0) { + TheISA::initCPU(&xc->regs); - xc->setStatus(ExecContext::Unallocated); + IntReg *ipr = xc->regs.ipr; + ipr[TheISA::IPR_MCSR] = 0x6; - //Open a GDB debug session on port (7000 + the cpu_id) - (new GDBListener(new RemoteGDB(system, xc), 7000 + cpu_id))->listen(); - - AlphaISA::init(system->physmem, &xc->regs); - - fault = Reset_Fault; - - IntReg *ipr = xc->regs.ipr; - ipr[TheISA::IPR_MCSR] = 0x6; - - AlphaISA::swap_palshadow(&xc->regs, true); - - xc->regs.pc = - ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; - xc->regs.npc = xc->regs.pc + sizeof(MachInst); - - _status = Idle; - } - else { - system->init(xc); - - // Reset the system - // - AlphaISA::init(system->physmem, &xc->regs); - - fault = Reset_Fault; - - IntReg *ipr = xc->regs.ipr; - ipr[TheISA::IPR_MCSR] = 0x6; - - AlphaISA::swap_palshadow(&xc->regs, true); - - xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; - xc->regs.npc = xc->regs.pc + sizeof(MachInst); - - _status = Running; - tickEvent.schedule(0); - } + AlphaISA::swap_palshadow(&xc->regs, true); + fault = Reset_Fault; + xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; + xc->regs.npc = xc->regs.pc + sizeof(MachInst); #else xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); fault = No_Fault; - if (xc->status() == ExecContext::Active) { - _status = Running; - tickEvent.schedule(0); - } else - _status = Idle; #endif // !FULL_SYSTEM icacheInterface = icache_interface; @@ -193,13 +155,61 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process, lastIcacheStall = 0; lastDcacheStall = 0; - contexts.push_back(xc); + execContexts.push_back(xc); } SimpleCPU::~SimpleCPU() { } + +void +SimpleCPU::registerExecContexts() +{ + BaseCPU::registerExecContexts(); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + // this should only happen at initialization time + assert(curTick == 0); + tickEvent.schedule(0); + } + } +} + + +void +SimpleCPU::switchOut() +{ + _status = SwitchedOut; + if (tickEvent.scheduled()) + tickEvent.squash(); +} + + +void +SimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + assert(!tickEvent.scheduled()); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick + 1); + } + } +} + + void SimpleCPU::regStats() { @@ -488,6 +498,11 @@ SimpleCPU::processCacheCompletion() dcacheStallCycles += curTick - lastDcacheStall; setStatus(Running); break; + case SwitchedOut: + // If this CPU has been switched out due to sampling/warm-up, + // ignore any further status changes (e.g., due to cache + // misses outstanding at the time of the switch). + return; default: panic("SimpleCPU::processCacheCompletion: bad state"); break; @@ -693,7 +708,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) SimObjectParam dtb; SimObjectParam mem; SimObjectParam system; - Param cpu_id; Param mult; #else SimObjectParam workload; @@ -702,6 +716,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) SimObjectParam icache; SimObjectParam dcache; + Param defer_registration; + END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) @@ -724,39 +740,47 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) INIT_PARAM(dtb, "Data TLB"), INIT_PARAM(mem, "memory"), INIT_PARAM(system, "system object"), - INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0), INIT_PARAM_DFLT(mult, "system clock multiplier", 1), #else INIT_PARAM(workload, "processes to run"), #endif // FULL_SYSTEM INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), - INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL) + INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), + INIT_PARAM_DFLT(defer_registration, "defer registration with system " + "(for sampling)", false) END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) CREATE_SIM_OBJECT(SimpleCPU) { + SimpleCPU *cpu; #ifdef FULL_SYSTEM if (mult != 1) panic("processor clock multiplier must be 1\n"); - return new SimpleCPU(getInstanceName(), system, - max_insts_any_thread, max_insts_all_threads, - max_loads_any_thread, max_loads_all_threads, - itb, dtb, mem, - (icache) ? icache->getInterface() : NULL, - (dcache) ? dcache->getInterface() : NULL, - cpu_id, ticksPerSecond * mult); + cpu = new SimpleCPU(getInstanceName(), system, + max_insts_any_thread, max_insts_all_threads, + max_loads_any_thread, max_loads_all_threads, + itb, dtb, mem, + (icache) ? icache->getInterface() : NULL, + (dcache) ? dcache->getInterface() : NULL, + ticksPerSecond * mult); #else - return new SimpleCPU(getInstanceName(), workload, - max_insts_any_thread, max_insts_all_threads, - max_loads_any_thread, max_loads_all_threads, - icache->getInterface(), dcache->getInterface()); + cpu = new SimpleCPU(getInstanceName(), workload, + max_insts_any_thread, max_insts_all_threads, + max_loads_any_thread, max_loads_all_threads, + icache->getInterface(), dcache->getInterface()); #endif // FULL_SYSTEM + + if (!defer_registration) { + cpu->registerExecContexts(); + } + + return cpu; } REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index fd50acfe1..e1b351cab 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -92,7 +92,8 @@ class SimpleCPU : public BaseCPU Idle, IcacheMissStall, IcacheMissComplete, - DcacheMissStall + DcacheMissStall, + SwitchedOut }; private: @@ -117,7 +118,7 @@ class SimpleCPU : public BaseCPU Counter max_loads_any_thread, Counter max_loads_all_threads, AlphaItb *itb, AlphaDtb *dtb, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, - int cpu_id, Tick freq); + Tick freq); #else @@ -135,6 +136,11 @@ class SimpleCPU : public BaseCPU // execution context ExecContext *xc; + void registerExecContexts(); + + void switchOut(); + void takeOverFrom(BaseCPU *oldCPU); + #ifdef FULL_SYSTEM Addr dbg_vtophys(Addr addr); @@ -171,6 +177,7 @@ class SimpleCPU : public BaseCPU CacheCompletionEvent cacheCompletionEvent; Status status() const { return _status; } + virtual void execCtxStatusChg() { if (xc) { if (xc->status() == ExecContext::Active) @@ -182,6 +189,10 @@ class SimpleCPU : public BaseCPU void setStatus(Status new_status) { Status old_status = status(); + + // We should never even get here if the CPU has been switched out. + assert(old_status != SwitchedOut); + _status = new_status; switch (status()) { diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc index b917d7a96..cd03b3656 100644 --- a/dev/alpha_console.cc +++ b/dev/alpha_console.cc @@ -153,7 +153,7 @@ AlphaConsole::write(MemReqPtr req, const uint8_t *data) int cpu = val; assert(cpu > 0 && "Must not access primary cpu"); - ExecContext *other_xc = req->xc->system->xcvec[cpu]; + ExecContext *other_xc = req->xc->system->execContexts[cpu]; other_xc->regs.intRegFile[16] = cpu; other_xc->regs.ipr[TheISA::IPR_PALtemp16] = cpu; other_xc->regs.intRegFile[0] = cpu; diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index 0a4f8ae4e..66eccf58c 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -184,24 +184,44 @@ Tru64System::~Tru64System() } -void -Tru64System::init(ExecContext *xc) +int +Tru64System::registerExecContext(ExecContext *xc) { - xc->regs = *initRegs; + int xcIndex = System::registerExecContext(xc); + + if (xcIndex == 0) { + // xc->regs = *initRegs; + xc->initStatus(ExecContext::Active); + } + else { + xc->initStatus(ExecContext::Unallocated); + } + + RemoteGDB *rgdb = new RemoteGDB(this, xc); + GDBListener *gdbl = new GDBListener(rgdb, 7000 + xcIndex); + gdbl->listen(); + + if (remoteGDB.size() <= xcIndex) { + remoteGDB.resize(xcIndex+1); + } + + remoteGDB[xcIndex] = rgdb; + + return xcIndex; +} - remoteGDB = new RemoteGDB(this, xc); - gdbListen = new GDBListener(remoteGDB, 7000); - gdbListen->listen(); - // Reset the system - // - TheISA::init(physmem, &xc->regs); +void +Tru64System::replaceExecContext(ExecContext *xc, int xcIndex) +{ + System::replaceExecContext(xcIndex, xc); + remoteGDB[xcIndex]->replaceExecContext(xc); } bool Tru64System::breakpoint() { - return remoteGDB->trap(ALPHA_KENTRY_IF); + return remoteGDB[0]->trap(ALPHA_KENTRY_IF); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64System) diff --git a/kern/tru64/tru64_system.hh b/kern/tru64/tru64_system.hh index 7fd337eb5..5a583d62c 100644 --- a/kern/tru64/tru64_system.hh +++ b/kern/tru64/tru64_system.hh @@ -29,6 +29,8 @@ #ifndef __TRU64_SYSTEM_HH__ #define __TRU64_SYSTEM_HH__ +#include + #include "sim/system.hh" #include "targetarch/isa_traits.hh" @@ -48,8 +50,6 @@ class AlphaArguments; class Tru64System : public System { private: - ExecContext *xc; - EcoffObject *kernel; EcoffObject *console; @@ -74,8 +74,8 @@ class Tru64System : public System Addr kernelEntry; public: - RemoteGDB *remoteGDB; - GDBListener *gdbListen; + std::vector remoteGDB; + std::vector gdbListen; public: Tru64System(const std::string _name, @@ -88,7 +88,8 @@ class Tru64System : public System const std::string &boot_osflags); ~Tru64System(); - void init(ExecContext *xc); + int registerExecContext(ExecContext *xc); + void replaceExecContext(ExecContext *xc, int xcIndex); Addr getKernelStart() const { return kernelStart; } Addr getKernelEnd() const { return kernelEnd; } diff --git a/sim/prog.cc b/sim/prog.cc index 275e1551b..599a0ca9a 100644 --- a/sim/prog.cc +++ b/sim/prog.cc @@ -85,8 +85,6 @@ Process::Process(const string &name, fd_map[i] = -1; } - numCpus = 0; - num_syscalls = 0; // other parameters will be initialized when the program is loaded @@ -136,30 +134,42 @@ Process::openOutputFile(const string &filename) } -void -Process::registerExecContext(ExecContext *ec) +int +Process::registerExecContext(ExecContext *xc) { - if (execContexts.empty()) { + // add to list + int myIndex = execContexts.size(); + execContexts.push_back(xc); + + if (myIndex == 0) { // first exec context for this process... initialize & enable // copy process's initial regs struct - ec->regs = *init_regs; + xc->regs = *init_regs; // mark this context as active - ec->setStatus(ExecContext::Active); + xc->initStatus(ExecContext::Active); } else { - ec->setStatus(ExecContext::Unallocated); + xc->initStatus(ExecContext::Unallocated); } - // add to list - execContexts.push_back(ec); - - // increment available CPU count - ++numCpus; + // return CPU number to caller and increment available CPU count + return myIndex; } +void +Process::replaceExecContext(int xcIndex, ExecContext *xc) +{ + if (xcIndex >= execContexts.size()) { + panic("replaceExecContext: bad xcIndex, %d >= %d\n", + xcIndex, execContexts.size()); + } + + execContexts[xcIndex] = xc; +} + // map simulator fd sim_fd to target fd tgt_fd void Process::dup_fd(int sim_fd, int tgt_fd) diff --git a/sim/prog.hh b/sim/prog.hh index ee4bc59fe..e93dd684c 100644 --- a/sim/prog.hh +++ b/sim/prog.hh @@ -36,7 +36,7 @@ // #ifndef FULL_SYSTEM -#include +#include #include "targetarch/isa_traits.hh" #include "sim/sim_object.hh" @@ -55,10 +55,10 @@ class Process : public SimObject bool initialContextLoaded; // execution contexts associated with this process - std::list execContexts; - // number of CPUs assigned to this process: should match number of - // contexts in execContexts list - unsigned numCpus; + std::vector execContexts; + + // number of CPUs (esxec contexts, really) assigned to this process. + unsigned int numCpus() { return execContexts.size(); } // record of blocked context struct WaitRec @@ -123,8 +123,12 @@ class Process : public SimObject // override of virtual SimObject method: register statistics virtual void regStats(); - // register an execution context for this process - void registerExecContext(ExecContext *); + // register an execution context for this process. + // returns xc's cpu number (index into execContexts[]) + int registerExecContext(ExecContext *xc); + + + void replaceExecContext(int xcIndex, ExecContext *xc); // map simulator fd sim_fd to target fd tgt_fd void dup_fd(int sim_fd, int tgt_fd); diff --git a/sim/system.cc b/sim/system.cc index 0e0b83332..76c895a88 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -56,16 +56,24 @@ System::~System() } -void +int System::registerExecContext(ExecContext *xc) { - if (xc->cpu_id >= 12/*MAX_CPUS*/) - panic("Too many CPU's\n"); + int myIndex = execContexts.size(); + execContexts.push_back(xc); + return myIndex; +} + - if (xc->cpu_id >= xcvec.size()) - xcvec.resize(xc->cpu_id + 1); +void +System::replaceExecContext(int xcIndex, ExecContext *xc) +{ + if (xcIndex >= execContexts.size()) { + panic("replaceExecContext: bad xcIndex, %d >= %d\n", + xcIndex, execContexts.size()); + } - xcvec[xc->cpu_id] = xc; + execContexts[xcIndex] = xc; } diff --git a/sim/system.hh b/sim/system.hh index 56a3d6a6f..1c4440b9a 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -52,16 +52,16 @@ class System : public SimObject PCEventQueue pcEventQueue; - std::vector xcvec; - void registerExecContext(ExecContext *xc); + std::vector execContexts; + + virtual int registerExecContext(ExecContext *xc); + virtual void replaceExecContext(int xcIndex, ExecContext *xc); public: System(const std::string _name, const int _init_param, MemoryController *, PhysicalMemory *); ~System(); - virtual void init(ExecContext *xc) = 0; - virtual Addr getKernelStart() const = 0; virtual Addr getKernelEnd() const = 0; virtual Addr getKernelEntry() const = 0; -- 2.30.2