diff options
Diffstat (limited to 'cpu')
98 files changed, 0 insertions, 30014 deletions
diff --git a/cpu/SConscript b/cpu/SConscript deleted file mode 100644 index 3840b9d41..000000000 --- a/cpu/SConscript +++ /dev/null @@ -1,167 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import os.path - -# Import build environment variable from SConstruct. -Import('env') - -################################################################# -# -# Generate StaticInst execute() method signatures. -# -# There must be one signature for each CPU model compiled in. -# Since the set of compiled-in models is flexible, we generate a -# header containing the appropriate set of signatures on the fly. -# -################################################################# - -# CPU model-specific data is contained in cpu_models.py -# Convert to SCons File node to get path handling -models_db = File('cpu_models.py') -# slurp in contents of file -execfile(models_db.srcnode().abspath) - -# Template for execute() signature. -exec_sig_template = ''' -virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; -''' - -mem_ini_sig_template = ''' -virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); }; -''' - -mem_comp_sig_template = ''' -virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; }; -''' - -# Generate header. -def gen_cpu_exec_signatures(target, source, env): - f = open(str(target[0]), 'w') - print >> f, ''' -#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__ -#define __CPU_STATIC_INST_EXEC_SIGS_HH__ -''' - for cpu in env['CPU_MODELS']: - xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % xc_type - print >> f, mem_ini_sig_template % xc_type - print >> f, mem_comp_sig_template % xc_type - print >> f, ''' -#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ -''' - -# Generate string that gets printed when header is rebuilt -def gen_sigs_string(target, source, env): - return "Generating static_inst_exec_sigs.hh: " \ - + ', '.join(env['CPU_MODELS']) - -# Add command to generate header to environment. -env.Command('static_inst_exec_sigs.hh', models_db, - Action(gen_cpu_exec_signatures, gen_sigs_string, - varlist = ['CPU_MODELS'])) - -################################################################# -# -# Include CPU-model-specific files based on set of models -# specified in CPU_MODELS build option. -# -################################################################# - -sources = [] - -if 'SimpleCPU' in env['CPU_MODELS']: - sources += Split('simple/cpu.cc') - -if 'FastCPU' in env['CPU_MODELS']: - sources += Split('fast/cpu.cc') - -if 'AlphaFullCPU' in env['CPU_MODELS']: - sources += Split(''' - o3/2bit_local_pred.cc - o3/alpha_dyn_inst.cc - o3/alpha_cpu.cc - o3/alpha_cpu_builder.cc - o3/bpred_unit.cc - o3/btb.cc - o3/commit.cc - o3/decode.cc - o3/fetch.cc - o3/free_list.cc - o3/fu_pool.cc - o3/cpu.cc - o3/iew.cc - o3/inst_queue.cc - o3/lsq_unit.cc - o3/lsq.cc - o3/mem_dep_unit.cc - o3/ras.cc - o3/rename.cc - o3/rename_map.cc - o3/rob.cc - o3/scoreboard.cc - o3/store_set.cc - o3/tournament_pred.cc - ''') - -if 'OzoneSimpleCPU' in env['CPU_MODELS']: - sources += Split(''' - ozone/cpu.cc - ozone/cpu_builder.cc - ozone/dyn_inst.cc - ozone/front_end.cc - ozone/inorder_back_end.cc - ozone/inst_queue.cc - ozone/rename_table.cc - ''') - -if 'OzoneCPU' in env['CPU_MODELS']: - sources += Split(''' - ozone/back_end.cc - ozone/lsq_unit.cc - ozone/lw_back_end.cc - ozone/lw_lsq.cc - ''') - -if 'CheckerCPU' in env['CPU_MODELS']: - sources += Split(''' - checker/cpu.cc - checker/cpu_builder.cc - checker/o3_cpu_builder.cc - ''') - -# FullCPU sources are included from m5/SConscript since they're not -# below this point in the file hierarchy. - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -Return('sources') - diff --git a/cpu/base.cc b/cpu/base.cc deleted file mode 100644 index de03b9eab..000000000 --- a/cpu/base.cc +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "sim/param.hh" -#include "sim/process.hh" -#include "sim/sim_events.hh" -#include "sim/system.hh" - -#include "base/trace.hh" - -using namespace std; - -vector<BaseCPU *> BaseCPU::cpuList; - -// This variable reflects the max number of threads in any CPU. Be -// careful to only use it once all the CPUs that you care about have -// been initialized -int maxThreadsPerCPU = 1; - -#if FULL_SYSTEM -BaseCPU::BaseCPU(Params *p) - : SimObject(p->name), clock(p->clock), checkInterrupts(true), - params(p), number_of_threads(p->numberOfThreads), system(p->system) -#else -BaseCPU::BaseCPU(Params *p) - : SimObject(p->name), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads) -#endif -{ - DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); - - // add self to global list of CPUs - cpuList.push_back(this); - - DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", - this); - - if (number_of_threads > maxThreadsPerCPU) - maxThreadsPerCPU = number_of_threads; - - // allocate per-thread instruction-based event queues - comInstEventQueue = new EventQueue *[number_of_threads]; - for (int i = 0; i < number_of_threads; ++i) - comInstEventQueue[i] = new EventQueue("instruction-based event queue"); - - // - // set up instruction-count-based termination events, if any - // - if (p->max_insts_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, - "a thread reached the max instruction count"); - - 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(comInstEventQueue[i], - "all threads reached the max instruction count", - 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); - } - -#if 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); - } - } -#if FULL_SYSTEM - profileEvent = NULL; - if (params->profile) - profileEvent = new ProfileEvent(this, params->profile); -#endif - -} - -BaseCPU::Params::Params() -{ -#if FULL_SYSTEM - profile = false; -#endif - checker = NULL; -} - -void -BaseCPU::enableFunctionTrace() -{ - functionTracingEnabled = true; -} - -BaseCPU::~BaseCPU() -{ -} - -void -BaseCPU::init() -{ - if (!params->deferRegistration) - registerExecContexts(); -} - -void -BaseCPU::startup() -{ -#if FULL_SYSTEM - if (!params->deferRegistration && profileEvent) - profileEvent->schedule(curTick); -#endif -} - - -void -BaseCPU::regStats() -{ - 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); - execContexts[i]->regStats(namestr.str()); - } - } else if (size == 1) - execContexts[0]->regStats(name()); - -#if FULL_SYSTEM -#endif -} - - -void -BaseCPU::registerExecContexts() -{ - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - if (xc->status() == ExecContext::Suspended) { -#if FULL_SYSTEM - int id = params->cpu_id; - if (id != -1) - id += i; - - xc->setCpuId(system->registerExecContext(xc, id)); -#else - xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); -#endif - } - } -} - - -void -BaseCPU::switchOut(Sampler *sampler) -{ - panic("This CPU doesn't support sampling!"); -} - -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->readCpuId() == oldXC->readCpuId()); -#if FULL_SYSTEM - system->replaceExecContext(newXC, newXC->readCpuId()); -#else - assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); - newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); -#endif - } - -#if FULL_SYSTEM - for (int i = 0; i < TheISA::NumInterruptLevels; ++i) - interrupts[i] = oldCPU->interrupts[i]; - intstatus = oldCPU->intstatus; - - for (int i = 0; i < execContexts.size(); ++i) - execContexts[i]->profileClear(); - - if (profileEvent) - profileEvent->schedule(curTick); -#endif -} - - -#if FULL_SYSTEM -BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) - : Event(&mainEventQueue), cpu(_cpu), interval(_interval) -{ } - -void -BaseCPU::ProfileEvent::process() -{ - for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { - ExecContext *xc = cpu->execContexts[i]; - xc->profileSample(); - } - - schedule(curTick + interval); -} - -void -BaseCPU::post_interrupt(int int_num, int index) -{ - DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); - - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); - - checkInterrupts = true; - interrupts[int_num] |= 1 << index; - intstatus |= (ULL(1) << int_num); -} - -void -BaseCPU::clear_interrupt(int int_num, int index) -{ - DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); - - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); - - interrupts[int_num] &= ~(1 << index); - if (interrupts[int_num] == 0) - intstatus &= ~(ULL(1) << int_num); -} - -void -BaseCPU::clear_interrupts() -{ - DPRINTF(Interrupt, "Interrupts all cleared\n"); - - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; -} - - -void -BaseCPU::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); - SERIALIZE_SCALAR(intstatus); -} - -void -BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(interrupts, TheISA::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) diff --git a/cpu/base.hh b/cpu/base.hh deleted file mode 100644 index dd776859d..000000000 --- a/cpu/base.hh +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_BASE_HH__ -#define __CPU_BASE_HH__ - -#include <vector> - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/sampler/sampler.hh" -#include "sim/eventq.hh" -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class BranchPred; -class CheckerCPU; -class ExecContext; -class System; - -class BaseCPU : public SimObject -{ - protected: - // CPU's clock period in terms of the number of ticks of curTime. - Tick clock; - - public: - inline Tick frequency() const { return Clock::Frequency / clock; } - inline Tick cycles(int numCycles) const { return clock * numCycles; } - inline Tick curCycle() const { return curTick / clock; } - -#if FULL_SYSTEM - protected: - uint64_t interrupts[TheISA::NumInterruptLevels]; - uint64_t intstatus; - - public: - virtual void post_interrupt(int int_num, int index); - virtual void clear_interrupt(int int_num, int index); - virtual void clear_interrupts(); - bool checkInterrupts; - - bool check_interrupt(int int_num) const { - if (int_num > TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - return interrupts[int_num] != 0; - } - - bool check_interrupts() const { return intstatus != 0; } - uint64_t intr_status() const { return intstatus; } - - class ProfileEvent : public Event - { - private: - BaseCPU *cpu; - int interval; - - public: - ProfileEvent(BaseCPU *cpu, int interval); - void process(); - }; - ProfileEvent *profileEvent; -#endif - - protected: - std::vector<ExecContext *> execContexts; - - public: - - /// Notify the CPU that the indicated context is now active. The - /// delay parameter indicates the number of ticks to wait before - /// executing (typically 0 or 1). - virtual void activateContext(int thread_num, int delay) {} - - /// Notify the CPU that the indicated context is now suspended. - virtual void suspendContext(int thread_num) {} - - /// Notify the CPU that the indicated context is now deallocated. - virtual void deallocateContext(int thread_num) {} - - /// Notify the CPU that the indicated context is now halted. - virtual void haltContext(int thread_num) {} - - public: - struct Params - { - std::string name; - int numberOfThreads; - bool deferRegistration; - Counter max_insts_any_thread; - Counter max_insts_all_threads; - Counter max_loads_any_thread; - Counter max_loads_all_threads; - Tick clock; - bool functionTrace; - Tick functionTraceStart; -#if FULL_SYSTEM - System *system; - int cpu_id; - Tick profile; -#endif - BaseCPU *checker; - - Params(); - }; - - const Params *params; - - BaseCPU(Params *params); - virtual ~BaseCPU(); - - virtual void init(); - virtual void startup(); - virtual void regStats(); - - virtual void activateWhenReady(int tid) {}; - - void registerExecContexts(); - - /// Prepare for another CPU to take over execution. When it is - /// is ready (drained pipe) it signals the sampler. - virtual void switchOut(Sampler *); - - /// 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. - */ - int number_of_threads; - - /** - * Vector of per-thread instruction-based event queues. Used for - * scheduling events based on number of instructions committed by - * a particular thread. - */ - EventQueue **comInstEventQueue; - - /** - * Vector of per-thread load-based event queues. Used for - * scheduling events based on number of loads committed by - *a particular thread. - */ - EventQueue **comLoadEventQueue; - -#if FULL_SYSTEM - System *system; - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -#endif - - /** - * Return pointer to CPU's branch predictor (NULL if none). - * @return Branch predictor pointer. - */ - virtual BranchPred *getBranchPred() { return NULL; }; - - virtual Counter totalInstructions() const { return 0; } - - // Function tracing - private: - bool functionTracingEnabled; - std::ostream *functionTraceStream; - Addr currentFunctionStart; - Addr currentFunctionEnd; - Tick functionEntryTick; - void enableFunctionTrace(); - void traceFunctionsInternal(Addr pc); - - protected: - void traceFunctions(Addr pc) - { - if (functionTracingEnabled) - traceFunctionsInternal(pc); - } - - private: - static std::vector<BaseCPU *> cpuList; //!< Static global cpu list - - public: - static int numSimulatedCPUs() { return cpuList.size(); } - static Counter numSimulatedInstructions() - { - Counter total = 0; - - int size = cpuList.size(); - for (int i = 0; i < size; ++i) - total += cpuList[i]->totalInstructions(); - - return total; - } - - public: - // Number of CPU cycles simulated - Stats::Scalar<> numCycles; -}; - -#endif // __CPU_BASE_HH__ diff --git a/cpu/base_dyn_inst.cc b/cpu/base_dyn_inst.cc deleted file mode 100644 index 7ab760ae3..000000000 --- a/cpu/base_dyn_inst.cc +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <set> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" -#include "base/trace.hh" - -#include "arch/faults.hh" -#include "cpu/exetrace.hh" -#include "mem/mem_req.hh" - -#include "cpu/base_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/ozone/simple_impl.hh" -#include "cpu/ozone/ozone_impl.hh" - -using namespace std; -using namespace TheISA; - -#define NOHASH -#ifndef NOHASH - -#include "base/hashmap.hh" - -unsigned int MyHashFunc(const BaseDynInst *addr) -{ - unsigned a = (unsigned)addr; - unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; - - return hash; -} - -typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc> -my_hash_t; - -my_hash_t thishash; -#endif - -template <class Impl> -BaseDynInst<Impl>::BaseDynInst(ExtMachInst machInst, Addr inst_PC, - Addr pred_PC, InstSeqNum seq_num, - FullCPU *cpu) - : staticInst(machInst), traceData(NULL), cpu(cpu)/*, xc(cpu->xcBase())*/ -{ - seqNum = seq_num; - - PC = inst_PC; - nextPC = PC + sizeof(MachInst); - predPC = pred_PC; - - initVars(); -} - -template <class Impl> -BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst) - : staticInst(_staticInst), traceData(NULL) -{ - seqNum = 0; - initVars(); -} - -template <class Impl> -void -BaseDynInst<Impl>::initVars() -{ - req = NULL; - effAddr = MemReq::inval_addr; - physEffAddr = MemReq::inval_addr; - storeSize = 0; - - readyRegs = 0; - - completed = false; - resultReady = false; - canIssue = false; - issued = false; - executed = false; - canCommit = false; - committed = false; - squashed = false; - squashedInIQ = false; - squashedInLSQ = false; - squashedInROB = false; - eaCalcDone = false; - memOpDone = false; - lqIdx = -1; - sqIdx = -1; - reachedCommit = false; - - blockingInst = false; - recoverInst = false; - - iqEntry = false; - robEntry = false; - - serializeBefore = false; - serializeAfter = false; - serializeHandled = false; - - // Eventually make this a parameter. - threadNumber = 0; - - // Also make this a parameter, or perhaps get it from xc or cpu. - asid = 0; - - // Initialize the fault to be unimplemented opcode. -// fault = new UnimplementedOpcodeFault; - fault = NoFault; - - ++instcount; - - if (instcount > 1500) { - cpu->dumpInsts(); -#ifdef DEBUG - dumpSNList(); -#endif - assert(instcount <= 1500); - } - - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", - seqNum, instcount); - -#ifdef DEBUG - cpu->snList.insert(seqNum); -#endif -} - -template <class Impl> -BaseDynInst<Impl>::~BaseDynInst() -{ - if (req) { - req = NULL; - } - - if (traceData) { - delete traceData; - } - - --instcount; - - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", - seqNum, instcount); -#ifdef DEBUG - cpu->snList.erase(seqNum); -#endif -} - -#ifdef DEBUG -template <class Impl> -void -BaseDynInst<Impl>::dumpSNList() -{ - std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin(); - - int count = 0; - while (sn_it != cpu->snList.end()) { - cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it)); - count++; - sn_it++; - } -} -#endif - -template <class Impl> -void -BaseDynInst<Impl>::prefetch(Addr addr, unsigned flags) -{ - // This is the "functional" implementation of prefetch. Not much - // happens here since prefetches don't affect the architectural - // state. - - // Generate a MemReq so we can translate the effective address. - MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags); - req->asid = asid; - - // Prefetches never cause faults. - fault = NoFault; - - // note this is a local, not BaseDynInst::fault - Fault trans_fault = cpu->translateDataReadReq(req); - - if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) { - // It's a valid address to cacheable space. Record key MemReq - // parameters so we can generate another one just like it for - // the timing access without calling translate() again (which - // might mess up the TLB). - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - } else { - // Bogus address (invalid or uncacheable space). Mark it by - // setting the eff_addr to InvalidAddr. - effAddr = physEffAddr = MemReq::inval_addr; - } - - if (traceData) { - traceData->setAddr(addr); - } -} - -template <class Impl> -void -BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags) -{ - // Need to create a MemReq here so we can do a translation. This - // will casue a TLB miss trap if necessary... not sure whether - // that's the best thing to do or not. We don't really need the - // MemReq otherwise, since wh64 has no functional effect. - MemReqPtr req = new MemReq(addr, thread->getXCProxy(), size, flags); - req->asid = asid; - - fault = cpu->translateDataWriteReq(req); - - if (fault == NoFault && !(req->flags & UNCACHEABLE)) { - // Record key MemReq parameters so we can generate another one - // just like it for the timing access without calling translate() - // again (which might mess up the TLB). - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - } else { - // ignore faults & accesses to uncacheable space... treat as no-op - effAddr = physEffAddr = MemReq::inval_addr; - } - - storeSize = size; - storeData = 0; -} - -/** - * @todo Need to find a way to get the cache block size here. - */ -template <class Impl> -Fault -BaseDynInst<Impl>::copySrcTranslate(Addr src) -{ - MemReqPtr req = new MemReq(src, thread->getXCProxy(), 64); - req->asid = asid; - - // translate to physical address - Fault fault = cpu->translateDataReadReq(req); - - if (fault == NoFault) { - thread->copySrcAddr = src; - thread->copySrcPhysAddr = req->paddr; - } else { - thread->copySrcAddr = 0; - thread->copySrcPhysAddr = 0; - } - return fault; -} - -/** - * @todo Need to find a way to get the cache block size here. - */ -template <class Impl> -Fault -BaseDynInst<Impl>::copy(Addr dest) -{ - uint8_t data[64]; - FunctionalMemory *mem = thread->mem; - assert(thread->copySrcPhysAddr || thread->misspeculating()); - MemReqPtr req = new MemReq(dest, thread->getXCProxy(), 64); - req->asid = asid; - - // translate to physical address - Fault fault = cpu->translateDataWriteReq(req); - - if (fault == NoFault) { - Addr dest_addr = req->paddr; - // Need to read straight from memory since we have more than 8 bytes. - req->paddr = thread->copySrcPhysAddr; - mem->read(req, data); - req->paddr = dest_addr; - mem->write(req, data); - } - return fault; -} - -template <class Impl> -void -BaseDynInst<Impl>::dump() -{ - cprintf("T%d : %#08d `", threadNumber, PC); - cout << staticInst->disassemble(PC); - cprintf("'\n"); -} - -template <class Impl> -void -BaseDynInst<Impl>::dump(std::string &outstring) -{ - std::ostringstream s; - s << "T" << threadNumber << " : 0x" << PC << " " - << staticInst->disassemble(PC); - - outstring = s.str(); -} - -#if 0 -template <class Impl> -Fault -BaseDynInst<Impl>::mem_access(mem_cmd cmd, Addr addr, void *p, int nbytes) -{ - Fault fault; - - // check alignments, even speculative this test should always pass - if ((nbytes & nbytes - 1) != 0 || (addr & nbytes - 1) != 0) { - for (int i = 0; i < nbytes; i++) - ((char *) p)[i] = 0; - - // I added the following because according to the comment above, - // we should never get here. The comment lies -#if 0 - panic("unaligned access. Cycle = %n", curTick); -#endif - return NoFault; - } - - MemReqPtr req = new MemReq(addr, thread, nbytes); - switch(cmd) { - case Read: - fault = spec_mem->read(req, (uint8_t *)p); - break; - - case Write: - fault = spec_mem->write(req, (uint8_t *)p); - if (fault != NoFault) - break; - - specMemWrite = true; - storeSize = nbytes; - switch(nbytes) { - case sizeof(uint8_t): - *(uint8_t)&storeData = (uint8_t *)p; - break; - case sizeof(uint16_t): - *(uint16_t)&storeData = (uint16_t *)p; - break; - case sizeof(uint32_t): - *(uint32_t)&storeData = (uint32_t *)p; - break; - case sizeof(uint64_t): - *(uint64_t)&storeData = (uint64_t *)p; - break; - } - break; - - default: - fault = genMachineCheckFault(); - break; - } - - trace_mem(fault, cmd, addr, p, nbytes); - - return fault; -} - -#endif - -template <class Impl> -void -BaseDynInst<Impl>::markSrcRegReady() -{ - if (++readyRegs == numSrcRegs()) { - canIssue = true; - } -} - -template <class Impl> -void -BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx) -{ - ++readyRegs; - - _readySrcRegIdx[src_idx] = true; - - if (readyRegs == numSrcRegs()) { - canIssue = true; - } -} - -template <class Impl> -bool -BaseDynInst<Impl>::eaSrcsReady() -{ - // For now I am assuming that src registers 1..n-1 are the ones that the - // EA calc depends on. (i.e. src reg 0 is the source of the data to be - // stored) - - for (int i = 1; i < numSrcRegs(); ++i) { - if (!_readySrcRegIdx[i]) - return false; - } - - return true; -} - -// Forward declaration -template class BaseDynInst<AlphaSimpleImpl>; - -template <> -int -BaseDynInst<AlphaSimpleImpl>::instcount = 0; - -// Forward declaration -template class BaseDynInst<SimpleImpl>; - -template <> -int -BaseDynInst<SimpleImpl>::instcount = 0; - -// Forward declaration -template class BaseDynInst<OzoneImpl>; - -template <> -int -BaseDynInst<OzoneImpl>::instcount = 0; diff --git a/cpu/base_dyn_inst.hh b/cpu/base_dyn_inst.hh deleted file mode 100644 index 388ea4a8d..000000000 --- a/cpu/base_dyn_inst.hh +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_BASE_DYN_INST_HH__ -#define __CPU_BASE_DYN_INST_HH__ - -#include <list> -#include <string> - -#include "base/fast_alloc.hh" -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/exetrace.hh" -#include "cpu/inst_seq.hh" -#include "cpu/static_inst.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "mem/functional/memory_control.hh" -#include "sim/system.hh" -/* -#include "encumbered/cpu/full/bpred_update.hh" -#include "encumbered/cpu/full/spec_memory.hh" -#include "encumbered/cpu/full/spec_state.hh" -#include "encumbered/mem/functional/main.hh" -*/ - -/** - * @file - * Defines a dynamic instruction context. - */ - -// Forward declaration. -class StaticInstPtr; - -template <class Impl> -class BaseDynInst : public FastAlloc, public RefCounted -{ - public: - // Typedef for the CPU. - typedef typename Impl::FullCPU FullCPU; - typedef typename FullCPU::ImplState ImplState; - - // Binary machine instruction type. - typedef TheISA::MachInst MachInst; - // Extended machine instruction type - typedef TheISA::ExtMachInst ExtMachInst; - // Logical register index type. - typedef TheISA::RegIndex RegIndex; - // Integer register index type. - typedef TheISA::IntReg IntReg; - - // The DynInstPtr type. - typedef typename Impl::DynInstPtr DynInstPtr; - - // The list of instructions iterator type. - typedef typename std::list<DynInstPtr>::iterator ListIt; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs - }; - - /** The StaticInst used by this BaseDynInst. */ - StaticInstPtr staticInst; - - //////////////////////////////////////////// - // - // INSTRUCTION EXECUTION - // - //////////////////////////////////////////// - /** InstRecord that tracks this instructions. */ - Trace::InstRecord *traceData; - - /** - * Does a read to a given address. - * @param addr The address to read. - * @param data The read's data is written into this parameter. - * @param flags The request's flags. - * @return Returns any fault due to the read. - */ - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - /** - * Does a write to a given address. - * @param data The data to be written. - * @param addr The address to write to. - * @param flags The request's flags. - * @param res The result of the write (for load locked/store conditionals). - * @return Returns any fault due to the write. - */ - template <class T> - Fault write(T data, Addr addr, unsigned flags, - uint64_t *res); - - void prefetch(Addr addr, unsigned flags); - void writeHint(Addr addr, int size, unsigned flags); - Fault copySrcTranslate(Addr src); - Fault copy(Addr dest); - - /** @todo: Consider making this private. */ - public: - /** The sequence number of the instruction. */ - InstSeqNum seqNum; - - /** Is the instruction in the IQ */ - bool iqEntry; - - /** Is the instruction in the ROB */ - bool robEntry; - - /** Is the instruction in the LSQ */ - bool lsqEntry; - - /** Is the instruction completed. */ - bool completed; - - /** Is the instruction's result ready. */ - bool resultReady; - - /** Can this instruction issue. */ - bool canIssue; - - /** Has this instruction issued. */ - bool issued; - - /** Has this instruction executed (or made it through execute) yet. */ - bool executed; - - /** Can this instruction commit. */ - bool canCommit; - - /** Is this instruction committed. */ - bool committed; - - /** Is this instruction squashed. */ - bool squashed; - - /** Is this instruction squashed in the instruction queue. */ - bool squashedInIQ; - - /** Is this instruction squashed in the instruction queue. */ - bool squashedInLSQ; - - /** Is this instruction squashed in the instruction queue. */ - bool squashedInROB; - - /** Is this a recover instruction. */ - bool recoverInst; - - /** Is this a thread blocking instruction. */ - bool blockingInst; /* this inst has called thread_block() */ - - /** Is this a thread syncrhonization instruction. */ - bool threadsyncWait; - - /** The thread this instruction is from. */ - short threadNumber; - - /** data address space ID, for loads & stores. */ - short asid; - - /** How many source registers are ready. */ - unsigned readyRegs; - - /** Pointer to the FullCPU object. */ - FullCPU *cpu; - - /** Pointer to the exec context. */ - ImplState *thread; - - /** The kind of fault this instruction has generated. */ - Fault fault; - - /** The memory request. */ - MemReqPtr req; - - /** The effective virtual address (lds & stores only). */ - Addr effAddr; - - /** The effective physical address. */ - Addr physEffAddr; - - /** Effective virtual address for a copy source. */ - Addr copySrcEffAddr; - - /** Effective physical address for a copy source. */ - Addr copySrcPhysEffAddr; - - /** The memory request flags (from translation). */ - unsigned memReqFlags; - - /** The size of the data to be stored. */ - int storeSize; - - /** The data to be stored. */ - IntReg storeData; - - union Result { - uint64_t integer; - float fp; - double dbl; - }; - - /** The result of the instruction; assumes for now that there's only one - * destination register. - */ - Result instResult; - - /** PC of this instruction. */ - Addr PC; - - /** Next non-speculative PC. It is not filled in at fetch, but rather - * once the target of the branch is truly known (either decode or - * execute). - */ - Addr nextPC; - - /** Predicted next PC. */ - Addr predPC; - - /** Count of total number of dynamic instructions. */ - static int instcount; - -#ifdef DEBUG - void dumpSNList(); -#endif - - /** Whether or not the source register is ready. - * @todo: Not sure this should be here vs the derived class. - */ - bool _readySrcRegIdx[MaxInstSrcRegs]; - - public: - /** BaseDynInst constructor given a binary instruction. - * @param inst The binary instruction. - * @param PC The PC of the instruction. - * @param pred_PC The predicted next PC. - * @param seq_num The sequence number of the instruction. - * @param cpu Pointer to the instruction's CPU. - */ - BaseDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, - FullCPU *cpu); - - /** BaseDynInst constructor given a StaticInst pointer. - * @param _staticInst The StaticInst for this BaseDynInst. - */ - BaseDynInst(StaticInstPtr &_staticInst); - - /** BaseDynInst destructor. */ - ~BaseDynInst(); - - private: - /** Function to initialize variables in the constructors. */ - void initVars(); - - public: - /** - * @todo: Make this function work; currently it is a dummy function. - * @param fault Last fault. - * @param cmd Last command. - * @param addr Virtual address of access. - * @param p Memory accessed. - * @param nbytes Access size. - */ - void - trace_mem(Fault fault, - MemCmd cmd, - Addr addr, - void *p, - int nbytes); - - /** Dumps out contents of this BaseDynInst. */ - void dump(); - - /** Dumps out contents of this BaseDynInst into given string. */ - void dump(std::string &outstring); - - /** Returns the fault type. */ - Fault getFault() { return fault; } - - /** Checks whether or not this instruction has had its branch target - * calculated yet. For now it is not utilized and is hacked to be - * always false. - * @todo: Actually use this instruction. - */ - bool doneTargCalc() { return false; } - - /** Returns the next PC. This could be the speculative next PC if it is - * called prior to the actual branch target being calculated. - */ - Addr readNextPC() { return nextPC; } - - /** Set the predicted target of this current instruction. */ - void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; } - - /** Returns the predicted target of the branch. */ - Addr readPredTarg() { return predPC; } - - /** Returns whether the instruction was predicted taken or not. */ - bool predTaken() { return predPC != (PC + sizeof(MachInst)); } - - /** Returns whether the instruction mispredicted. */ - bool mispredicted() { return predPC != nextPC; } - - // - // Instruction types. Forward checks to StaticInst object. - // - bool isNop() const { return staticInst->isNop(); } - bool isMemRef() const { return staticInst->isMemRef(); } - bool isLoad() const { return staticInst->isLoad(); } - bool isStore() const { return staticInst->isStore(); } - bool isStoreConditional() const - { return staticInst->isStoreConditional(); } - bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } - bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } - bool isCopy() const { return staticInst->isCopy(); } - bool isInteger() const { return staticInst->isInteger(); } - bool isFloating() const { return staticInst->isFloating(); } - bool isControl() const { return staticInst->isControl(); } - bool isCall() const { return staticInst->isCall(); } - bool isReturn() const { return staticInst->isReturn(); } - bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } - bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } - bool isCondCtrl() const { return staticInst->isCondCtrl(); } - bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } - bool isThreadSync() const { return staticInst->isThreadSync(); } - bool isSerializing() const { return staticInst->isSerializing(); } - bool isSerializeBefore() const - { return staticInst->isSerializeBefore() || serializeBefore; } - bool isSerializeAfter() const - { return staticInst->isSerializeAfter() || serializeAfter; } - bool isMemBarrier() const { return staticInst->isMemBarrier(); } - bool isWriteBarrier() const { return staticInst->isWriteBarrier(); } - bool isNonSpeculative() const { return staticInst->isNonSpeculative(); } - bool isQuiesce() const { return staticInst->isQuiesce(); } - bool isIprAccess() const { return staticInst->isIprAccess(); } - bool isUnverifiable() const { return staticInst->isUnverifiable(); } - - /** Temporarily sets this instruction as a serialize before instruction. */ - void setSerializeBefore() { serializeBefore = true; } - - /** Clears the serializeBefore part of this instruction. */ - void clearSerializeBefore() { serializeBefore = false; } - - /** Checks if this serializeBefore is only temporarily set. */ - bool isTempSerializeBefore() { return serializeBefore; } - - /** Tracks if instruction has been externally set as serializeBefore. */ - bool serializeBefore; - - /** Temporarily sets this instruction as a serialize after instruction. */ - void setSerializeAfter() { serializeAfter = true; } - - /** Clears the serializeAfter part of this instruction.*/ - void clearSerializeAfter() { serializeAfter = false; } - - /** Checks if this serializeAfter is only temporarily set. */ - bool isTempSerializeAfter() { return serializeAfter; } - - /** Tracks if instruction has been externally set as serializeAfter. */ - bool serializeAfter; - - /** Checks if the serialization part of this instruction has been - * handled. This does not apply to the temporary serializing - * state; it only applies to this instruction's own permanent - * serializing state. - */ - bool isSerializeHandled() { return serializeHandled; } - - /** Sets the serialization part of this instruction as handled. */ - void setSerializeHandled() { serializeHandled = true; } - - /** Whether or not the serialization of this instruction has been handled. */ - bool serializeHandled; - - /** Returns the opclass of this instruction. */ - OpClass opClass() const { return staticInst->opClass(); } - - /** Returns the branch target address. */ - Addr branchTarget() const { return staticInst->branchTarget(PC); } - - /** Returns the number of source registers. */ - int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } - - /** Returns the number of destination registers. */ - int8_t numDestRegs() const { return staticInst->numDestRegs(); } - - // the following are used to track physical register usage - // for machines with separate int & FP reg files - int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); } - int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); } - - /** Returns the logical register index of the i'th destination register. */ - RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); } - - /** Returns the logical register index of the i'th source register. */ - RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } - - /** Returns the result of an integer instruction. */ - uint64_t readIntResult() { return instResult.integer; } - - /** Returns the result of a floating point instruction. */ - float readFloatResult() { return instResult.fp; } - - /** Returns the result of a floating point (double) instruction. */ - double readDoubleResult() { return instResult.dbl; } - - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - instResult.integer = val; - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - instResult.fp = val; - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - instResult.dbl = val; - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - instResult.integer = val; - } - - /** Records that one of the source registers is ready. */ - void markSrcRegReady(); - - /** Marks a specific register as ready. */ - void markSrcRegReady(RegIndex src_idx); - - /** Returns if a source register is ready. */ - bool isReadySrcRegIdx(int idx) const - { - return this->_readySrcRegIdx[idx]; - } - - /** Sets this instruction as completed. */ - void setCompleted() { completed = true; } - - /** Returns whether or not this instruction is completed. */ - bool isCompleted() const { return completed; } - - void setResultReady() { resultReady = true; } - - bool isResultReady() const { return resultReady; } - - /** Sets this instruction as ready to issue. */ - void setCanIssue() { canIssue = true; } - - /** Returns whether or not this instruction is ready to issue. */ - bool readyToIssue() const { return canIssue; } - - /** Sets this instruction as issued from the IQ. */ - void setIssued() { issued = true; } - - /** Returns whether or not this instruction has issued. */ - bool isIssued() const { return issued; } - - /** Sets this instruction as executed. */ - void setExecuted() { executed = true; } - - /** Returns whether or not this instruction has executed. */ - bool isExecuted() const { return executed; } - - /** Sets this instruction as ready to commit. */ - void setCanCommit() { canCommit = true; } - - /** Clears this instruction as being ready to commit. */ - void clearCanCommit() { canCommit = false; } - - /** Returns whether or not this instruction is ready to commit. */ - bool readyToCommit() const { return canCommit; } - - /** Sets this instruction as committed. */ - void setCommitted() { committed = true; } - - /** Returns whether or not this instruction is committed. */ - bool isCommitted() const { return committed; } - - /** Sets this instruction as squashed. */ - void setSquashed() { squashed = true; } - - /** Returns whether or not this instruction is squashed. */ - bool isSquashed() const { return squashed; } - - //Instruction Queue Entry - //----------------------- - /** Sets this instruction as a entry the IQ. */ - void setInIQ() { iqEntry = true; } - - /** Sets this instruction as a entry the IQ. */ - void removeInIQ() { iqEntry = false; } - - /** Sets this instruction as squashed in the IQ. */ - void setSquashedInIQ() { squashedInIQ = true; squashed = true;} - - /** Returns whether or not this instruction is squashed in the IQ. */ - bool isSquashedInIQ() const { return squashedInIQ; } - - /** Returns whether or not this instruction has issued. */ - bool isInIQ() const { return iqEntry; } - - - //Load / Store Queue Functions - //----------------------- - /** Sets this instruction as a entry the LSQ. */ - void setInLSQ() { lsqEntry = true; } - - /** Sets this instruction as a entry the LSQ. */ - void removeInLSQ() { lsqEntry = false; } - - /** Sets this instruction as squashed in the LSQ. */ - void setSquashedInLSQ() { squashedInLSQ = true;} - - /** Returns whether or not this instruction is squashed in the LSQ. */ - bool isSquashedInLSQ() const { return squashedInLSQ; } - - /** Returns whether or not this instruction is in the LSQ. */ - bool isInLSQ() const { return lsqEntry; } - - - //Reorder Buffer Functions - //----------------------- - /** Sets this instruction as a entry the ROB. */ - void setInROB() { robEntry = true; } - - /** Sets this instruction as a entry the ROB. */ - void removeInROB() { robEntry = false; } - - /** Sets this instruction as squashed in the ROB. */ - void setSquashedInROB() { squashedInROB = true; } - - /** Returns whether or not this instruction is squashed in the ROB. */ - bool isSquashedInROB() const { return squashedInROB; } - - /** Returns whether or not this instruction is in the ROB. */ - bool isInROB() const { return robEntry; } - - /** Read the PC of this instruction. */ - const Addr readPC() const { return PC; } - - /** Set the next PC of this instruction (its actual target). */ - void setNextPC(uint64_t val) - { - nextPC = val; -// instResult.integer = val; - } - - void setASID(short addr_space_id) { asid = addr_space_id; } - - void setThread(unsigned tid) { threadNumber = tid; } - - void setState(ImplState *state) { thread = state; } - - /** Returns the exec context. - * @todo: Remove this once the ExecContext is no longer used. - */ - ExecContext *xcBase() { return thread->getXCProxy(); } - - private: - /** Instruction effective address. - * @todo: Consider if this is necessary or not. - */ - Addr instEffAddr; - - /** Whether or not the effective address calculation is completed. - * @todo: Consider if this is necessary or not. - */ - bool eaCalcDone; - - public: - /** Sets the effective address. */ - void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; } - - /** Returns the effective address. */ - const Addr &getEA() const { return req->vaddr; } - - /** Returns whether or not the eff. addr. calculation has been completed. */ - bool doneEACalc() { return eaCalcDone; } - - /** Returns whether or not the eff. addr. source registers are ready. */ - bool eaSrcsReady(); - - /** Whether or not the memory operation is done. */ - bool memOpDone; - - public: - /** Load queue index. */ - int16_t lqIdx; - - /** Store queue index. */ - int16_t sqIdx; - - bool reachedCommit; - - /** Iterator pointing to this BaseDynInst in the list of all insts. */ - ListIt instListIt; - - /** Returns iterator to this instruction in the list of all insts. */ - ListIt &getInstListIt() { return instListIt; } - - /** Sets iterator for this instruction in the list of all insts. */ - void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; } -}; - -template<class Impl> -template<class T> -inline Fault -BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) -{ - if (executed) { - fault = cpu->read(req, data, lqIdx); - return fault; - } - - req = new MemReq(addr, thread->getXCProxy(), sizeof(T), flags); - req->asid = asid; - req->thread_num = threadNumber; - req->pc = this->PC; - - if ((req->vaddr & (TheISA::VMPageSize - 1)) + req->size > - TheISA::VMPageSize) { - return TheISA::genAlignmentFault(); - } - - fault = cpu->translateDataReadReq(req); - - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - - if (fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(physEffAddr)) { - fault = TheISA::genMachineCheckFault(); - data = (T)-1; - this->setExecuted(); - } else { - fault = cpu->read(req, data, lqIdx); - } -#else - fault = cpu->read(req, data, lqIdx); -#endif - } else { - // Return a fixed value to keep simulation deterministic even - // along misspeculated paths. - data = (T)-1; - - // Commit will have to clean up whatever happened. Set this - // instruction as executed. - this->setExecuted(); - } - - if (traceData) { - traceData->setAddr(addr); - traceData->setData(data); - } - - return fault; -} - -template<class Impl> -template<class T> -inline Fault -BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - if (traceData) { - traceData->setAddr(addr); - traceData->setData(data); - } - - req = new MemReq(addr, thread->getXCProxy(), sizeof(T), flags); - - req->asid = asid; - req->thread_num = threadNumber; - req->pc = this->PC; - - if ((req->vaddr & (TheISA::VMPageSize - 1)) + req->size > - TheISA::VMPageSize) { - return TheISA::genAlignmentFault(); - } - - fault = cpu->translateDataWriteReq(req); - - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - - if (fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(physEffAddr)) { - fault = TheISA::genMachineCheckFault(); - } else { - fault = cpu->write(req, data, sqIdx); - } -#else - fault = cpu->write(req, data, sqIdx); -#endif - } - - if (res) { - // always return some result to keep misspeculated paths - // (which will ignore faults) deterministic - *res = (fault == NoFault) ? req->result : 0; - } - - return fault; -} - -#endif // __CPU_BASE_DYN_INST_HH__ diff --git a/cpu/cpu_exec_context.cc b/cpu/cpu_exec_context.cc deleted file mode 100644 index e30295ef8..000000000 --- a/cpu/cpu_exec_context.cc +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2001-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" - -#if FULL_SYSTEM -#include "base/callback.hh" -#include "base/cprintf.hh" -#include "base/output.hh" -#include "base/trace.hh" -#include "cpu/profile.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#include "sim/serialize.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#include "arch/stacktrace.hh" -#else -#include "sim/process.hh" -#endif - -using namespace std; - -// constructor -#if FULL_SYSTEM -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, - AlphaITB *_itb, AlphaDTB *_dtb, - FunctionalMemory *_mem, - bool use_kernel_stats) - : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), - cpu_id(-1), lastActivate(0), lastSuspend(0), mem(_mem), itb(_itb), - dtb(_dtb), system(_sys), memctrl(_sys->memctrl), physmem(_sys->physmem), - profile(NULL), func_exe_inst(0), storeCondFailures(0) -{ - proxy = new ProxyExecContext<CPUExecContext>(this); - - quiesceEvent = new EndQuiesceEvent(proxy); - - memset(®s, 0, sizeof(RegFile)); - - if (cpu->params->profile) { - profile = new FunctionProfile(system->kernelSymtab); - Callback *cb = - new MakeCallback<CPUExecContext, - &CPUExecContext::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; - - if (use_kernel_stats) { - kernelStats = new Kernel::Statistics(system); - } else { - kernelStats = NULL; - } -} -#else -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - Process *_process, int _asid) - : _status(ExecContext::Unallocated), - cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0), - lastSuspend(0), process(_process), mem(process->getMemory()), asid(_asid), - func_exe_inst(0), storeCondFailures(0) -{ - memset(®s, 0, sizeof(RegFile)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(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)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(RegFile *regFile) - : cpu(NULL), thread_num(-1), process(NULL), mem(NULL), asid(-1), - func_exe_inst(0), storeCondFailures(0) -{ - regs = *regFile; - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -#endif - -CPUExecContext::~CPUExecContext() -{ - delete proxy; -} - -#if FULL_SYSTEM -void -CPUExecContext::dumpFuncProfile() -{ - std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name())); - profile->dump(proxy, *os); -} - -void -CPUExecContext::profileClear() -{ - if (profile) - profile->clear(); -} - -void -CPUExecContext::profileSample() -{ - if (profile) - profile->sample(profileNode, profilePC); -} - -#endif - -void -CPUExecContext::takeOverFrom(ExecContext *oldContext) -{ - // some things should already be set up - assert(mem == oldContext->getMemPtr()); -#if FULL_SYSTEM - assert(system == oldContext->getSystemPtr()); -#else - assert(process == oldContext->getProcessPtr()); -#endif - - // copy over functional state - _status = oldContext->status(); - copyArchRegs(oldContext); - cpu_id = oldContext->readCpuId(); -#if !FULL_SYSTEM - func_exe_inst = oldContext->readFuncExeInst(); -#else - EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent(); - if (quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - quiesce->xc = proxy; - } - if (quiesceEvent) { - quiesceEvent->xc = proxy; - } -#endif - - storeCondFailures = 0; - - oldContext->setStatus(ExecContext::Unallocated); -} - -void -CPUExecContext::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 - Tick quiesceEndTick = 0; - if (quiesceEvent->scheduled()) - quiesceEndTick = quiesceEvent->when(); - SERIALIZE_SCALAR(quiesceEndTick); - if (kernelStats) - kernelStats->serialize(os); -#endif -} - - -void -CPUExecContext::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 - Tick quiesceEndTick; - UNSERIALIZE_SCALAR(quiesceEndTick); - if (quiesceEndTick) - quiesceEvent->schedule(quiesceEndTick); - if (kernelStats) - kernelStats->unserialize(cp, section); -#endif -} - - -void -CPUExecContext::activate(int delay) -{ - if (status() == ExecContext::Active) - return; - - lastActivate = curTick; - - if (status() == ExecContext::Unallocated) { - cpu->activateWhenReady(thread_num); - return; - } - - _status = ExecContext::Active; - - // status() == Suspended - cpu->activateContext(thread_num, delay); -} - -void -CPUExecContext::suspend() -{ - if (status() == ExecContext::Suspended) - return; - - lastActivate = curTick; - lastSuspend = curTick; -/* -#if FULL_SYSTEM - // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { - assert(status() == ExecContext::Active); - return; - } -#endif -*/ - _status = ExecContext::Suspended; - cpu->suspendContext(thread_num); -} - -void -CPUExecContext::deallocate() -{ - if (status() == ExecContext::Unallocated) - return; - - _status = ExecContext::Unallocated; - cpu->deallocateContext(thread_num); -} - -void -CPUExecContext::halt() -{ - if (status() == ExecContext::Halted) - return; - - _status = ExecContext::Halted; - cpu->haltContext(thread_num); -} - - -void -CPUExecContext::regStats(const string &name) -{ -#if FULL_SYSTEM - if (kernelStats) - kernelStats->regStats(name + ".kern"); -#endif -} - -void -CPUExecContext::copyArchRegs(ExecContext *xc) -{ - // First loop through the integer registers. - for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { - setIntReg(i, xc->readIntReg(i)); - } - - // Then loop through the floating point registers. - for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { - setFloatRegDouble(i, xc->readFloatRegDouble(i)); - setFloatRegInt(i, xc->readFloatRegInt(i)); - } - - // Copy misc. registers - regs.miscRegs.copyMiscRegs(xc); - - // Lastly copy PC/NPC - setPC(xc->readPC()); - setNextPC(xc->readNextPC()); -} - diff --git a/cpu/cpu_exec_context.hh b/cpu/cpu_exec_context.hh deleted file mode 100644 index 061fe450a..000000000 --- a/cpu/cpu_exec_context.hh +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright (c) 2001-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_CPU_EXEC_CONTEXT_HH__ -#define __CPU_CPU_EXEC_CONTEXT_HH__ - -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_req.hh" -#include "sim/byteswap.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" - -// forward declaration: see functional_memory.hh -class FunctionalMemory; -class PhysicalMemory; -class BaseCPU; - -#if FULL_SYSTEM - -#include "sim/system.hh" -#include "arch/tlb.hh" - -class FunctionProfile; -class ProfileNode; -class MemoryController; - -namespace Kernel { - class Statistics; -}; - -#else // !FULL_SYSTEM - -#include "sim/process.hh" - -#endif // FULL_SYSTEM - -// -// The CPUExecContext object represents a functional context for -// instruction execution. It incorporates everything required for -// architecture-level functional simulation of a single thread. -// - -class CPUExecContext -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - public: - typedef ExecContext::Status Status; - - private: - Status _status; - - public: - Status status() const { return _status; } - - void setStatus(Status newStatus) { _status = newStatus; } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1); - - /// Set the status to Suspended. - void suspend(); - - /// Set the status to Unallocated. - void deallocate(); - - /// Set the status to Halted. - void halt(); - - protected: - RegFile regs; // correct-path register context - - public: - // pointer to CPU associated with this context - BaseCPU *cpu; - - ProxyExecContext<CPUExecContext> *proxy; - - // Current instruction - MachInst inst; - - // 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; - - Tick lastActivate; - Tick lastSuspend; - -#if FULL_SYSTEM - FunctionalMemory *mem; - AlphaITB *itb; - AlphaDTB *dtb; - System *system; - - // the following two fields are redundant, since we can always - // look them up through the system pointer, but we'll leave them - // here for now for convenience - MemoryController *memctrl; - PhysicalMemory *physmem; - - FunctionProfile *profile; - ProfileNode *profileNode; - Addr profilePC; - void dumpFuncProfile(); - - EndQuiesceEvent *quiesceEvent; - - EndQuiesceEvent *getQuiesceEvent() { return quiesceEvent; } - - Tick readLastActivate() { return lastActivate; } - - Tick readLastSuspend() { return lastSuspend; } - - void profileClear(); - - void profileSample(); - - Kernel::Statistics *getKernelStats() { return kernelStats; } - - Kernel::Statistics *kernelStats; -#else - Process *process; - - FunctionalMemory *mem; // functional storage for process address space - - // Address space ID. Note that this is used for TIMING cache - // simulation only; all functional memory accesses should use - // one of the FunctionalMemory pointers above. - short asid; - -#endif - - /** - * Temporary storage to pass the source address from copy_load to - * copy_store. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcAddr; - /** - * Temp storage for the physical source address of a copy. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcPhysAddr; - - - /* - * number of executed instructions, for matching with syscall trace - * points in EIO files. - */ - Counter func_exe_inst; - - // - // Count failed store conditionals so we can warn of apparent - // application deadlock situations. - unsigned storeCondFailures; - - // constructor: initialize context from given process structure -#if FULL_SYSTEM - CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system, - AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_mem, - bool use_kernel_stats = true); -#else - CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); - CPUExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, - int _asid); - // Constructor to use XC to pass reg file around. Not used for anything - // else. - CPUExecContext(RegFile *regFile); -#endif - virtual ~CPUExecContext(); - - virtual void takeOverFrom(ExecContext *oldContext); - - void regStats(const std::string &name); - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - BaseCPU *getCpuPtr() { return cpu; } - - ExecContext *getProxy() { return proxy; } - - int getThreadNum() { return thread_num; } - -#if FULL_SYSTEM - System *getSystemPtr() { return system; } - - PhysicalMemory *getPhysMemPtr() { return physmem; } - - AlphaITB *getITBPtr() { return itb; } - - AlphaDTB *getDTBPtr() { return dtb; } - - bool validInstAddr(Addr addr) { return true; } - bool validDataAddr(Addr addr) { return true; } - int getInstAsid() { return regs.instAsid(); } - int getDataAsid() { return regs.dataAsid(); } - - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - Process *getProcessPtr() { return process; } - - bool validInstAddr(Addr addr) - { return process->validInstAddr(addr); } - - bool validDataAddr(Addr addr) - { return process->validDataAddr(addr); } - - int getInstAsid() { return asid; } - int getDataAsid() { return asid; } - - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - -#endif - - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif - - Fault error; - error = mem->read(req, data); - data = LittleEndianGuest::gtoh(data); - return error; - } - - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < system->execContexts.size(); i++){ - xc = system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif - return mem->write(req, (T)LittleEndianGuest::htog(data)); - } - - virtual bool misspeculating(); - - - MachInst getInst() { return inst; } - - void setInst(MachInst new_inst) - { - inst = new_inst; - } - - Fault instRead(MemReqPtr &req) - { - return mem->read(req, inst); - } - - void setCpuId(int id) { cpu_id = id; } - - int readCpuId() { return cpu_id; } - - FunctionalMemory *getMemPtr() { return mem; } - - void copyArchRegs(ExecContext *xc); - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { - return regs.intRegFile[reg_idx]; - } - - float readFloatRegSingle(int reg_idx) - { - return (float)regs.floatRegFile.d[reg_idx]; - } - - double readFloatRegDouble(int reg_idx) - { - return regs.floatRegFile.d[reg_idx]; - } - - uint64_t readFloatRegInt(int reg_idx) - { - return regs.floatRegFile.q[reg_idx]; - } - - void setIntReg(int reg_idx, uint64_t val) - { - regs.intRegFile[reg_idx] = val; - } - - void setFloatRegSingle(int reg_idx, float val) - { - regs.floatRegFile.d[reg_idx] = (double)val; - } - - void setFloatRegDouble(int reg_idx, double val) - { - regs.floatRegFile.d[reg_idx] = val; - } - - void setFloatRegInt(int reg_idx, uint64_t val) - { - regs.floatRegFile.q[reg_idx] = val; - } - - uint64_t readPC() - { - return regs.pc; - } - - void setPC(uint64_t val) - { - regs.pc = val; - } - - uint64_t readNextPC() - { - return regs.npc; - } - - void setNextPC(uint64_t val) - { - regs.npc = val; - } - - uint64_t readNextNPC() - { - return regs.nnpc; - } - - void setNextNPC(uint64_t val) - { - regs.nnpc = val; - } - - - MiscReg readMiscReg(int misc_reg) - { - return regs.miscRegs.readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return regs.miscRegs.readRegWithEffect(misc_reg, fault, proxy); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setRegWithEffect(misc_reg, val, proxy); - } - - unsigned readStCondFailures() { return storeCondFailures; } - - void setStCondFailures(unsigned sc_failures) - { storeCondFailures = sc_failures; } - - void clearArchRegs() { memset(®s, 0, sizeof(regs)); } - -#if FULL_SYSTEM - int readIntrFlag() { return regs.intrflag; } - void setIntrFlag(int val) { regs.intrflag = val; } - Fault hwrei(); - bool inPalMode() { return AlphaISA::PcPAL(regs.pc); } - bool simPalCheck(int palFunc); -#endif - -#if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - return regs.intRegFile[TheISA::ArgumentReg0 + i]; - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - regs.intRegFile[TheISA::ArgumentReg0 + i] = val; - } - - void setSyscallReturn(SyscallReturn return_value) - { - TheISA::setSyscallReturn(return_value, ®s); - } - - void syscall() - { - process->syscall(proxy); - } - - Counter readFuncExeInst() { return func_exe_inst; } - - void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; } -#endif -}; - - -// for non-speculative execution context, spec_mode is always false -inline bool -CPUExecContext::misspeculating() -{ - return false; -} - -#endif // __CPU_CPU_EXEC_CONTEXT_HH__ diff --git a/cpu/cpu_models.py b/cpu/cpu_models.py deleted file mode 100644 index 2b1ae6277..000000000 --- a/cpu/cpu_models.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2003-2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -################ -# CpuModel class -# -# The CpuModel class encapsulates everything the ISA parser needs to -# know about a particular CPU model. - -class CpuModel: - # Dict of available CPU model objects. Accessible as CpuModel.dict. - dict = {} - - # Constructor. Automatically adds models to CpuModel.dict. - def __init__(self, name, filename, includes, strings): - self.name = name - self.filename = filename # filename for output exec code - self.includes = includes # include files needed in exec file - # The 'strings' dict holds all the per-CPU symbols we can - # substitute into templates etc. - self.strings = strings - # Add self to dict - CpuModel.dict[name] = self - - -# -# Define CPU models. -# -# Parameters are: -# - name of model -# - filename for generated ISA execution file -# - includes needed for generated ISA execution file -# - substitution strings for ISA description templates -# - -CpuModel('SimpleCPU', 'simple_cpu_exec.cc', - '#include "cpu/simple/cpu.hh"', - { 'CPU_exec_context': 'SimpleCPU' }) -CpuModel('FastCPU', 'fast_cpu_exec.cc', - '#include "cpu/fast/cpu.hh"', - { 'CPU_exec_context': 'FastCPU' }) -CpuModel('FullCPU', 'full_cpu_exec.cc', - '#include "encumbered/cpu/full/dyn_inst.hh"', - { 'CPU_exec_context': 'DynInst' }) -CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc', - '#include "cpu/o3/alpha_dyn_inst.hh"', - { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' }) -CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc', - '#include "cpu/ozone/dyn_inst.hh"', - { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' }) -CpuModel('OzoneCPU', 'ozone_exec.cc', - '#include "cpu/ozone/dyn_inst.hh"', - { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' }) -CpuModel('CheckerCPU', 'checker_cpu_exec.cc', - '#include "cpu/checker/cpu.hh"', - { 'CPU_exec_context': 'CheckerCPU' }) - diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh deleted file mode 100644 index e1f1016e5..000000000 --- a/cpu/exec_context.hh +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_EXEC_CONTEXT_HH__ -#define __CPU_EXEC_CONTEXT_HH__ - -#include "config/full_system.hh" -#include "mem/mem_req.hh" -#include "sim/faults.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" -#include "sim/byteswap.hh" - -// forward declaration: see functional_memory.hh -// @todo: Figure out a more architecture independent way to obtain the ITB and -// DTB pointers. -class AlphaDTB; -class AlphaITB; -class BaseCPU; -class EndQuiesceEvent; -class Event; -class FunctionalMemory; -class PhysicalMemory; -class Process; -class System; -namespace Kernel { - class Statistics; -}; - -class ExecContext -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - typedef TheISA::IntReg IntReg; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - public: - enum Status - { - /// Initialized but not running yet. All CPUs start in - /// this state, but most transition to Active on cycle 1. - /// In MP or SMT systems, non-primary contexts will stay - /// in this state until a thread is assigned to them. - Unallocated, - - /// Running. Instructions should be executed only when - /// the context is in this state. - Active, - - /// Temporarily inactive. Entered while waiting for - /// synchronization, etc. - Suspended, - - /// Permanently shut down. Entered when target executes - /// m5exit pseudo-instruction. When all contexts enter - /// this state, the simulation will terminate. - Halted - }; - - virtual ~ExecContext() { }; - - virtual BaseCPU *getCpuPtr() = 0; - - virtual void setCpuId(int id) = 0; - - virtual int readCpuId() = 0; - - virtual FunctionalMemory *getMemPtr() = 0; - -#if FULL_SYSTEM - virtual System *getSystemPtr() = 0; - - virtual PhysicalMemory *getPhysMemPtr() = 0; - - virtual AlphaITB *getITBPtr() = 0; - - virtual AlphaDTB * getDTBPtr() = 0; - - virtual Kernel::Statistics *getKernelStats() = 0; -#else - virtual Process *getProcessPtr() = 0; -#endif - - virtual Status status() const = 0; - - virtual void setStatus(Status new_status) = 0; - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - virtual void activate(int delay = 1) = 0; - - /// Set the status to Suspended. - virtual void suspend() = 0; - - /// Set the status to Unallocated. - virtual void deallocate() = 0; - - /// Set the status to Halted. - virtual void halt() = 0; - -#if FULL_SYSTEM - virtual void dumpFuncProfile() = 0; -#endif - - virtual void takeOverFrom(ExecContext *old_context) = 0; - - virtual void regStats(const std::string &name) = 0; - - virtual void serialize(std::ostream &os) = 0; - virtual void unserialize(Checkpoint *cp, const std::string §ion) = 0; - -#if FULL_SYSTEM - virtual EndQuiesceEvent *getQuiesceEvent() = 0; - - // Not necessarily the best location for these... - // Having an extra function just to read these is obnoxious - virtual Tick readLastActivate() = 0; - virtual Tick readLastSuspend() = 0; - - virtual void profileClear() = 0; - virtual void profileSample() = 0; -#endif - - virtual int getThreadNum() = 0; - - // Also somewhat obnoxious. Really only used for the TLB fault. - // However, may be quite useful in SPARC. - virtual TheISA::MachInst getInst() = 0; - - virtual void copyArchRegs(ExecContext *xc) = 0; - - virtual void clearArchRegs() = 0; - - // - // New accessors for new decoder. - // - virtual uint64_t readIntReg(int reg_idx) = 0; - - virtual float readFloatRegSingle(int reg_idx) = 0; - - virtual double readFloatRegDouble(int reg_idx) = 0; - - virtual uint64_t readFloatRegInt(int reg_idx) = 0; - - virtual void setIntReg(int reg_idx, uint64_t val) = 0; - - virtual void setFloatRegSingle(int reg_idx, float val) = 0; - - virtual void setFloatRegDouble(int reg_idx, double val) = 0; - - virtual void setFloatRegInt(int reg_idx, uint64_t val) = 0; - - virtual uint64_t readPC() = 0; - - virtual void setPC(uint64_t val) = 0; - - virtual uint64_t readNextPC() = 0; - - virtual void setNextPC(uint64_t val) = 0; - - virtual MiscReg readMiscReg(int misc_reg) = 0; - - virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0; - - virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0; - - virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0; - - // Also not necessarily the best location for these two. Hopefully will go - // away once we decide upon where st cond failures goes. - virtual unsigned readStCondFailures() = 0; - - virtual void setStCondFailures(unsigned sc_failures) = 0; - -#if FULL_SYSTEM - virtual bool inPalMode() = 0; -#endif - - // Only really makes sense for old CPU model. Still could be useful though. - virtual bool misspeculating() = 0; - -#if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i) = 0; - - // used to shift args for indirect syscall - virtual void setSyscallArg(int i, IntReg val) = 0; - - virtual void setSyscallReturn(SyscallReturn return_value) = 0; - -// virtual void syscall() = 0; - - // Same with st cond failures. - virtual Counter readFuncExeInst() = 0; -#endif -}; - -template <class XC> -class ProxyExecContext : public ExecContext -{ - public: - ProxyExecContext(XC *actual_xc) - { actualXC = actual_xc; } - - private: - XC *actualXC; - - public: - - BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); } - - void setCpuId(int id) { actualXC->setCpuId(id); } - - int readCpuId() { return actualXC->readCpuId(); } - - FunctionalMemory *getMemPtr() { return actualXC->getMemPtr(); } - -#if FULL_SYSTEM - System *getSystemPtr() { return actualXC->getSystemPtr(); } - - PhysicalMemory *getPhysMemPtr() { return actualXC->getPhysMemPtr(); } - - AlphaITB *getITBPtr() { return actualXC->getITBPtr(); } - - AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); } - - Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); } -#else - Process *getProcessPtr() { return actualXC->getProcessPtr(); } -#endif - - Status status() const { return actualXC->status(); } - - void setStatus(Status new_status) { actualXC->setStatus(new_status); } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1) { actualXC->activate(delay); } - - /// Set the status to Suspended. - void suspend() { actualXC->suspend(); } - - /// Set the status to Unallocated. - void deallocate() { actualXC->deallocate(); } - - /// Set the status to Halted. - void halt() { actualXC->halt(); } - -#if FULL_SYSTEM - void dumpFuncProfile() { actualXC->dumpFuncProfile(); } -#endif - - void takeOverFrom(ExecContext *oldContext) - { actualXC->takeOverFrom(oldContext); } - - void regStats(const std::string &name) { actualXC->regStats(name); } - - void serialize(std::ostream &os) { actualXC->serialize(os); } - void unserialize(Checkpoint *cp, const std::string §ion) - { actualXC->unserialize(cp, section); } - -#if FULL_SYSTEM - EndQuiesceEvent *getQuiesceEvent() { return actualXC->getQuiesceEvent(); } - - Tick readLastActivate() { return actualXC->readLastActivate(); } - Tick readLastSuspend() { return actualXC->readLastSuspend(); } - - void profileClear() { return actualXC->profileClear(); } - void profileSample() { return actualXC->profileSample(); } -#endif - - int getThreadNum() { return actualXC->getThreadNum(); } - - // @todo: Do I need this? - MachInst getInst() { return actualXC->getInst(); } - - // @todo: Do I need this? - void copyArchRegs(ExecContext *xc) { actualXC->copyArchRegs(xc); } - - void clearArchRegs() { actualXC->clearArchRegs(); } - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { return actualXC->readIntReg(reg_idx); } - - float readFloatRegSingle(int reg_idx) - { return actualXC->readFloatRegSingle(reg_idx); } - - double readFloatRegDouble(int reg_idx) - { return actualXC->readFloatRegDouble(reg_idx); } - - uint64_t readFloatRegInt(int reg_idx) - { return actualXC->readFloatRegInt(reg_idx); } - - void setIntReg(int reg_idx, uint64_t val) - { actualXC->setIntReg(reg_idx, val); } - - void setFloatRegSingle(int reg_idx, float val) - { actualXC->setFloatRegSingle(reg_idx, val); } - - void setFloatRegDouble(int reg_idx, double val) - { actualXC->setFloatRegDouble(reg_idx, val); } - - void setFloatRegInt(int reg_idx, uint64_t val) - { actualXC->setFloatRegInt(reg_idx, val); } - - uint64_t readPC() { return actualXC->readPC(); } - - void setPC(uint64_t val) { actualXC->setPC(val); } - - uint64_t readNextPC() { return actualXC->readNextPC(); } - - void setNextPC(uint64_t val) { actualXC->setNextPC(val); } - - MiscReg readMiscReg(int misc_reg) - { return actualXC->readMiscReg(misc_reg); } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return actualXC->readMiscRegWithEffect(misc_reg, fault); } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { return actualXC->setMiscReg(misc_reg, val); } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { return actualXC->setMiscRegWithEffect(misc_reg, val); } - - unsigned readStCondFailures() - { return actualXC->readStCondFailures(); } - - void setStCondFailures(unsigned sc_failures) - { actualXC->setStCondFailures(sc_failures); } -#if FULL_SYSTEM - bool inPalMode() { return actualXC->inPalMode(); } -#endif - - // @todo: Fix this! - bool misspeculating() { return actualXC->misspeculating(); } - -#if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { actualXC->setSyscallArg(i, val); } - - void setSyscallReturn(SyscallReturn return_value) - { actualXC->setSyscallReturn(return_value); } - -// void syscall() { actualXC->syscall(); } - - Counter readFuncExeInst() { return actualXC->readFuncExeInst(); } -#endif -}; - -#endif diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc deleted file mode 100644 index d5eacd839..000000000 --- a/cpu/exetrace.cc +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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 - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <fstream> -#include <iomanip> - -#include "sim/param.hh" -#include "encumbered/cpu/full/dyn_inst.hh" -#include "encumbered/cpu/full/spec_state.hh" -#include "encumbered/cpu/full/issue.hh" -#include "cpu/exetrace.hh" -#include "base/loader/symtab.hh" -#include "cpu/base.hh" -#include "cpu/static_inst.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// Methods for the InstRecord object -// - - -void -Trace::InstRecord::dump(ostream &outs) -{ - if (flags[INTEL_FORMAT]) { -#if FULL_SYSTEM - bool is_trace_system = (cpu->system->name() == trace_system); -#else - bool is_trace_system = true; -#endif - if (is_trace_system) { - ccprintf(outs, "%7d ) ", cycle); - outs << "0x" << hex << PC << ":\t"; - if (staticInst->isLoad()) { - outs << "<RD 0x" << hex << addr; - outs << ">"; - } else if (staticInst->isStore()) { - outs << "<WR 0x" << hex << addr; - outs << ">"; - } - outs << endl; - } - } else { - if (flags[PRINT_CYCLE]) - ccprintf(outs, "%7d: ", cycle); - - outs << cpu->name() << " "; - - if (flags[TRACE_MISSPEC]) - outs << (misspeculating ? "-" : "+") << " "; - - if (flags[PRINT_THREAD_NUM]) - outs << "T" << thread << " : "; - - - std::string sym_str; - Addr sym_addr; - if (debugSymbolTable - && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) - && flags[PC_SYMBOL]) { - if (PC != sym_addr) - sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; - } - else { - outs << "0x" << hex << PC << " : "; - } - - // - // Print decoded instruction - // - -#if defined(__GNUC__) && (__GNUC__ < 3) - // There's a bug in gcc 2.x library that prevents setw() - // from working properly on strings - string mc(staticInst->disassemble(PC, debugSymbolTable)); - while (mc.length() < 26) - mc += " "; - outs << mc; -#else - outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); -#endif - - outs << " : "; - - if (flags[PRINT_OP_CLASS]) { - outs << opClassStrings[staticInst->opClass()] << " : "; - } - - if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) { - outs << " D="; -#if 0 - if (data_status == DataDouble) - ccprintf(outs, "%f", data.as_double); - else - ccprintf(outs, "%#018x", data.as_int); -#else - ccprintf(outs, "%#018x", data.as_int); -#endif - } - - if (flags[PRINT_EFF_ADDR] && addr_valid) - outs << " A=0x" << hex << addr; - - if (flags[PRINT_INT_REGS] && regs_valid) { - for (int i = 0; i < 32;) - for (int j = i + 1; i <= j; i++) - ccprintf(outs, "r%02d = %#018x%s", i, iregs->regs[i], - ((i == j) ? "\n" : " ")); - outs << "\n"; - } - - if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; - - if (flags[PRINT_CP_SEQ] && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; - - // - // End of line... - // - outs << endl; - } -} - - -vector<bool> Trace::InstRecord::flags(NUM_BITS); -string Trace::InstRecord::trace_system; - -//////////////////////////////////////////////////////////////////////// -// -// Parameter space for per-cycle execution address tracing options. -// Derive from ParamContext so we can override checkParams() function. -// -class ExecutionTraceParamContext : public ParamContext -{ - public: - ExecutionTraceParamContext(const string &_iniSection) - : ParamContext(_iniSection) - { - } - - void checkParams(); // defined at bottom of file -}; - -ExecutionTraceParamContext exeTraceParams("exetrace"); - -Param<bool> exe_trace_spec(&exeTraceParams, "speculative", - "capture speculative instructions", true); - -Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle", - "print cycle number", true); -Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass", - "print op class", true); -Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread", - "print thread number", true); -Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr", - "print effective address", true); -Param<bool> exe_trace_print_data(&exeTraceParams, "print_data", - "print result data", true); -Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs", - "print all integer regs", false); -Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq", - "print fetch sequence number", false); -Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq", - "print correct-path sequence number", false); -Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol", - "Use symbols for the PC if available", true); -Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format", - "print trace in intel compatible format", false); -Param<string> exe_trace_system(&exeTraceParams, "trace_system", - "print trace of which system (client or server)", - "client"); - - -// -// Helper function for ExecutionTraceParamContext::checkParams() just -// to get us into the InstRecord namespace -// -void -Trace::InstRecord::setParams() -{ - flags[TRACE_MISSPEC] = exe_trace_spec; - - flags[PRINT_CYCLE] = exe_trace_print_cycle; - flags[PRINT_OP_CLASS] = exe_trace_print_opclass; - flags[PRINT_THREAD_NUM] = exe_trace_print_thread; - flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr; - flags[PRINT_EFF_ADDR] = exe_trace_print_data; - flags[PRINT_INT_REGS] = exe_trace_print_iregs; - flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq; - flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq; - flags[PC_SYMBOL] = exe_trace_pc_symbol; - flags[INTEL_FORMAT] = exe_trace_intel_format; - trace_system = exe_trace_system; -} - -void -ExecutionTraceParamContext::checkParams() -{ - Trace::InstRecord::setParams(); -} - diff --git a/cpu/exetrace.hh b/cpu/exetrace.hh deleted file mode 100644 index 2f70e26e7..000000000 --- a/cpu/exetrace.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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 - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __EXETRACE_HH__ -#define __EXETRACE_HH__ - -#include <fstream> -#include <vector> - -#include "sim/host.hh" -#include "cpu/inst_seq.hh" // for InstSeqNum -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/static_inst.hh" - -class BaseCPU; - - -namespace Trace { - -class InstRecord : public Record -{ - protected: - typedef TheISA::IntRegFile IntRegFile; - - // The following fields are initialized by the constructor and - // thus guaranteed to be valid. - BaseCPU *cpu; - // need to make this ref-counted so it doesn't go away before we - // dump the record - StaticInstPtr staticInst; - Addr PC; - bool misspeculating; - unsigned thread; - - // The remaining fields are only valid for particular instruction - // types (e.g, addresses for memory ops) or when particular - // options are enabled (e.g., tracing full register contents). - // Each data field has an associated valid flag to indicate - // whether the data field is valid. - Addr addr; - bool addr_valid; - - union { - uint64_t as_int; - double as_double; - } data; - enum { - DataInvalid = 0, - DataInt8 = 1, // set to equal number of bytes - DataInt16 = 2, - DataInt32 = 4, - DataInt64 = 8, - DataDouble = 3 - } data_status; - - InstSeqNum fetch_seq; - bool fetch_seq_valid; - - InstSeqNum cp_seq; - bool cp_seq_valid; - - struct iRegFile { - IntRegFile regs; - }; - iRegFile *iregs; - bool regs_valid; - - public: - InstRecord(Tick _cycle, BaseCPU *_cpu, - const StaticInstPtr &_staticInst, - Addr _pc, bool spec, int _thread) - : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc), - misspeculating(spec), thread(_thread) - { - data_status = DataInvalid; - addr_valid = false; - regs_valid = false; - - fetch_seq_valid = false; - cp_seq_valid = false; - } - - virtual ~InstRecord() { } - - virtual void dump(std::ostream &outs); - - void setAddr(Addr a) { addr = a; addr_valid = true; } - - void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } - void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } - void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } - void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } - - void setData(int64_t d) { setData((uint64_t)d); } - void setData(int32_t d) { setData((uint32_t)d); } - void setData(int16_t d) { setData((uint16_t)d); } - void setData(int8_t d) { setData((uint8_t)d); } - - void setData(double d) { data.as_double = d; data_status = DataDouble; } - - void setFetchSeq(InstSeqNum seq) - { fetch_seq = seq; fetch_seq_valid = true; } - - void setCPSeq(InstSeqNum seq) - { cp_seq = seq; cp_seq_valid = true; } - - void setRegs(const IntRegFile ®s); - - void finalize() { theLog.append(this); } - - enum InstExecFlagBits { - TRACE_MISSPEC = 0, - PRINT_CYCLE, - PRINT_OP_CLASS, - PRINT_THREAD_NUM, - PRINT_RESULT_DATA, - PRINT_EFF_ADDR, - PRINT_INT_REGS, - PRINT_FETCH_SEQ, - PRINT_CP_SEQ, - PC_SYMBOL, - INTEL_FORMAT, - NUM_BITS - }; - - static std::vector<bool> flags; - static std::string trace_system; - - static void setParams(); - - static bool traceMisspec() { return flags[TRACE_MISSPEC]; } -}; - - -inline void -InstRecord::setRegs(const IntRegFile ®s) -{ - if (!iregs) - iregs = new iRegFile; - - memcpy(&iregs->regs, regs, sizeof(IntRegFile)); - regs_valid = true; -} - -inline -InstRecord * -getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu, - const StaticInstPtr staticInst, - Addr pc, int thread = 0) -{ - if (DTRACE(InstExec) && - (InstRecord::traceMisspec() || !xc->misspeculating())) { - return new InstRecord(cycle, cpu, staticInst, pc, - xc->misspeculating(), thread); - } - - return NULL; -} - - -} - -#endif // __EXETRACE_HH__ diff --git a/cpu/inst_seq.hh b/cpu/inst_seq.hh deleted file mode 100644 index 356d19df0..000000000 --- a/cpu/inst_seq.hh +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __STD_TYPES_HH__ -#define __STD_TYPES_HH__ - -#include <stdint.h> - -// inst sequence type, used to order instructions in the ready list, -// if this rolls over the ready list order temporarily will get messed -// up, but execution will continue and complete correctly -typedef uint64_t InstSeqNum; - -// inst tag type, used to tag an operation instance in the IQ -typedef unsigned int InstTag; - -#endif // __STD_TYPES_HH__ diff --git a/cpu/intr_control.cc b/cpu/intr_control.cc deleted file mode 100644 index 43e7f654c..000000000 --- a/cpu/intr_control.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" - -using namespace std; - -IntrControl::IntrControl(const string &name, BaseCPU *c) - : SimObject(name), cpu(c) -{} - -/* @todo - *Fix the cpu sim object parameter to be a system pointer - *instead, to avoid some extra dereferencing - */ -void -IntrControl::post(int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[0]->getCpuPtr(); - temp->post_interrupt(int_num, index); -} - -void -IntrControl::post(int cpu_id, int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[cpu_id]->getCpuPtr(); - temp->post_interrupt(int_num, index); -} - -void -IntrControl::clear(int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[0]->getCpuPtr(); - temp->clear_interrupt(int_num, index); -} - -void -IntrControl::clear(int cpu_id, int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[cpu_id]->getCpuPtr(); - temp->clear_interrupt(int_num, index); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IntrControl) - - SimObjectParam<BaseCPU *> cpu; - -END_DECLARE_SIM_OBJECT_PARAMS(IntrControl) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IntrControl) - - INIT_PARAM(cpu, "the cpu") - -END_INIT_SIM_OBJECT_PARAMS(IntrControl) - -CREATE_SIM_OBJECT(IntrControl) -{ - return new IntrControl(getInstanceName(), cpu); -} - -REGISTER_SIM_OBJECT("IntrControl", IntrControl) diff --git a/cpu/intr_control.hh b/cpu/intr_control.hh deleted file mode 100644 index 5ec4e14cb..000000000 --- a/cpu/intr_control.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __INTR_CONTROL_HH__ -#define __INTR_CONTROL_HH__ - -#include <vector> -#include "base/misc.hh" -#include "cpu/base.hh" -#include "sim/sim_object.hh" -#include "sim/system.hh" - - -class IntrControl : public SimObject -{ - public: - BaseCPU *cpu; - IntrControl(const std::string &name, BaseCPU *c); - - void clear(int int_num, int index = 0); - void post(int int_num, int index = 0); - void clear(int cpu_id, int int_num, int index); - void post(int cpu_id, int int_num, int index); -}; - -#endif // __INTR_CONTROL_HH__ - - - - - - - diff --git a/cpu/memtest/memtest.cc b/cpu/memtest/memtest.cc deleted file mode 100644 index 94b66b70b..000000000 --- a/cpu/memtest/memtest.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded - -#include <iomanip> -#include <set> -#include <sstream> -#include <string> -#include <vector> - -#include "base/misc.hh" -#include "base/statistics.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/memtest/memtest.hh" -#include "mem/cache/base_cache.hh" -#include "sim/builder.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -using namespace std; -using namespace TheISA; - -int TESTER_ALLOCATOR=0; - -MemTest::MemTest(const string &name, - MemInterface *_cache_interface, - FunctionalMemory *main_mem, - FunctionalMemory *check_mem, - unsigned _memorySize, - unsigned _percentReads, - unsigned _percentCopies, - unsigned _percentUncacheable, - unsigned _progressInterval, - unsigned _percentSourceUnaligned, - unsigned _percentDestUnaligned, - Addr _traceAddr, - Counter _max_loads) - : SimObject(name), - tickEvent(this), - cacheInterface(_cache_interface), - mainMem(main_mem), - checkMem(check_mem), - size(_memorySize), - percentReads(_percentReads), - percentCopies(_percentCopies), - percentUncacheable(_percentUncacheable), - progressInterval(_progressInterval), - nextProgressMessage(_progressInterval), - percentSourceUnaligned(_percentSourceUnaligned), - percentDestUnaligned(percentDestUnaligned), - maxLoads(_max_loads) -{ - vector<string> cmd; - cmd.push_back("/bin/ls"); - vector<string> null_vec; - cpuXC = new CPUExecContext(NULL, 0, mainMem, 0); - - blockSize = cacheInterface->getBlockSize(); - blockAddrMask = blockSize - 1; - traceBlockAddr = blockAddr(_traceAddr); - - //setup data storage with interesting values - uint8_t *data1 = new uint8_t[size]; - uint8_t *data2 = new uint8_t[size]; - uint8_t *data3 = new uint8_t[size]; - memset(data1, 1, size); - memset(data2, 2, size); - memset(data3, 3, size); - curTick = 0; - - baseAddr1 = 0x100000; - baseAddr2 = 0x400000; - uncacheAddr = 0x800000; - - // set up intial memory contents here - mainMem->prot_write(baseAddr1, data1, size); - checkMem->prot_write(baseAddr1, data1, size); - mainMem->prot_write(baseAddr2, data2, size); - checkMem->prot_write(baseAddr2, data2, size); - mainMem->prot_write(uncacheAddr, data3, size); - checkMem->prot_write(uncacheAddr, data3, size); - - delete [] data1; - delete [] data2; - delete [] data3; - - // set up counters - noResponseCycles = 0; - numReads = 0; - tickEvent.schedule(0); - - id = TESTER_ALLOCATOR++; -} - -static void -printData(ostream &os, uint8_t *data, int nbytes) -{ - os << hex << setfill('0'); - // assume little-endian: print bytes from highest address to lowest - for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { - os << setw(2) << (unsigned)*dp; - } - os << dec; -} - -void -MemTest::completeRequest(MemReqPtr &req, uint8_t *data) -{ - //Remove the address from the list of outstanding - std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); - assert(removeAddr != outstandingAddrs.end()); - outstandingAddrs.erase(removeAddr); - - switch (req->cmd) { - case Read: - if (memcmp(req->data, data, req->size) != 0) { - cerr << name() << ": on read of 0x" << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << "@ cycle " << dec << curTick - << ", cache returns 0x"; - printData(cerr, req->data, req->size); - cerr << ", expected 0x"; - printData(cerr, data, req->size); - cerr << endl; - fatal(""); - } - - numReads++; - numReadsStat++; - - if (numReads == nextProgressMessage) { - ccprintf(cerr, "%s: completed %d read accesses @%d\n", - name(), numReads, curTick); - nextProgressMessage += progressInterval; - } - - if (numReads >= maxLoads) - SimExit(curTick, "Maximum number of loads reached!"); - break; - - case Write: - numWritesStat++; - break; - - case Copy: - //Also remove dest from outstanding list - removeAddr = outstandingAddrs.find(req->dest); - assert(removeAddr != outstandingAddrs.end()); - outstandingAddrs.erase(removeAddr); - numCopiesStat++; - break; - - default: - panic("invalid command"); - } - - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() << ": completed " - << (req->cmd.isWrite() ? "write" : "read") - << " access of " - << dec << req->size << " bytes at address 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << ", value = 0x"; - printData(cerr, req->data, req->size); - cerr << " @ cycle " << dec << curTick; - - cerr << endl; - } - - noResponseCycles = 0; - delete [] data; -} - - -void -MemTest::regStats() -{ - using namespace Stats; - - - numReadsStat - .name(name() + ".num_reads") - .desc("number of read accesses completed") - ; - - numWritesStat - .name(name() + ".num_writes") - .desc("number of write accesses completed") - ; - - numCopiesStat - .name(name() + ".num_copies") - .desc("number of copy accesses completed") - ; -} - -void -MemTest::tick() -{ - if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); - - if (++noResponseCycles >= 500000) { - cerr << name() << ": deadlocked at cycle " << curTick << endl; - fatal(""); - } - - if (cacheInterface->isBlocked()) { - return; - } - - //make new request - unsigned cmd = random() % 100; - unsigned offset = random() % size; - unsigned base = random() % 2; - uint64_t data = random(); - unsigned access_size = random() % 4; - unsigned cacheable = random() % 100; - - //If we aren't doing copies, use id as offset, and do a false sharing - //mem tester - if (percentCopies == 0) { - //We can eliminate the lower bits of the offset, and then use the id - //to offset within the blks - offset &= ~63; //Not the low order bits - offset += id; - access_size = 0; - } - - MemReqPtr req = new MemReq(); - - if (cacheable < percentUncacheable) { - req->flags |= UNCACHEABLE; - req->paddr = uncacheAddr + offset; - } else { - req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset; - } - // bool probe = (random() % 2 == 1) && !req->isUncacheable(); - bool probe = false; - - req->size = 1 << access_size; - req->data = new uint8_t[req->size]; - req->paddr &= ~(req->size - 1); - req->time = curTick; - req->xc = cpuXC->getProxy(); - - if (cmd < percentReads) { - // read - - //For now we only allow one outstanding request per addreess per tester - //This means we assume CPU does write forwarding to reads that alias something - //in the cpu store buffer. - if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(req->paddr); - - req->cmd = Read; - uint8_t *result = new uint8_t[8]; - checkMem->access(Read, req->paddr, result, req->size); - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() - << ": initiating read " - << ((probe) ? "probe of " : "access of ") - << dec << req->size << " bytes from addr 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << " at cycle " - << dec << curTick << endl; - } - if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, result); - } else { - req->completionEvent = new MemCompleteEvent(req, result, this); - cacheInterface->access(req); - } - } else if (cmd < (100 - percentCopies)){ - // write - - //For now we only allow one outstanding request per addreess per tester - //This means we assume CPU does write forwarding to reads that alias something - //in the cpu store buffer. - if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(req->paddr); - - req->cmd = Write; - memcpy(req->data, &data, req->size); - checkMem->access(Write, req->paddr, req->data, req->size); - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() << ": initiating write " - << ((probe)?"probe of ":"access of ") - << dec << req->size << " bytes (value = 0x"; - printData(cerr, req->data, req->size); - cerr << ") to addr 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << " at cycle " - << dec << curTick << endl; - } - if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, NULL); - } else { - req->completionEvent = new MemCompleteEvent(req, NULL, this); - cacheInterface->access(req); - } - } else { - // copy - unsigned source_align = random() % 100; - unsigned dest_align = random() % 100; - unsigned offset2 = random() % size; - - Addr source = ((base) ? baseAddr1 : baseAddr2) + offset; - Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; - if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(source); - if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(dest); - - if (source_align >= percentSourceUnaligned) { - source = blockAddr(source); - } - if (dest_align >= percentDestUnaligned) { - dest = blockAddr(dest); - } - req->cmd = Copy; - req->flags &= ~UNCACHEABLE; - req->paddr = source; - req->dest = dest; - delete [] req->data; - req->data = new uint8_t[blockSize]; - req->size = blockSize; - if (source == traceBlockAddr || dest == traceBlockAddr) { - cerr << name() - << ": initiating copy of " - << dec << req->size << " bytes from addr 0x" - << hex << source - << " (0x" << hex << blockAddr(source) << ")" - << " to addr 0x" - << hex << dest - << " (0x" << hex << blockAddr(dest) << ")" - << " at cycle " - << dec << curTick << endl; - } - cacheInterface->access(req); - uint8_t result[blockSize]; - checkMem->access(Read, source, &result, blockSize); - checkMem->access(Write, dest, &result, blockSize); - } -} - - -void -MemCompleteEvent::process() -{ - tester->completeRequest(req, data); - delete this; -} - - -const char * -MemCompleteEvent::description() -{ - return "memory access completion"; -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) - - SimObjectParam<BaseCache *> cache; - SimObjectParam<FunctionalMemory *> main_mem; - SimObjectParam<FunctionalMemory *> check_mem; - Param<unsigned> memory_size; - Param<unsigned> percent_reads; - Param<unsigned> percent_copies; - Param<unsigned> percent_uncacheable; - Param<unsigned> progress_interval; - Param<unsigned> percent_source_unaligned; - Param<unsigned> percent_dest_unaligned; - Param<Addr> trace_addr; - Param<Counter> max_loads; - -END_DECLARE_SIM_OBJECT_PARAMS(MemTest) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) - - INIT_PARAM(cache, "L1 cache"), - INIT_PARAM(main_mem, "hierarchical memory"), - INIT_PARAM(check_mem, "check memory"), - INIT_PARAM(memory_size, "memory size"), - INIT_PARAM(percent_reads, "target read percentage"), - INIT_PARAM(percent_copies, "target copy percentage"), - INIT_PARAM(percent_uncacheable, "target uncacheable percentage"), - INIT_PARAM(progress_interval, "progress report interval (in accesses)"), - INIT_PARAM(percent_source_unaligned, - "percent of copy source address that are unaligned"), - INIT_PARAM(percent_dest_unaligned, - "percent of copy dest address that are unaligned"), - INIT_PARAM(trace_addr, "address to trace"), - INIT_PARAM(max_loads, "terminate when we have reached this load count") - -END_INIT_SIM_OBJECT_PARAMS(MemTest) - - -CREATE_SIM_OBJECT(MemTest) -{ - return new MemTest(getInstanceName(), cache->getInterface(), main_mem, - check_mem, memory_size, percent_reads, percent_copies, - percent_uncacheable, progress_interval, - percent_source_unaligned, percent_dest_unaligned, - trace_addr, max_loads); -} - -REGISTER_SIM_OBJECT("MemTest", MemTest) diff --git a/cpu/memtest/memtest.hh b/cpu/memtest/memtest.hh deleted file mode 100644 index cdb40a26a..000000000 --- a/cpu/memtest/memtest.hh +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_MEMTEST_MEMTEST_HH__ -#define __CPU_MEMTEST_MEMTEST_HH__ - -#include <set> - -#include "base/statistics.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_interface.hh" -#include "sim/eventq.hh" -#include "sim/sim_exit.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -class ExecContext; -class MemTest : public SimObject -{ - public: - - MemTest(const std::string &name, - MemInterface *_cache_interface, - FunctionalMemory *main_mem, - FunctionalMemory *check_mem, - unsigned _memorySize, - unsigned _percentReads, - unsigned _percentCopies, - unsigned _percentUncacheable, - unsigned _progressInterval, - unsigned _percentSourceUnaligned, - unsigned _percentDestUnaligned, - Addr _traceAddr, - Counter _max_loads); - - // register statistics - virtual void regStats(); - - inline Tick cycles(int numCycles) const { return numCycles; } - - // main simulation loop (one cycle) - void tick(); - - protected: - class TickEvent : public Event - { - private: - MemTest *cpu; - public: - TickEvent(MemTest *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {} - void process() {cpu->tick();} - virtual const char *description() { return "tick event"; } - }; - - TickEvent tickEvent; - - MemInterface *cacheInterface; - FunctionalMemory *mainMem; - FunctionalMemory *checkMem; - CPUExecContext *cpuXC; - - unsigned size; // size of testing memory region - - unsigned percentReads; // target percentage of read accesses - unsigned percentCopies; // target percentage of copy accesses - unsigned percentUncacheable; - - int id; - - std::set<unsigned> outstandingAddrs; - - unsigned blockSize; - - Addr blockAddrMask; - - Addr blockAddr(Addr addr) - { - return (addr & ~blockAddrMask); - } - - Addr traceBlockAddr; - - Addr baseAddr1; // fix this to option - Addr baseAddr2; // fix this to option - Addr uncacheAddr; - - unsigned progressInterval; // frequency of progress reports - Tick nextProgressMessage; // access # for next progress report - - unsigned percentSourceUnaligned; - unsigned percentDestUnaligned; - - Tick noResponseCycles; - - uint64_t numReads; - uint64_t maxLoads; - Stats::Scalar<> numReadsStat; - Stats::Scalar<> numWritesStat; - Stats::Scalar<> numCopiesStat; - - // called by MemCompleteEvent::process() - void completeRequest(MemReqPtr &req, uint8_t *data); - - friend class MemCompleteEvent; -}; - - -class MemCompleteEvent : public Event -{ - MemReqPtr req; - uint8_t *data; - MemTest *tester; - - public: - - MemCompleteEvent(MemReqPtr &_req, uint8_t *_data, MemTest *_tester) - : Event(&mainEventQueue), - req(_req), data(_data), tester(_tester) - { - } - - void process(); - - virtual const char *description(); -}; - -#endif // __CPU_MEMTEST_MEMTEST_HH__ - - - diff --git a/cpu/o3/2bit_local_pred.cc b/cpu/o3/2bit_local_pred.cc deleted file mode 100644 index c3fb2fdb8..000000000 --- a/cpu/o3/2bit_local_pred.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/intmath.hh" -#include "base/trace.hh" -#include "cpu/o3/2bit_local_pred.hh" - -DefaultBP::DefaultBP(unsigned _localPredictorSize, - unsigned _localCtrBits, - unsigned _instShiftAmt) - : localPredictorSize(_localPredictorSize), - localCtrBits(_localCtrBits), - instShiftAmt(_instShiftAmt) -{ - if (!isPowerOf2(localPredictorSize)) { - fatal("Invalid local predictor size!\n"); - } - - localPredictorSets = localPredictorSize / localCtrBits; - - if (!isPowerOf2(localPredictorSets)) { - fatal("Invalid number of local predictor sets! Check localCtrBits.\n"); - } - - // Setup the index mask. - indexMask = localPredictorSets - 1; - - DPRINTF(Fetch, "Branch predictor: index mask: %#x\n", indexMask); - - // Setup the array of counters for the local predictor. - localCtrs.resize(localPredictorSets); - - for (int i = 0; i < localPredictorSets; ++i) - localCtrs[i].setBits(_localCtrBits); - - DPRINTF(Fetch, "Branch predictor: local predictor size: %i\n", - localPredictorSize); - - DPRINTF(Fetch, "Branch predictor: local counter bits: %i\n", localCtrBits); - - DPRINTF(Fetch, "Branch predictor: instruction shift amount: %i\n", - instShiftAmt); -} - -void -DefaultBP::reset() -{ - for (int i = 0; i < localPredictorSets; ++i) { - localCtrs[i].reset(); - } -} - -bool -DefaultBP::lookup(Addr &branch_addr) -{ - bool taken; - uint8_t local_prediction; - unsigned local_predictor_idx = getLocalIndex(branch_addr); - - DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n", - local_predictor_idx); - - local_prediction = localCtrs[local_predictor_idx].read(); - - DPRINTF(Fetch, "Branch predictor: prediction is %i.\n", - (int)local_prediction); - - taken = getPrediction(local_prediction); - -#if 0 - // Speculative update. - if (taken) { - DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n"); - localCtrs[local_predictor_idx].increment(); - } else { - DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n"); - localCtrs[local_predictor_idx].decrement(); - } -#endif - - return taken; -} - -void -DefaultBP::update(Addr &branch_addr, bool taken) -{ - unsigned local_predictor_idx; - - // Update the local predictor. - local_predictor_idx = getLocalIndex(branch_addr); - - DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n", - local_predictor_idx); - - if (taken) { - DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n"); - localCtrs[local_predictor_idx].increment(); - } else { - DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n"); - localCtrs[local_predictor_idx].decrement(); - } -} - -inline -bool -DefaultBP::getPrediction(uint8_t &count) -{ - // Get the MSB of the count - return (count >> (localCtrBits - 1)); -} - -inline -unsigned -DefaultBP::getLocalIndex(Addr &branch_addr) -{ - return (branch_addr >> instShiftAmt) & indexMask; -} diff --git a/cpu/o3/2bit_local_pred.hh b/cpu/o3/2bit_local_pred.hh deleted file mode 100644 index cd65978ca..000000000 --- a/cpu/o3/2bit_local_pred.hh +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_2BIT_LOCAL_PRED_HH__ -#define __CPU_O3_2BIT_LOCAL_PRED_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include "cpu/o3/sat_counter.hh" - -#include <vector> - -class DefaultBP -{ - public: - /** - * Default branch predictor constructor. - * @param localPredictorSize Size of the local predictor. - * @param localCtrBits Number of bits per counter. - * @param instShiftAmt Offset amount for instructions to ignore alignment. - */ - DefaultBP(unsigned localPredictorSize, unsigned localCtrBits, - unsigned instShiftAmt); - - /** - * Looks up the given address in the branch predictor and returns - * a true/false value as to whether it is taken. - * @param branch_addr The address of the branch to look up. - * @return Whether or not the branch is taken. - */ - bool lookup(Addr &branch_addr); - - /** - * Updates the branch predictor with the actual result of a branch. - * @param branch_addr The address of the branch to update. - * @param taken Whether or not the branch was taken. - */ - void update(Addr &branch_addr, bool taken); - - void reset(); - - private: - - /** - * Returns the taken/not taken prediction given the value of the - * counter. - * @param count The value of the counter. - * @return The prediction based on the counter value. - */ - inline bool getPrediction(uint8_t &count); - - /** Calculates the local index based on the PC. */ - inline unsigned getLocalIndex(Addr &PC); - - /** Array of counters that make up the local predictor. */ - std::vector<SatCounter> localCtrs; - - /** Size of the local predictor. */ - unsigned localPredictorSize; - - /** Number of sets. */ - unsigned localPredictorSets; - - /** Number of bits of the local predictor's counters. */ - unsigned localCtrBits; - - /** Number of bits to shift the PC when calculating index. */ - unsigned instShiftAmt; - - /** Mask to get index bits. */ - unsigned indexMask; -}; - -#endif // __CPU_O3_2BIT_LOCAL_PRED_HH__ diff --git a/cpu/o3/alpha_cpu.cc b/cpu/o3/alpha_cpu.cc deleted file mode 100644 index 7bc90dae6..000000000 --- a/cpu/o3/alpha_cpu.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_cpu_impl.hh" -#include "cpu/o3/alpha_dyn_inst.hh" - -// Force instantiation of AlphaFullCPU for all the implemntations that are -// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (alpha_impl.cc?). -template class AlphaFullCPU<AlphaSimpleImpl>; diff --git a/cpu/o3/alpha_cpu.hh b/cpu/o3/alpha_cpu.hh deleted file mode 100644 index 5c89e3462..000000000 --- a/cpu/o3/alpha_cpu.hh +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_FULL_CPU_HH__ -#define __CPU_O3_ALPHA_FULL_CPU_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/exec_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -template <class Impl> -class AlphaFullCPU : public FullO3CPU<Impl> -{ - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::MiscReg MiscReg; - typedef TheISA::RegFile RegFile; - typedef TheISA::MiscRegFile MiscRegFile; - - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaFullCPU with the given parameters. */ - AlphaFullCPU(Params *params); - - class AlphaXC : public ExecContext - { - public: - AlphaFullCPU<Impl> *cpu; - - O3ThreadState<Impl> *thread; - - virtual BaseCPU *getCpuPtr() { return cpu; } - - virtual void setCpuId(int id) { cpu->cpu_id = id; } - - virtual int readCpuId() { return cpu->cpu_id; } - - virtual FunctionalMemory *getMemPtr() { return thread->mem; } - -#if FULL_SYSTEM - virtual System *getSystemPtr() { return cpu->system; } - - virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } - - virtual AlphaITB *getITBPtr() { return cpu->itb; } - - virtual AlphaDTB * getDTBPtr() { return cpu->dtb; } - - virtual Kernel::Statistics *getKernelStats() - { return thread->kernelStats; } -#else - virtual Process *getProcessPtr() { return thread->process; } -#endif - - virtual Status status() const { return thread->status(); } - - virtual void setStatus(Status new_status) - { thread->setStatus(new_status); } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - virtual void activate(int delay = 1); - - /// Set the status to Suspended. - virtual void suspend(); - - /// Set the status to Unallocated. - virtual void deallocate(); - - /// Set the status to Halted. - virtual void halt(); - -#if FULL_SYSTEM - virtual void dumpFuncProfile(); -#endif - - virtual void takeOverFrom(ExecContext *old_context); - - virtual void regStats(const std::string &name); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -#if FULL_SYSTEM - virtual EndQuiesceEvent *getQuiesceEvent(); - - virtual Tick readLastActivate(); - virtual Tick readLastSuspend(); - - virtual void profileClear(); - virtual void profileSample(); -#endif - - virtual int getThreadNum() { return thread->tid; } - - virtual TheISA::MachInst getInst(); - - virtual void copyArchRegs(ExecContext *xc); - - virtual void clearArchRegs(); - - virtual uint64_t readIntReg(int reg_idx); - - virtual float readFloatRegSingle(int reg_idx); - - virtual double readFloatRegDouble(int reg_idx); - - virtual uint64_t readFloatRegInt(int reg_idx); - - virtual void setIntReg(int reg_idx, uint64_t val); - - virtual void setFloatRegSingle(int reg_idx, float val); - - virtual void setFloatRegDouble(int reg_idx, double val); - - virtual void setFloatRegInt(int reg_idx, uint64_t val); - - virtual uint64_t readPC() - { return cpu->readPC(thread->tid); } - - virtual void setPC(uint64_t val); - - virtual uint64_t readNextPC() - { return cpu->readNextPC(thread->tid); } - - virtual void setNextPC(uint64_t val); - - virtual MiscReg readMiscReg(int misc_reg) - { return cpu->readMiscReg(misc_reg, thread->tid); } - - virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return cpu->readMiscRegWithEffect(misc_reg, fault, thread->tid); } - - virtual Fault setMiscReg(int misc_reg, const MiscReg &val); - - virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); - - // @todo: Figure out where these store cond failures should go. - virtual unsigned readStCondFailures() - { return thread->storeCondFailures; } - - virtual void setStCondFailures(unsigned sc_failures) - { thread->storeCondFailures = sc_failures; } - -#if FULL_SYSTEM - virtual bool inPalMode() - { return TheISA::PcPAL(cpu->readPC(thread->tid)); } -#endif - - // Only really makes sense for old CPU model. Lots of code - // outside the CPU still checks this function, so it will - // always return false to keep everything working. - virtual bool misspeculating() { return false; } - -#if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i); - - virtual void setSyscallArg(int i, IntReg val); - - virtual void setSyscallReturn(SyscallReturn return_value); - - virtual void syscall() { return cpu->syscall(thread->tid); } - - virtual Counter readFuncExeInst() { return thread->funcExeInst; } -#endif - }; - -#if FULL_SYSTEM - /** ITB pointer. */ - AlphaITB *itb; - /** DTB pointer. */ - AlphaDTB *dtb; -#endif - - /** Registers statistics. */ - void regStats(); - -#if FULL_SYSTEM - /** Translates instruction requestion. */ - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - /** Translates data read request. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - -#endif - MiscReg readMiscReg(int misc_reg, unsigned tid); - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, unsigned tid); - - Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); - - void squashFromXC(unsigned tid); - -#if FULL_SYSTEM - void post_interrupt(int int_num, int index); - - int readIntrFlag(); - /** Sets the interrupt flags. */ - void setIntrFlag(int val); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - /** Returns if a specific PC is a PAL mode PC. */ - bool inPalMode(uint64_t PC) - { return AlphaISA::PcPAL(PC); } - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - bool simPalCheck(int palFunc, unsigned tid); - - /** Processes any interrupts. */ - void processInterrupts(); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int thread_num); - /** Gets a syscall argument. */ - IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** Read from memory function. */ - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif -#endif - Fault error; - -#if FULL_SYSTEM - // @todo: Fix this LL/SC hack. - if (req->flags & LOCKED) { - lockAddr = req->paddr; - lockFlag = true; - } -#endif - - error = this->mem->read(req, data); - data = gtoh(data); - return error; - } - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** Write to memory function. */ - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < this->system->execContexts.size(); i++){ - xc = this->system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif -#endif - -#if FULL_SYSTEM - // @todo: Fix this LL/SC hack. - if (req->flags & LOCKED) { - if (req->flags & UNCACHEABLE) { - req->result = 2; - } else { - if (this->lockFlag) { - req->result = 1; - } else { - req->result = 0; - return NoFault; - } - } - } -#endif - - return this->mem->write(req, (T)htog(data)); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - bool lockFlag; -}; - -#endif // __CPU_O3_ALPHA_FULL_CPU_HH__ diff --git a/cpu/o3/alpha_cpu_builder.cc b/cpu/o3/alpha_cpu_builder.cc deleted file mode 100644 index b0d812edc..000000000 --- a/cpu/o3/alpha_cpu_builder.cc +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "cpu/base.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/fu_pool.hh" -#include "mem/cache/base_cache.hh" -#include "sim/builder.hh" - -class DerivAlphaFullCPU : public AlphaFullCPU<AlphaSimpleImpl> -{ - public: - DerivAlphaFullCPU(AlphaSimpleParams *p) - : AlphaFullCPU<AlphaSimpleImpl>(p) - { } -}; - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - - Param<int> clock; - Param<int> numThreads; -Param<int> activity; - -#if FULL_SYSTEM -SimObjectParam<System *> system; -Param<int> cpu_id; -SimObjectParam<AlphaITB *> itb; -SimObjectParam<AlphaDTB *> dtb; -#else -SimObjectVectorParam<Process *> workload; -//SimObjectParam<PageTable *> page_table; -#endif // FULL_SYSTEM - -SimObjectParam<FunctionalMemory *> mem; - -SimObjectParam<BaseCPU *> checker; - -Param<Counter> max_insts_any_thread; -Param<Counter> max_insts_all_threads; -Param<Counter> max_loads_any_thread; -Param<Counter> max_loads_all_threads; - -SimObjectParam<BaseCache *> icache; -SimObjectParam<BaseCache *> dcache; - -Param<unsigned> cachePorts; - -Param<unsigned> decodeToFetchDelay; -Param<unsigned> renameToFetchDelay; -Param<unsigned> iewToFetchDelay; -Param<unsigned> commitToFetchDelay; -Param<unsigned> fetchWidth; - -Param<unsigned> renameToDecodeDelay; -Param<unsigned> iewToDecodeDelay; -Param<unsigned> commitToDecodeDelay; -Param<unsigned> fetchToDecodeDelay; -Param<unsigned> decodeWidth; - -Param<unsigned> iewToRenameDelay; -Param<unsigned> commitToRenameDelay; -Param<unsigned> decodeToRenameDelay; -Param<unsigned> renameWidth; - -Param<unsigned> commitToIEWDelay; -Param<unsigned> renameToIEWDelay; -Param<unsigned> issueToExecuteDelay; -Param<unsigned> issueWidth; -Param<unsigned> executeWidth; -Param<unsigned> executeIntWidth; -Param<unsigned> executeFloatWidth; -Param<unsigned> executeBranchWidth; -Param<unsigned> executeMemoryWidth; -SimObjectParam<FUPool *> fuPool; - -Param<unsigned> iewToCommitDelay; -Param<unsigned> renameToROBDelay; -Param<unsigned> commitWidth; -Param<unsigned> squashWidth; -Param<Tick> trapLatency; -Param<Tick> fetchTrapLatency; - -Param<unsigned> localPredictorSize; -Param<unsigned> localCtrBits; -Param<unsigned> localHistoryTableSize; -Param<unsigned> localHistoryBits; -Param<unsigned> globalPredictorSize; -Param<unsigned> globalCtrBits; -Param<unsigned> globalHistoryBits; -Param<unsigned> choicePredictorSize; -Param<unsigned> choiceCtrBits; - -Param<unsigned> BTBEntries; -Param<unsigned> BTBTagSize; - -Param<unsigned> RASSize; - -Param<unsigned> LQEntries; -Param<unsigned> SQEntries; -Param<unsigned> LFSTSize; -Param<unsigned> SSITSize; - -Param<unsigned> numPhysIntRegs; -Param<unsigned> numPhysFloatRegs; -Param<unsigned> numIQEntries; -Param<unsigned> numROBEntries; - -Param<unsigned> smtNumFetchingThreads; -Param<std::string> smtFetchPolicy; -Param<std::string> smtLSQPolicy; -Param<unsigned> smtLSQThreshold; -Param<std::string> smtIQPolicy; -Param<unsigned> smtIQThreshold; -Param<std::string> smtROBPolicy; -Param<unsigned> smtROBThreshold; -Param<std::string> smtCommitPolicy; - -Param<unsigned> instShiftAmt; - -Param<bool> defer_registration; - -Param<bool> function_trace; -Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(numThreads, "number of HW thread contexts"), - INIT_PARAM_DFLT(activity, "Initial activity count", 0), - -#if FULL_SYSTEM - INIT_PARAM(system, "System object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(itb, "Instruction translation buffer"), - INIT_PARAM(dtb, "Data translation buffer"), -#else - INIT_PARAM(workload, "Processes to run"), -// INIT_PARAM(page_table, "Page table"), -#endif // FULL_SYSTEM - - INIT_PARAM_DFLT(mem, "Memory", NULL), - - INIT_PARAM_DFLT(checker, "Checker CPU", NULL), - - INIT_PARAM_DFLT(max_insts_any_thread, - "Terminate when any thread reaches this inst count", - 0), - INIT_PARAM_DFLT(max_insts_all_threads, - "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", - 0), - INIT_PARAM_DFLT(max_loads_all_threads, - "Terminate when all threads have reached this load" - "count", - 0), - - INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL), - INIT_PARAM_DFLT(dcache, "L1 data cache", NULL), - - INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), - - INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), - INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), - INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" - "delay"), - INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), - INIT_PARAM(fetchWidth, "Fetch width"), - INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), - INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" - "delay"), - INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), - INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), - INIT_PARAM(decodeWidth, "Decode width"), - - INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" - "delay"), - INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), - INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), - INIT_PARAM(renameWidth, "Rename width"), - - INIT_PARAM(commitToIEWDelay, "Commit to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(renameToIEWDelay, "Rename to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" - "to the IEW stage)"), - INIT_PARAM(issueWidth, "Issue width"), - INIT_PARAM(executeWidth, "Execute width"), - INIT_PARAM(executeIntWidth, "Integer execute width"), - INIT_PARAM(executeFloatWidth, "Floating point execute width"), - INIT_PARAM(executeBranchWidth, "Branch execute width"), - INIT_PARAM(executeMemoryWidth, "Memory execute width"), - INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL), - - INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " - "delay"), - INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), - INIT_PARAM(commitWidth, "Commit width"), - INIT_PARAM(squashWidth, "Squash width"), - INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6), - INIT_PARAM_DFLT(fetchTrapLatency, "Number of cycles before the fetch trap is handled", 12), - - INIT_PARAM(localPredictorSize, "Size of local predictor"), - INIT_PARAM(localCtrBits, "Bits per counter"), - INIT_PARAM(localHistoryTableSize, "Size of local history table"), - INIT_PARAM(localHistoryBits, "Bits for the local history"), - INIT_PARAM(globalPredictorSize, "Size of global predictor"), - INIT_PARAM(globalCtrBits, "Bits per counter"), - INIT_PARAM(globalHistoryBits, "Bits of history"), - INIT_PARAM(choicePredictorSize, "Size of choice predictor"), - INIT_PARAM(choiceCtrBits, "Bits of choice counters"), - - INIT_PARAM(BTBEntries, "Number of BTB entries"), - INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), - - INIT_PARAM(RASSize, "RAS size"), - - INIT_PARAM(LQEntries, "Number of load queue entries"), - INIT_PARAM(SQEntries, "Number of store queue entries"), - INIT_PARAM(LFSTSize, "Last fetched store table size"), - INIT_PARAM(SSITSize, "Store set ID table size"), - - INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), - INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " - "registers"), - INIT_PARAM(numIQEntries, "Number of instruction queue entries"), - INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), - - INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), - INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), - INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), - INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), - INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), - INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), - INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), - - INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - -CREATE_SIM_OBJECT(DerivAlphaFullCPU) -{ - DerivAlphaFullCPU *cpu; - -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - numThreads.isValid() ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } - -#endif - - AlphaSimpleParams *params = new AlphaSimpleParams; - - params->clock = clock; - - params->name = getInstanceName(); - params->numberOfThreads = actual_num_threads; - params->activity = activity; - -#if FULL_SYSTEM - params->system = system; - params->cpu_id = cpu_id; - params->itb = itb; - params->dtb = dtb; -#else - params->workload = workload; -// params->pTable = page_table; -#endif // FULL_SYSTEM - - params->mem = mem; - - params->checker = checker; - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - - // - // Caches - // - params->icacheInterface = icache ? icache->getInterface() : NULL; - params->dcacheInterface = dcache ? dcache->getInterface() : NULL; - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->issueWidth = issueWidth; - params->executeWidth = executeWidth; - params->executeIntWidth = executeIntWidth; - params->executeFloatWidth = executeFloatWidth; - params->executeBranchWidth = executeBranchWidth; - params->executeMemoryWidth = executeMemoryWidth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - params->fetchTrapLatency = fetchTrapLatency; - - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - params->smtFetchPolicy = smtFetchPolicy; - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new DerivAlphaFullCPU(params); - - return cpu; -} - -REGISTER_SIM_OBJECT("DerivAlphaFullCPU", DerivAlphaFullCPU) - diff --git a/cpu/o3/alpha_cpu_impl.hh b/cpu/o3/alpha_cpu_impl.hh deleted file mode 100644 index 91cd3d9e6..000000000 --- a/cpu/o3/alpha_cpu_impl.hh +++ /dev/null @@ -1,776 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/faults.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/exec_context.hh" -#include "mem/mem_interface.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/alpha/osfpal.hh" -#include "arch/isa_traits.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#endif - -using namespace TheISA; - -template <class Impl> -AlphaFullCPU<Impl>::AlphaFullCPU(Params *params) -#if FULL_SYSTEM - : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) -#else - : FullO3CPU<Impl>(params) -#endif -{ - DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n"); - - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0, params->mem); - this->thread[i]->setStatus(ExecContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, " - "process is %#x", - i, params->workload[i]->prog_entry, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - assert(params->workload[i]->getMemory() != NULL); - - this->thread[i]->setStatus(ExecContext::Suspended); - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty execution context so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - this->thread[i]->numInst = 0; - - ExecContext *xc_proxy; - - AlphaXC *alpha_xc_proxy = new AlphaXC; - - if (params->checker) { - xc_proxy = new CheckerExecContext<AlphaXC>(alpha_xc_proxy, this->checker); - } else { - xc_proxy = alpha_xc_proxy; - } - - alpha_xc_proxy->cpu = this; - alpha_xc_proxy->thread = this->thread[i]; - -#if FULL_SYSTEM - this->thread[i]->quiesceEvent = - new EndQuiesceEvent(xc_proxy); - this->thread[i]->lastActivate = 0; - this->thread[i]->lastSuspend = 0; -#endif - this->thread[i]->xcProxy = xc_proxy; - - this->execContexts.push_back(xc_proxy); - } - - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->funcExeInst = 0; - } - - // Sets CPU pointers. These must be set at this level because the CPU - // pointers are defined to be the highest level of CPU class. - this->fetch.setCPU(this); - this->decode.setCPU(this); - this->rename.setCPU(this); - this->iew.setCPU(this); - this->commit.setCPU(this); - - this->rob.setCPU(this); - this->regFile.setCPU(this); - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - -#if FULL_SYSTEM -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::dumpFuncProfile() -{ - // Currently not supported -} -#endif - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::takeOverFrom(ExecContext *old_context) -{ - // some things should already be set up - assert(getMemPtr() == old_context->getMemPtr()); -#if FULL_SYSTEM - assert(getSystemPtr() == old_context->getSystemPtr()); -#else - assert(getProcessPtr() == old_context->getProcessPtr()); -#endif - - // copy over functional state - setStatus(old_context->status()); - copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); -#if !FULL_SYSTEM - thread->funcExeInst = old_context->readFuncExeInst(); -#else - EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); - if (other_quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - other_quiesce->xc = this; - } - if (thread->quiesceEvent) { - thread->quiesceEvent->xc = this; - } - - // Transfer kernel stats from one CPU to the other. - thread->kernelStats = old_context->getKernelStats(); -// storeCondFailures = 0; - cpu->lockFlag = false; -#endif - - old_context->setStatus(ExecContext::Unallocated); - - thread->inSyscall = false; - thread->trapPending = false; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::activate(int delay) -{ - DPRINTF(FullCPU, "Calling activate on AlphaXC\n"); - - if (thread->status() == ExecContext::Active) - return; - -#if FULL_SYSTEM - thread->lastActivate = curTick; -#endif - - if (thread->status() == ExecContext::Unallocated) { - cpu->activateWhenReady(thread->tid); - return; - } - - thread->setStatus(ExecContext::Active); - - // status() == Suspended - cpu->activateContext(thread->tid, delay); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::suspend() -{ - DPRINTF(FullCPU, "Calling suspend on AlphaXC\n"); - - if (thread->status() == ExecContext::Suspended) - return; - -#if FULL_SYSTEM - thread->lastActivate = curTick; - thread->lastSuspend = curTick; -#endif -/* -#if FULL_SYSTEM - // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { - assert(status() == ExecContext::Active); - return; - } -#endif -*/ - thread->setStatus(ExecContext::Suspended); - cpu->suspendContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::deallocate() -{ - DPRINTF(FullCPU, "Calling deallocate on AlphaXC\n"); - - if (thread->status() == ExecContext::Unallocated) - return; - - thread->setStatus(ExecContext::Unallocated); - cpu->deallocateContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::halt() -{ - DPRINTF(FullCPU, "Calling halt on AlphaXC\n"); - - if (thread->status() == ExecContext::Halted) - return; - - thread->setStatus(ExecContext::Halted); - cpu->haltContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::regStats(const std::string &name) -{ -#if FULL_SYSTEM - thread->kernelStats = new Kernel::Statistics(cpu->system); - thread->kernelStats->regStats(name + ".kern"); -#endif -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::serialize(std::ostream &os) -{ -#if FULL_SYSTEM - if (thread->kernelStats) - thread->kernelStats->serialize(os); -#endif - -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::unserialize(Checkpoint *cp, const std::string §ion) -{ -#if FULL_SYSTEM - if (thread->kernelStats) - thread->kernelStats->unserialize(cp, section); -#endif - -} - -#if FULL_SYSTEM -template <class Impl> -EndQuiesceEvent * -AlphaFullCPU<Impl>::AlphaXC::getQuiesceEvent() -{ - return thread->quiesceEvent; -} - -template <class Impl> -Tick -AlphaFullCPU<Impl>::AlphaXC::readLastActivate() -{ - return thread->lastActivate; -} - -template <class Impl> -Tick -AlphaFullCPU<Impl>::AlphaXC::readLastSuspend() -{ - return thread->lastSuspend; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::profileClear() -{} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::profileSample() -{} -#endif - -template <class Impl> -TheISA::MachInst -AlphaFullCPU<Impl>::AlphaXC:: getInst() -{ - return thread->inst; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::copyArchRegs(ExecContext *xc) -{ - // This function will mess things up unless the ROB is empty and - // there are no instructions in the pipeline. - unsigned tid = thread->tid; - PhysRegIndex renamed_reg; - - // First loop through the integer registers. - for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i); - - DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, " - "now has data %lli.\n", - renamed_reg, cpu->readIntReg(renamed_reg), - xc->readIntReg(i)); - - cpu->setIntReg(renamed_reg, xc->readIntReg(i)); - } - - // Then loop through the floating point registers. - for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i + AlphaISA::FP_Base_DepTag); - cpu->setFloatRegDouble(renamed_reg, - xc->readFloatRegDouble(i)); - cpu->setFloatRegInt(renamed_reg, - xc->readFloatRegInt(i)); - } - - // Copy the misc regs. - cpu->regFile.miscRegs[tid].copyMiscRegs(xc); - - // Then finally set the PC and the next PC. - cpu->setPC(xc->readPC(), tid); - cpu->setNextPC(xc->readNextPC(), tid); -#if !FULL_SYSTEM - this->thread->funcExeInst = xc->readFuncExeInst(); -#endif -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::clearArchRegs() -{} - -template <class Impl> -uint64_t -AlphaFullCPU<Impl>::AlphaXC::readIntReg(int reg_idx) -{ - DPRINTF(Fault, "Reading int register through the XC!\n"); - return cpu->readArchIntReg(reg_idx, thread->tid); -} - -template <class Impl> -float -AlphaFullCPU<Impl>::AlphaXC::readFloatRegSingle(int reg_idx) -{ - DPRINTF(Fault, "Reading float register through the XC!\n"); - return cpu->readArchFloatRegSingle(reg_idx, thread->tid); -} - -template <class Impl> -double -AlphaFullCPU<Impl>::AlphaXC::readFloatRegDouble(int reg_idx) -{ - DPRINTF(Fault, "Reading float register through the XC!\n"); - return cpu->readArchFloatRegDouble(reg_idx, thread->tid); -} - -template <class Impl> -uint64_t -AlphaFullCPU<Impl>::AlphaXC::readFloatRegInt(int reg_idx) -{ - DPRINTF(Fault, "Reading floatint register through the XC!\n"); - return cpu->readArchFloatRegInt(reg_idx, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setIntReg(int reg_idx, uint64_t val) -{ - DPRINTF(Fault, "Setting int register through the XC!\n"); - cpu->setArchIntReg(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegSingle(int reg_idx, float val) -{ - DPRINTF(Fault, "Setting float register through the XC!\n"); - cpu->setArchFloatRegSingle(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegDouble(int reg_idx, double val) -{ - DPRINTF(Fault, "Setting float register through the XC!\n"); - cpu->setArchFloatRegDouble(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegInt(int reg_idx, uint64_t val) -{ - DPRINTF(Fault, "Setting floatint register through the XC!\n"); - cpu->setArchFloatRegInt(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setPC(uint64_t val) -{ - cpu->setPC(val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setNextPC(uint64_t val) -{ - cpu->setNextPC(val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::AlphaXC::setMiscReg(int misc_reg, const MiscReg &val) -{ - DPRINTF(Fault, "Setting misc register through the XC!\n"); - - Fault ret_fault = cpu->setMiscReg(misc_reg, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } - - return ret_fault; -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::AlphaXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) -{ - DPRINTF(Fault, "Setting misc register through the XC!\n"); - - Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } - - return ret_fault; -} - -#if !FULL_SYSTEM - -template <class Impl> -TheISA::IntReg -AlphaFullCPU<Impl>::AlphaXC::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->tid); -} - -#endif // FULL_SYSTEM - -template <class Impl> -MiscReg -AlphaFullCPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -MiscReg -AlphaFullCPU<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault, - unsigned tid) -{ - return this->regFile.readMiscRegWithEffect(misc_reg, fault, tid); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) -{ - return this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned tid) -{ - return this->regFile.setMiscRegWithEffect(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::squashFromXC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateXCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -AlphaFullCPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); -// xcProxies[0]->activate(); - this->execContexts[0]->activate(); - } -} - -template <class Impl> -int -AlphaFullCPU<Impl>::readIntrFlag() -{ - return this->regFile.readIntrFlag(); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setIntrFlag(int val) -{ - this->regFile.setIntrFlag(val); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::hwrei(unsigned tid) -{ - // Need to clear the lock flag upon returning from an interrupt. - this->lockFlag = false; - - this->thread[tid]->kernelStats->hwrei(); - - this->checkInterrupts = true; - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -bool -AlphaFullCPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->execContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } - - return true; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::trap(Fault fault, unsigned tid) -{ - fault->invoke(this->execContexts[tid]); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::processInterrupts() -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - // Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - this->checkInterrupts = false; - - if (this->readMiscReg(IPR_ASTRR, 0)) - panic("asynchronous traps not implemented\n"); - - if (this->readMiscReg(IPR_SIRR, 0)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (this->readMiscReg(IPR_SIRR, 0) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = this->intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > this->readMiscReg(IPR_IPLR, 0)) { - this->setMiscReg(IPR_ISR, summary, 0); - this->setMiscReg(IPR_INTID, ipl, 0); - if (this->checker) { - this->checker->cpuXCBase()->setMiscReg(IPR_ISR, summary); - this->checker->cpuXCBase()->setMiscReg(IPR_INTID, ipl); - } - this->trap(Fault(new InterruptFault), 0); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - this->readMiscReg(IPR_IPLR, 0), ipl, summary); - } -} - -#endif // FULL_SYSTEM - -#if !FULL_SYSTEM - -template <class Impl> -void -AlphaFullCPU<Impl>::syscall(int tid) -{ - DPRINTF(FullCPU, "AlphaFullCPU: [tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -AlphaFullCPU<Impl>::getSyscallArg(int i, int tid) -{ - return this->readArchIntReg(AlphaISA::ArgumentReg0 + i, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setSyscallArg(int i, IntReg val, int tid) -{ - this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - this->setArchIntReg(SyscallSuccessReg, 0, tid); - this->setArchIntReg(ReturnValueReg, return_value.value(), tid); - } else { - // got an error, return details - this->setArchIntReg(SyscallSuccessReg, (IntReg) -1, tid); - this->setArchIntReg(ReturnValueReg, -return_value.value(), tid); - } -} -#endif diff --git a/cpu/o3/alpha_dyn_inst.cc b/cpu/o3/alpha_dyn_inst.cc deleted file mode 100644 index 72ac77d95..000000000 --- a/cpu/o3/alpha_dyn_inst.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst_impl.hh" -#include "cpu/o3/alpha_impl.hh" - -// Force instantiation of AlphaDynInst for all the implementations that -// are needed. -template class AlphaDynInst<AlphaSimpleImpl>; diff --git a/cpu/o3/alpha_dyn_inst.hh b/cpu/o3/alpha_dyn_inst.hh deleted file mode 100644 index 1c5b738aa..000000000 --- a/cpu/o3/alpha_dyn_inst.hh +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ -#define __CPU_O3_ALPHA_DYN_INST_HH__ - -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" - -/** - * Mostly implementation & ISA specific AlphaDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The AlphaDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class AlphaDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::FullCPU FullCPU; - - /** Binary machine instruction type. */ - typedef TheISA::MachInst MachInst; - /** Extended machine instruction type. */ - typedef TheISA::ExtMachInst ExtMachInst; - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num, - FullCPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - AlphaDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(); - - private: - /** Initializes variables. */ - void initVars(); - - public: - MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return this->cpu->readMiscRegWithEffect(misc_reg, fault, - this->threadNumber); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return this->cpu->setMiscRegWithEffect(misc_reg, val, - this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Reads interrupt flag. */ - int readIntrFlag(); - /** Sets interrupt flag. */ - void setIntrFlag(int val); - /** Checks if system is in PAL mode. */ - bool inPalMode(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(); -#endif - - private: - /** Physical register index of the destination registers of this - * instruction. - */ - PhysRegIndex _destRegIdx[MaxInstDestRegs]; - - /** Physical register index of the source registers of this - * instruction. - */ - PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** Physical register index of the previous producers of the - * architected destinations. - */ - PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntReg(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(_srcRegIdx[idx]); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegSingle(_srcRegIdx[idx]); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegDouble(_srcRegIdx[idx]); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegInt(_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntReg(si, idx, val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - this->cpu->setFloatRegSingle(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegSingle(si, idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - this->cpu->setFloatRegDouble(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegDouble(si, idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setFloatRegInt(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegInt(si, idx, val); - } - - /** Returns the physical register index of the i'th destination - * register. - */ - PhysRegIndex renamedDestRegIdx(int idx) const - { - return _destRegIdx[idx]; - } - - /** Returns the physical register index of the i'th source register. */ - PhysRegIndex renamedSrcRegIdx(int idx) const - { - return _srcRegIdx[idx]; - } - - /** Returns the physical register index of the previous physical register - * that remapped to the same logical register index. - */ - PhysRegIndex prevDestRegIdx(int idx) const - { - return _prevDestRegIdx[idx]; - } - - /** Renames a destination register to a physical register. Also records - * the previous physical register that the logical register mapped to. - */ - void renameDestReg(int idx, - PhysRegIndex renamed_dest, - PhysRegIndex previous_rename) - { - _destRegIdx[idx] = renamed_dest; - _prevDestRegIdx[idx] = previous_rename; - } - - /** Renames a source logical register to the physical register which - * has/will produce that logical register's result. - * @todo: add in whether or not the source register is ready. - */ - void renameSrcReg(int idx, PhysRegIndex renamed_src) - { - _srcRegIdx[idx] = renamed_src; - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_ALPHA_DYN_INST_HH__ - diff --git a/cpu/o3/alpha_dyn_inst_impl.hh b/cpu/o3/alpha_dyn_inst_impl.hh deleted file mode 100644 index 541d5ab82..000000000 --- a/cpu/o3/alpha_dyn_inst_impl.hh +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" - -template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, - InstSeqNum seq_num, FullCPU *cpu) - : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initVars(); -} - -template <class Impl> -void -AlphaDynInst<Impl>::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - _destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - _srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template <class Impl> -Fault -AlphaDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening when using - // the XC during an instruction's execution (specifically for instructions - // that have sideeffects that use the XC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -AlphaDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening when using - // the XC during an instruction's execution (specifically for instructions - // that have sideeffects that use the XC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -AlphaDynInst<Impl>::completeAcc() -{ - if (this->isLoad()) { - this->fault = this->staticInst->completeAcc(this->req->data, - this, - this->traceData); - } else if (this->isStore()) { - this->fault = this->staticInst->completeAcc((uint8_t*)&this->req->result, - this, - this->traceData); - } else { - panic("Unknown type!"); - } - - return this->fault; -} - -#if FULL_SYSTEM -template <class Impl> -Fault -AlphaDynInst<Impl>::hwrei() -{ - if (!this->cpu->inPalMode(this->readPC())) - return new AlphaISA::UnimplementedOpcodeFault; - - this->setNextPC(this->cpu->readMiscReg(AlphaISA::IPR_EXC_ADDR, - this->threadNumber)); - - // Tell CPU to clear any state it needs to if a hwrei is taken. - this->cpu->hwrei(this->threadNumber); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -int -AlphaDynInst<Impl>::readIntrFlag() -{ - return this->cpu->readIntrFlag(); -} - -template <class Impl> -void -AlphaDynInst<Impl>::setIntrFlag(int val) -{ - this->cpu->setIntrFlag(val); -} - -template <class Impl> -bool -AlphaDynInst<Impl>::inPalMode() -{ - return this->cpu->inPalMode(this->PC); -} - -template <class Impl> -void -AlphaDynInst<Impl>::trap(Fault fault) -{ - this->cpu->trap(fault, this->threadNumber); -} - -template <class Impl> -bool -AlphaDynInst<Impl>::simPalCheck(int palFunc) -{ - return this->cpu->simPalCheck(palFunc, this->threadNumber); -} -#else -template <class Impl> -void -AlphaDynInst<Impl>::syscall() -{ - this->cpu->syscall(this->threadNumber); -} -#endif - diff --git a/cpu/o3/alpha_impl.hh b/cpu/o3/alpha_impl.hh deleted file mode 100644 index f404bd3ec..000000000 --- a/cpu/o3/alpha_impl.hh +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_IMPL_HH__ -#define __CPU_O3_ALPHA_IMPL_HH__ - -#include "arch/alpha/isa_traits.hh" - -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/cpu_policy.hh" - -// Forward declarations. -template <class Impl> -class AlphaDynInst; - -template <class Impl> -class AlphaFullCPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific FullCPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct AlphaSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol; - - /** The DynInst type to be used. */ - typedef AlphaDynInst<AlphaSimpleImpl> DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr<DynInst> DynInstPtr; - - /** The FullCPU type to be used. */ - typedef AlphaFullCPU<AlphaSimpleImpl> FullCPU; - - /** The Params to be passed to each stage. */ - typedef AlphaSimpleParams Params; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -#endif // __CPU_O3_ALPHA_IMPL_HH__ diff --git a/cpu/o3/alpha_params.hh b/cpu/o3/alpha_params.hh deleted file mode 100644 index e3acf2c05..000000000 --- a/cpu/o3/alpha_params.hh +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_PARAMS_HH__ -#define __CPU_O3_ALPHA_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" - -//Forward declarations -class AlphaDTB; -class AlphaITB; -class FUPool; -class FunctionalMemory; -class MemInterface; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaFullCPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ - -class AlphaSimpleParams : public BaseFullCPU::Params -{ - public: - -#if FULL_SYSTEM - AlphaITB *itb; AlphaDTB *dtb; -#else - std::vector<Process *> workload; - Process *process; -#endif // FULL_SYSTEM - - //Page Table -// PageTable *pTable; - - FunctionalMemory *mem; - - BaseCPU *checker; - - unsigned activity; - - // - // Caches - // - MemInterface *icacheInterface; - MemInterface *dcacheInterface; - - unsigned cachePorts; - - // - // Fetch - // - unsigned decodeToFetchDelay; - unsigned renameToFetchDelay; - unsigned iewToFetchDelay; - unsigned commitToFetchDelay; - unsigned fetchWidth; - - // - // Decode - // - unsigned renameToDecodeDelay; - unsigned iewToDecodeDelay; - unsigned commitToDecodeDelay; - unsigned fetchToDecodeDelay; - unsigned decodeWidth; - - // - // Rename - // - unsigned iewToRenameDelay; - unsigned commitToRenameDelay; - unsigned decodeToRenameDelay; - unsigned renameWidth; - - // - // IEW - // - unsigned commitToIEWDelay; - unsigned renameToIEWDelay; - unsigned issueToExecuteDelay; - unsigned issueWidth; - unsigned executeWidth; - unsigned executeIntWidth; - unsigned executeFloatWidth; - unsigned executeBranchWidth; - unsigned executeMemoryWidth; - FUPool *fuPool; - - // - // Commit - // - unsigned iewToCommitDelay; - unsigned renameToROBDelay; - unsigned commitWidth; - unsigned squashWidth; - Tick trapLatency; - Tick fetchTrapLatency; - - // - // Branch predictor (BP & BTB) - // - unsigned localPredictorSize; - unsigned localCtrBits; - unsigned localHistoryTableSize; - unsigned localHistoryBits; - unsigned globalPredictorSize; - unsigned globalCtrBits; - unsigned globalHistoryBits; - unsigned choicePredictorSize; - unsigned choiceCtrBits; - - unsigned BTBEntries; - unsigned BTBTagSize; - - unsigned RASSize; - - // - // Load store queue - // - unsigned LQEntries; - unsigned SQEntries; - - // - // Memory dependence - // - unsigned SSITSize; - unsigned LFSTSize; - - // - // Miscellaneous - // - unsigned numPhysIntRegs; - unsigned numPhysFloatRegs; - unsigned numIQEntries; - unsigned numROBEntries; - - //SMT Parameters - unsigned smtNumFetchingThreads; - - std::string smtFetchPolicy; - - std::string smtIQPolicy; - unsigned smtIQThreshold; - - std::string smtLSQPolicy; - unsigned smtLSQThreshold; - - std::string smtCommitPolicy; - - std::string smtROBPolicy; - unsigned smtROBThreshold; - - // Probably can get this from somewhere. - unsigned instShiftAmt; -}; - -#endif // __CPU_O3_ALPHA_PARAMS_HH__ diff --git a/cpu/o3/bpred_unit.cc b/cpu/o3/bpred_unit.cc deleted file mode 100644 index 92344111f..000000000 --- a/cpu/o3/bpred_unit.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/bpred_unit_impl.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class TwobitBPredUnit<AlphaSimpleImpl>; -template class TwobitBPredUnit<OzoneImpl>; -template class TwobitBPredUnit<SimpleImpl>; diff --git a/cpu/o3/bpred_unit.hh b/cpu/o3/bpred_unit.hh deleted file mode 100644 index b7814b2e9..000000000 --- a/cpu/o3/bpred_unit.hh +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_BPRED_UNIT_HH__ -#define __CPU_O3_BPRED_UNIT_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include "base/statistics.hh" -#include "cpu/inst_seq.hh" - -#include "cpu/o3/2bit_local_pred.hh" -#include "cpu/o3/btb.hh" -#include "cpu/o3/ras.hh" -#include "cpu/o3/tournament_pred.hh" - -#include <list> - -/** - * Basically a wrapper class to hold both the branch predictor - * and the BTB. - */ -template<class Impl> -class TwobitBPredUnit -{ - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - /** - * @param params The params object, that has the size of the BP and BTB. - */ - TwobitBPredUnit(Params *params); - - /** - * Registers statistics. - */ - void regStats(); - - void switchOut(); - - void takeOverFrom(); - - /** - * Predicts whether or not the instruction is a taken branch, and the - * target of the branch if it is taken. - * @param inst The branch instruction. - * @param PC The predicted PC is passed back through this parameter. - * @param tid The thread id. - * @return Returns if the branch is taken or not. - */ - bool predict(DynInstPtr &inst, Addr &PC, unsigned tid); - - /** - * Tells the branch predictor to commit any updates until the given - * sequence number. - * @param done_sn The sequence number to commit any older updates up until. - * @param tid The thread id. - */ - void update(const InstSeqNum &done_sn, unsigned tid); - - /** - * Squashes all outstanding updates until a given sequence number. - * @param squashed_sn The sequence number to squash any younger updates up - * until. - * @param tid The thread id. - */ - void squash(const InstSeqNum &squashed_sn, unsigned tid); - - /** - * Squashes all outstanding updates until a given sequence number, and - * corrects that sn's update with the proper address and taken/not taken. - * @param squashed_sn The sequence number to squash any younger updates up - * until. - * @param corr_target The correct branch target. - * @param actually_taken The correct branch direction. - * @param tid The thread id. - */ - void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, - bool actually_taken, unsigned tid); - - /** - * Looks up a given PC in the BP to see if it is taken or not taken. - * @param inst_PC The PC to look up. - * @return Whether the branch is taken or not taken. - */ - bool BPLookup(Addr &inst_PC) - { return BP.lookup(inst_PC); } - - /** - * Looks up a given PC in the BTB to see if a matching entry exists. - * @param inst_PC The PC to look up. - * @return Whether the BTB contains the given PC. - */ - bool BTBValid(Addr &inst_PC) - { return BTB.valid(inst_PC, 0); } - - /** - * Looks up a given PC in the BTB to get the predicted target. - * @param inst_PC The PC to look up. - * @return The address of the target of the branch. - */ - Addr BTBLookup(Addr &inst_PC) - { return BTB.lookup(inst_PC, 0); } - - /** - * Updates the BP with taken/not taken information. - * @param inst_PC The branch's PC that will be updated. - * @param taken Whether the branch was taken or not taken. - * @todo Make this update flexible enough to handle a global predictor. - */ - void BPUpdate(Addr &inst_PC, bool taken) - { BP.update(inst_PC, taken); } - - /** - * Updates the BTB with the target of a branch. - * @param inst_PC The branch's PC that will be updated. - * @param target_PC The branch's target that will be added to the BTB. - */ - void BTBUpdate(Addr &inst_PC, Addr &target_PC) - { BTB.update(inst_PC, target_PC,0); } - - private: - struct PredictorHistory { - /** - * Makes a predictor history struct that contains a sequence number, - * the PC of its instruction, and whether or not it was predicted - * taken. - */ - PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC, - const bool pred_taken, const unsigned _tid) - : seqNum(seq_num), PC(inst_PC), RASTarget(0), globalHistory(0), - RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), - wasCall(0) - { } - - /** The sequence number for the predictor history entry. */ - InstSeqNum seqNum; - - /** The PC associated with the sequence number. */ - Addr PC; - - /** The RAS target (only valid if a return). */ - Addr RASTarget; - - /** The global history at the time this entry was created. */ - unsigned globalHistory; - - /** The RAS index of the instruction (only valid if a call). */ - unsigned RASIndex; - - /** The thread id. */ - unsigned tid; - - /** Whether or not it was predicted taken. */ - bool predTaken; - - /** Whether or not the RAS was used. */ - bool usedRAS; - - /** Whether or not the instruction was a call. */ - bool wasCall; - }; - - typedef std::list<PredictorHistory> History; - - /** - * The per-thread predictor history. This is used to update the predictor - * as instructions are committed, or restore it to the proper state after - * a squash. - */ - History predHist[Impl::MaxThreads]; - - /** The branch predictor. */ - DefaultBP BP; - - /** The BTB. */ - DefaultBTB BTB; - - /** The per-thread return address stack. */ - ReturnAddrStack RAS[Impl::MaxThreads]; - - /** Stat for number of BP lookups. */ - Stats::Scalar<> lookups; - /** Stat for number of conditional branches predicted. */ - Stats::Scalar<> condPredicted; - /** Stat for number of conditional branches predicted incorrectly. */ - Stats::Scalar<> condIncorrect; - /** Stat for number of BTB lookups. */ - Stats::Scalar<> BTBLookups; - /** Stat for number of BTB hits. */ - Stats::Scalar<> BTBHits; - /** Stat for number of times the BTB is correct. */ - Stats::Scalar<> BTBCorrect; - /** Stat for number of times the RAS is used to get a target. */ - Stats::Scalar<> usedRAS; - /** Stat for number of times the RAS is incorrect. */ - Stats::Scalar<> RASIncorrect; -}; - -#endif // __CPU_O3_BPRED_UNIT_HH__ diff --git a/cpu/o3/bpred_unit_impl.hh b/cpu/o3/bpred_unit_impl.hh deleted file mode 100644 index c37df606b..000000000 --- a/cpu/o3/bpred_unit_impl.hh +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> -#include <vector> - -#include "base/trace.hh" -#include "base/traceflags.hh" -#include "cpu/o3/bpred_unit.hh" - -using namespace std; - -template<class Impl> -TwobitBPredUnit<Impl>::TwobitBPredUnit(Params *params) - : BP(params->localPredictorSize, - params->localCtrBits, - params->instShiftAmt), - BTB(params->BTBEntries, - params->BTBTagSize, - params->instShiftAmt) -{ - for (int i=0; i < Impl::MaxThreads; i++) - RAS[i].init(params->RASSize); -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::regStats() -{ - lookups - .name(name() + ".BPredUnit.lookups") - .desc("Number of BP lookups") - ; - - condPredicted - .name(name() + ".BPredUnit.condPredicted") - .desc("Number of conditional branches predicted") - ; - - condIncorrect - .name(name() + ".BPredUnit.condIncorrect") - .desc("Number of conditional branches incorrect") - ; - - BTBLookups - .name(name() + ".BPredUnit.BTBLookups") - .desc("Number of BTB lookups") - ; - - BTBHits - .name(name() + ".BPredUnit.BTBHits") - .desc("Number of BTB hits") - ; - - BTBCorrect - .name(name() + ".BPredUnit.BTBCorrect") - .desc("Number of correct BTB predictions (this stat may not " - "work properly.") - ; - - usedRAS - .name(name() + ".BPredUnit.usedRAS") - .desc("Number of times the RAS was used to get a target.") - ; - - RASIncorrect - .name(name() + ".BPredUnit.RASInCorrect") - .desc("Number of incorrect RAS predictions.") - ; -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::switchOut() -{ - for (int i = 0; i < Impl::MaxThreads; ++i) { - predHist[i].clear(); - } -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::takeOverFrom() -{ -/* - for (int i = 0; i < Impl::MaxThreads; ++i) - RAS[i].reset(); - - BP.reset(); - BTB.reset(); -*/ -} - -template <class Impl> -bool -TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid) -{ - // See if branch predictor predicts taken. - // If so, get its target addr either from the BTB or the RAS. - // Once that's done, speculatively update the predictor? - // Save off record of branch stuff so the RAS can be fixed - // up once it's done. - - using TheISA::MachInst; - - bool pred_taken = false; - Addr target; - - ++lookups; - - if (inst->isUncondCtrl()) { - DPRINTF(Fetch, "BranchPred: [tid:%i] Unconditional control.\n", tid); - pred_taken = true; - } else { - ++condPredicted; - - pred_taken = BPLookup(PC); - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i " - "for PC %#x\n", - tid, pred_taken, inst->readPC()); - } - - PredictorHistory predict_record(inst->seqNum, PC, pred_taken, tid); - - // Now lookup in the BTB or RAS. - if (pred_taken) { - if (inst->isReturn()) { - ++usedRAS; - - // If it's a function return call, then look up the address - // in the RAS. - target = RAS[tid].top(); - - // Record the top entry of the RAS, and its index. - predict_record.usedRAS = true; - predict_record.RASIndex = RAS[tid].topIdx(); - predict_record.RASTarget = target; - - assert(predict_record.RASIndex < 16); - - RAS[tid].pop(); - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, " - "RAS predicted target: %#x, RAS index: %i.\n", - tid, inst->readPC(), target, predict_record.RASIndex); - } else { - ++BTBLookups; - - if (inst->isCall()) { - RAS[tid].push(PC + sizeof(MachInst)); - - // Record that it was a call so that the top RAS entry can - // be popped off if the speculation is incorrect. - predict_record.wasCall = true; - - DPRINTF(Fetch, "BranchPred: [tid:%i] Instruction %#x was a call" - ", adding %#x to the RAS.\n", - tid, inst->readPC(), PC + sizeof(MachInst)); - } - - if (BTB.valid(PC, tid)) { - ++BTBHits; - - //If it's anything else, use the BTB to get the target addr. - target = BTB.lookup(PC, tid); - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted" - " target is %#x.\n", - tid, inst->readPC(), target); - - } else { - DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a " - "valid entry.\n",tid); - pred_taken = false; - } - - } - } - - if (pred_taken) { - // Set the PC and the instruction's predicted target. - PC = target; - inst->setPredTarg(target); - } else { - PC = PC + sizeof(MachInst); - inst->setPredTarg(PC); - } - - predHist[tid].push_front(predict_record); - - DPRINTF(Fetch, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size()); - - return pred_taken; -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid) -{ - DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until sequence" - "number %lli.\n", tid, done_sn); - - while (!predHist[tid].empty() && - predHist[tid].back().seqNum <= done_sn) { - // Update the branch predictor with the correct results. - BP.update(predHist[tid].back().PC, - predHist[tid].back().predTaken); - - predHist[tid].pop_back(); - } -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid) -{ - History &pred_hist = predHist[tid]; - - while (!pred_hist.empty() && - pred_hist.front().seqNum > squashed_sn) { - if (pred_hist.front().usedRAS) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i," - " target: %#x.\n", - tid, - pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - - RAS[tid].restore(pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - - } else if (pred_hist.front().wasCall) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry added " - "to the RAS.\n",tid); - - RAS[tid].pop(); - } - - pred_hist.pop_front(); - } - -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, - const Addr &corr_target, - const bool actually_taken, - unsigned tid) -{ - // Now that we know that a branch was mispredicted, we need to undo - // all the branches that have been seen up until this branch and - // fix up everything. - - History &pred_hist = predHist[tid]; - - ++condIncorrect; - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, " - "setting target to %#x.\n", - tid, squashed_sn, corr_target); - - while (!pred_hist.empty() && - pred_hist.front().seqNum > squashed_sn) { - if (pred_hist.front().usedRAS) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i, " - "target: %#x.\n", - tid, - pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - - RAS[tid].restore(pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - } else if (pred_hist.front().wasCall) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry" - " added to the RAS.\n", tid); - - RAS[tid].pop(); - } - - pred_hist.pop_front(); - } - - // If there's a squash due to a syscall, there may not be an entry - // corresponding to the squash. In that case, don't bother trying to - // fix up the entry. - if (!pred_hist.empty()) { - pred_hist.front().predTaken = actually_taken; - - if (pred_hist.front().usedRAS) { - ++RASIncorrect; - } - - BP.update(pred_hist.front().PC, actually_taken); - - BTB.update(pred_hist.front().PC, corr_target, tid); - pred_hist.pop_front(); - } -} diff --git a/cpu/o3/btb.cc b/cpu/o3/btb.cc deleted file mode 100644 index e5f69043a..000000000 --- a/cpu/o3/btb.cc +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/intmath.hh" -#include "base/trace.hh" -#include "cpu/o3/btb.hh" - -using namespace TheISA; - -DefaultBTB::DefaultBTB(unsigned _numEntries, - unsigned _tagBits, - unsigned _instShiftAmt) - : numEntries(_numEntries), - tagBits(_tagBits), - instShiftAmt(_instShiftAmt) -{ - DPRINTF(Fetch, "BTB: Creating BTB object.\n"); - - if (!isPowerOf2(numEntries)) { - fatal("BTB entries is not a power of 2!"); - } - - btb.resize(numEntries); - - for (int i = 0; i < numEntries; ++i) { - btb[i].valid = false; - } - - idxMask = numEntries - 1; - - tagMask = (1 << tagBits) - 1; - - tagShiftAmt = instShiftAmt + floorLog2(numEntries); -} - -void -DefaultBTB::reset() -{ - for (int i = 0; i < numEntries; ++i) { - btb[i].valid = false; - } -} - -inline -unsigned -DefaultBTB::getIndex(const Addr &inst_PC) -{ - // Need to shift PC over by the word offset. - return (inst_PC >> instShiftAmt) & idxMask; -} - -inline -Addr -DefaultBTB::getTag(const Addr &inst_PC) -{ - return (inst_PC >> tagShiftAmt) & tagMask; -} - -bool -DefaultBTB::valid(const Addr &inst_PC, unsigned tid) -{ - unsigned btb_idx = getIndex(inst_PC); - - Addr inst_tag = getTag(inst_PC); - - assert(btb_idx < numEntries); - - if (btb[btb_idx].valid - && inst_tag == btb[btb_idx].tag - && btb[btb_idx].tid == tid) { - return true; - } else { - return false; - } -} - -// @todo Create some sort of return struct that has both whether or not the -// address is valid, and also the address. For now will just use addr = 0 to -// represent invalid entry. -Addr -DefaultBTB::lookup(const Addr &inst_PC, unsigned tid) -{ - unsigned btb_idx = getIndex(inst_PC); - - Addr inst_tag = getTag(inst_PC); - - assert(btb_idx < numEntries); - - if (btb[btb_idx].valid - && inst_tag == btb[btb_idx].tag - && btb[btb_idx].tid == tid) { - return btb[btb_idx].target; - } else { - return 0; - } -} - -void -DefaultBTB::update(const Addr &inst_PC, const Addr &target, unsigned tid) -{ - unsigned btb_idx = getIndex(inst_PC); - - assert(btb_idx < numEntries); - - btb[btb_idx].tid = tid; - btb[btb_idx].valid = true; - btb[btb_idx].target = target; - btb[btb_idx].tag = getTag(inst_PC); -} diff --git a/cpu/o3/btb.hh b/cpu/o3/btb.hh deleted file mode 100644 index b9ff42573..000000000 --- a/cpu/o3/btb.hh +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_BTB_HH__ -#define __CPU_O3_BTB_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" - -class DefaultBTB -{ - private: - struct BTBEntry - { - BTBEntry() - : tag(0), target(0), valid(false) - { - } - - /** The entry's tag. */ - Addr tag; - - /** The entry's target. */ - Addr target; - - /** The entry's thread id. */ - unsigned tid; - - /** Whether or not the entry is valid. */ - bool valid; - }; - - public: - /** Creates a BTB with the given number of entries, number of bits per - * tag, and instruction offset amount. - * @param numEntries Number of entries for the BTB. - * @param tagBits Number of bits for each tag in the BTB. - * @param instShiftAmt Offset amount for instructions to ignore alignment. - */ - DefaultBTB(unsigned numEntries, unsigned tagBits, - unsigned instShiftAmt); - - void reset(); - - /** Looks up an address in the BTB. Must call valid() first on the address. - * @param inst_PC The address of the branch to look up. - * @param tid The thread id. - * @return Returns the target of the branch. - */ - Addr lookup(const Addr &inst_PC, unsigned tid); - - /** Checks if a branch is in the BTB. - * @param inst_PC The address of the branch to look up. - * @param tid The thread id. - * @return Whether or not the branch exists in the BTB. - */ - bool valid(const Addr &inst_PC, unsigned tid); - - /** Updates the BTB with the target of a branch. - * @param inst_PC The address of the branch being updated. - * @param target_PC The target address of the branch. - * @param tid The thread id. - */ - void update(const Addr &inst_PC, const Addr &target_PC, - unsigned tid); - - private: - /** Returns the index into the BTB, based on the branch's PC. - * @param inst_PC The branch to look up. - * @return Returns the index into the BTB. - */ - inline unsigned getIndex(const Addr &inst_PC); - - /** Returns the tag bits of a given address. - * @param inst_PC The branch's address. - * @return Returns the tag bits. - */ - inline Addr getTag(const Addr &inst_PC); - - /** The actual BTB. */ - std::vector<BTBEntry> btb; - - /** The number of entries in the BTB. */ - unsigned numEntries; - - /** The index mask. */ - unsigned idxMask; - - /** The number of tag bits per entry. */ - unsigned tagBits; - - /** The tag mask. */ - unsigned tagMask; - - /** Number of bits to shift PC when calculating index. */ - unsigned instShiftAmt; - - /** Number of bits to shift PC when calculating tag. */ - unsigned tagShiftAmt; -}; - -#endif // __CPU_O3_BTB_HH__ diff --git a/cpu/o3/comm.hh b/cpu/o3/comm.hh deleted file mode 100644 index c36c58d3d..000000000 --- a/cpu/o3/comm.hh +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_COMM_HH__ -#define __CPU_O3_COMM_HH__ - -#include <vector> - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" -#include "sim/host.hh" - -// Typedef for physical register index type. Although the Impl would be the -// most likely location for this, there are a few classes that need this -// typedef yet are not templated on the Impl. For now it will be defined here. -typedef short int PhysRegIndex; - -template<class Impl> -struct DefaultFetchDefaultDecode { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; - Fault fetchFault; - InstSeqNum fetchFaultSN; - bool clearFetchFault; -}; - -template<class Impl> -struct DefaultDecodeDefaultRename { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; -}; - -template<class Impl> -struct DefaultRenameDefaultIEW { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; -}; - -template<class Impl> -struct DefaultIEWDefaultCommit { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; - - bool squash[Impl::MaxThreads]; - bool branchMispredict[Impl::MaxThreads]; - bool branchTaken[Impl::MaxThreads]; - uint64_t mispredPC[Impl::MaxThreads]; - uint64_t nextPC[Impl::MaxThreads]; - InstSeqNum squashedSeqNum[Impl::MaxThreads]; - - bool includeSquashInst[Impl::MaxThreads]; -}; - -template<class Impl> -struct IssueStruct { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; -}; - -template<class Impl> -struct TimeBufStruct { - struct decodeComm { - bool squash; - bool predIncorrect; - uint64_t branchAddr; - - InstSeqNum doneSeqNum; - - // @todo: Might want to package this kind of branch stuff into a single - // struct as it is used pretty frequently. - bool branchMispredict; - bool branchTaken; - uint64_t mispredPC; - uint64_t nextPC; - - unsigned branchCount; - }; - - decodeComm decodeInfo[Impl::MaxThreads]; - - // Rename can't actually tell anything to squash or send a new PC back - // because it doesn't do anything along those lines. But maybe leave - // these fields in here to keep the stages mostly orthagonal. - struct renameComm { - bool squash; - - uint64_t nextPC; - }; - - renameComm renameInfo[Impl::MaxThreads]; - - struct iewComm { - // Also eventually include skid buffer space. - bool usedIQ; - unsigned freeIQEntries; - bool usedLSQ; - unsigned freeLSQEntries; - - unsigned iqCount; - unsigned ldstqCount; - - unsigned dispatched; - unsigned dispatchedToLSQ; - }; - - iewComm iewInfo[Impl::MaxThreads]; - - struct commitComm { - bool usedROB; - unsigned freeROBEntries; - bool emptyROB; - - bool squash; - bool robSquashing; - - bool branchMispredict; - bool branchTaken; - uint64_t mispredPC; - uint64_t nextPC; - - // Represents the instruction that has either been retired or - // squashed. Similar to having a single bus that broadcasts the - // retired or squashed sequence number. - InstSeqNum doneSeqNum; - - //Just in case we want to do a commit/squash on a cycle - //(necessary for multiple ROBs?) - bool commitInsts; - InstSeqNum squashSeqNum; - - // Communication specifically to the IQ to tell the IQ that it can - // schedule a non-speculative instruction. - InstSeqNum nonSpecSeqNum; - - // Hack for now to send back an uncached access to the IEW stage. - typedef typename Impl::DynInstPtr DynInstPtr; - bool uncached; - DynInstPtr uncachedLoad; - - bool interruptPending; - bool clearInterrupt; - }; - - commitComm commitInfo[Impl::MaxThreads]; - - bool decodeBlock[Impl::MaxThreads]; - bool decodeUnblock[Impl::MaxThreads]; - bool renameBlock[Impl::MaxThreads]; - bool renameUnblock[Impl::MaxThreads]; - bool iewBlock[Impl::MaxThreads]; - bool iewUnblock[Impl::MaxThreads]; - bool commitBlock[Impl::MaxThreads]; - bool commitUnblock[Impl::MaxThreads]; -}; - -#endif //__CPU_O3_COMM_HH__ diff --git a/cpu/o3/commit.cc b/cpu/o3/commit.cc deleted file mode 100644 index fe5e9c1de..000000000 --- a/cpu/o3/commit.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/commit_impl.hh" - -template class DefaultCommit<AlphaSimpleImpl>; diff --git a/cpu/o3/commit.hh b/cpu/o3/commit.hh deleted file mode 100644 index 66abf8dc6..000000000 --- a/cpu/o3/commit.hh +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_COMMIT_HH__ -#define __CPU_O3_COMMIT_HH__ - -#include "arch/faults.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/exetrace.hh" -#include "cpu/inst_seq.hh" -#include "mem/memory_interface.hh" - -template <class> -class O3ThreadState; - -/** - * DefaultCommit handles single threaded and SMT commit. Its width is - * specified by the parameters; each cycle it tries to commit that - * many instructions. The SMT policy decides which thread it tries to - * commit instructions from. Non- speculative instructions must reach - * the head of the ROB before they are ready to execute; once they - * reach the head, commit will broadcast the instruction's sequence - * number to the previous stages so that they can issue/ execute the - * instruction. Only one non-speculative instruction is handled per - * cycle. Commit is responsible for handling all back-end initiated - * redirects. It receives the redirect, and then broadcasts it to all - * stages, indicating the sequence number they should squash until, - * and any necessary branch misprediction information as well. It - * priortizes redirects by instruction's age, only broadcasting a - * redirect if it corresponds to an instruction that should currently - * be in the ROB. This is done by tracking the sequence number of the - * youngest instruction in the ROB, which gets updated to any - * squashing instruction's sequence number, and only broadcasting a - * redirect if it corresponds to an older instruction. Commit also - * supports multiple cycle squashing, to model a ROB that can only - * remove a certain number of instructions per cycle. - */ -template<class Impl> -class DefaultCommit -{ - public: - // Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - typedef typename Impl::CPUPol CPUPol; - - typedef typename CPUPol::RenameMap RenameMap; - typedef typename CPUPol::ROB ROB; - - typedef typename CPUPol::TimeStruct TimeStruct; - typedef typename CPUPol::FetchStruct FetchStruct; - typedef typename CPUPol::IEWStruct IEWStruct; - typedef typename CPUPol::RenameStruct RenameStruct; - - typedef typename CPUPol::Fetch Fetch; - typedef typename CPUPol::IEW IEW; - - typedef O3ThreadState<Impl> Thread; - - class TrapEvent : public Event { - private: - DefaultCommit<Impl> *commit; - unsigned tid; - - public: - TrapEvent(DefaultCommit<Impl> *_commit, unsigned _tid); - - void process(); - const char *description(); - }; - - /** Overall commit status. Used to determine if the CPU can deschedule - * itself due to a lack of activity. - */ - enum CommitStatus{ - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - ROBSquashing, - TrapPending, - FetchTrapPending - }; - - /** Commit policy for SMT mode. */ - enum CommitPolicy { - Aggressive, - RoundRobin, - OldestReady - }; - - private: - /** Overall commit status. */ - CommitStatus _status; - /** Next commit status, to be set at the end of the cycle. */ - CommitStatus _nextStatus; - /** Per-thread status. */ - ThreadStatus commitStatus[Impl::MaxThreads]; - /** Commit policy used in SMT mode. */ - CommitPolicy commitPolicy; - - public: - /** Construct a DefaultCommit with the given parameters. */ - DefaultCommit(Params *params); - - /** Returns the name of the DefaultCommit. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the list of threads. */ - void setThreads(std::vector<Thread *> &threads); - - /** Sets the main time buffer pointer, used for backwards communication. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); - - /** Sets the pointer to the queue coming from rename. */ - void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); - - /** Sets the pointer to the queue coming from IEW. */ - void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr); - - void setFetchStage(Fetch *fetch_stage); - - Fetch *fetchStage; - - /** Sets the poitner to the IEW stage. */ - void setIEWStage(IEW *iew_stage); - - /** The pointer to the IEW stage. Used solely to ensure that - * various events (traps, interrupts, syscalls) do not occur until - * all stores have written back. - */ - IEW *iewStage; - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to the commited state rename map. */ - void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]); - - /** Sets pointer to the ROB. */ - void setROB(ROB *rob_ptr); - - /** Initializes stage by sending back the number of free entries. */ - void initStage(); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - /** Ticks the commit stage, which tries to commit instructions. */ - void tick(); - - /** Handles any squashes that are sent from IEW, and adds instructions - * to the ROB and tries to commit instructions. - */ - void commit(); - - /** Returns the number of free ROB entries for a specific thread. */ - unsigned numROBFreeEntries(unsigned tid); - - void generateXCEvent(unsigned tid); - - private: - /** Updates the overall status of commit with the nextStatus, and - * tell the CPU if commit is active/inactive. */ - void updateStatus(); - - /** Sets the next status based on threads' statuses, which becomes the - * current status at the end of the cycle. - */ - void setNextStatus(); - - /** Checks if the ROB is completed with squashing. This is for the case - * where the ROB can take multiple cycles to complete squashing. - */ - bool robDoneSquashing(); - - /** Returns if any of the threads have the number of ROB entries changed - * on this cycle. Used to determine if the number of free ROB entries needs - * to be sent back to previous stages. - */ - bool changedROBEntries(); - - void squashAll(unsigned tid); - - void squashFromTrap(unsigned tid); - - void squashFromXC(unsigned tid); - - /** Commits as many instructions as possible. */ - void commitInsts(); - - /** Tries to commit the head ROB instruction passed in. - * @param head_inst The instruction to be committed. - */ - bool commitHead(DynInstPtr &head_inst, unsigned inst_num); - - void generateTrapEvent(unsigned tid); - - /** Gets instructions from rename and inserts them into the ROB. */ - void getInsts(); - - /** Marks completed instructions using information sent from IEW. */ - void markCompletedInsts(); - - /** Gets the thread to commit, based on the SMT policy. */ - int getCommittingThread(); - - /** Returns the thread ID to use based on a round robin policy. */ - int roundRobin(); - - /** Returns the thread ID to use based on an oldest instruction policy. */ - int oldestReady(); - - public: - /** Returns the PC of the head instruction of the ROB. - * @todo: Probably remove this function as it returns only thread 0. - */ - uint64_t readPC() { return PC[0]; } - - uint64_t readPC(unsigned tid) { return PC[tid]; } - - void setPC(uint64_t val, unsigned tid) { PC[tid] = val; } - - uint64_t readNextPC(unsigned tid) { return nextPC[tid]; } - - void setNextPC(uint64_t val, unsigned tid) { nextPC[tid] = val; } - - private: - /** Time buffer interface. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to write information heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toIEW; - - /** Wire to read information from IEW (for ROB). */ - typename TimeBuffer<TimeStruct>::wire robInfoFromIEW; - - TimeBuffer<FetchStruct> *fetchQueue; - - typename TimeBuffer<FetchStruct>::wire fromFetch; - - /** IEW instruction queue interface. */ - TimeBuffer<IEWStruct> *iewQueue; - - /** Wire to read information from IEW queue. */ - typename TimeBuffer<IEWStruct>::wire fromIEW; - - /** Rename instruction queue interface, for ROB. */ - TimeBuffer<RenameStruct> *renameQueue; - - /** Wire to read information from rename queue. */ - typename TimeBuffer<RenameStruct>::wire fromRename; - - public: - /** ROB interface. */ - ROB *rob; - - private: - /** Pointer to FullCPU. */ - FullCPU *cpu; - - /** Memory interface. Used for d-cache accesses. */ - MemInterface *dcacheInterface; - - std::vector<Thread *> thread; - - Fault fetchFault; - - int fetchTrapWait; - - /** Records that commit has written to the time buffer this cycle. Used for - * the CPU to determine if it can deschedule itself if there is no activity. - */ - bool wroteToTimeBuffer; - - /** Records if the number of ROB entries has changed this cycle. If it has, - * then the number of free entries must be re-broadcast. - */ - bool changedROBNumEntries[Impl::MaxThreads]; - - /** A counter of how many threads are currently squashing. */ - int squashCounter; - - /** Records if a thread has to squash this cycle due to a trap. */ - bool trapSquash[Impl::MaxThreads]; - - /** Records if a thread has to squash this cycle due to an XC write. */ - bool xcSquash[Impl::MaxThreads]; - - /** Priority List used for Commit Policy */ - std::list<unsigned> priority_list; - - /** IEW to Commit delay, in ticks. */ - unsigned iewToCommitDelay; - - /** Commit to IEW delay, in ticks. */ - unsigned commitToIEWDelay; - - /** Rename to ROB delay, in ticks. */ - unsigned renameToROBDelay; - - unsigned fetchToCommitDelay; - - /** Rename width, in instructions. Used so ROB knows how many - * instructions to get from the rename instruction queue. - */ - unsigned renameWidth; - - /** IEW width, in instructions. Used so ROB knows how many - * instructions to get from the IEW instruction queue. - */ - unsigned iewWidth; - - /** Commit width, in instructions. */ - unsigned commitWidth; - - /** Number of Reorder Buffers */ - unsigned numRobs; - - /** Number of Active Threads */ - unsigned numThreads; - - bool switchPending; - bool switchedOut; - - Tick trapLatency; - - Tick fetchTrapLatency; - - Tick fetchFaultTick; - - Addr PC[Impl::MaxThreads]; - - Addr nextPC[Impl::MaxThreads]; - - /** The sequence number of the youngest valid instruction in the ROB. */ - InstSeqNum youngestSeqNum[Impl::MaxThreads]; - - /** Pointer to the list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Rename map interface. */ - RenameMap *renameMap[Impl::MaxThreads]; - - void updateComInstStats(DynInstPtr &inst); - - /** Stat for the total number of committed instructions. */ - Stats::Scalar<> commitCommittedInsts; - /** Stat for the total number of squashed instructions discarded by commit. - */ - Stats::Scalar<> commitSquashedInsts; - /** Stat for the total number of times commit is told to squash. - * @todo: Actually increment this stat. - */ - Stats::Scalar<> commitSquashEvents; - /** Stat for the total number of times commit has had to stall due to a non- - * speculative instruction reaching the head of the ROB. - */ - Stats::Scalar<> commitNonSpecStalls; - /** Stat for the total number of branch mispredicts that caused a squash. */ - Stats::Scalar<> branchMispredicts; - /** Distribution of the number of committed instructions each cycle. */ - Stats::Distribution<> numCommittedDist; - - /** Total number of instructions committed. */ - Stats::Vector<> statComInst; - /** Total number of software prefetches committed. */ - Stats::Vector<> statComSwp; - /** Stat for the total number of committed memory references. */ - Stats::Vector<> statComRefs; - /** Stat for the total number of committed loads. */ - Stats::Vector<> statComLoads; - /** Total number of committed memory barriers. */ - Stats::Vector<> statComMembars; - /** Total number of committed branches. */ - Stats::Vector<> statComBranches; - - Stats::Scalar<> commitEligibleSamples; - Stats::Vector<> commitEligible; -}; - -#endif // __CPU_O3_COMMIT_HH__ diff --git a/cpu/o3/commit_impl.hh b/cpu/o3/commit_impl.hh deleted file mode 100644 index 346a8bc1c..000000000 --- a/cpu/o3/commit_impl.hh +++ /dev/null @@ -1,1307 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <string> - -#include "base/loader/symtab.hh" -#include "base/timebuf.hh" -#include "cpu/checker/cpu.hh" -#include "cpu/exetrace.hh" -#include "cpu/o3/commit.hh" -#include "cpu/o3/thread_state.hh" - -using namespace std; - -template <class Impl> -DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, - unsigned _tid) - : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -DefaultCommit<Impl>::TrapEvent::process() -{ - // This will get reset by commit if it was switched out at the - // time of this event processing. - commit->trapSquash[tid] = true; -} - -template <class Impl> -const char * -DefaultCommit<Impl>::TrapEvent::description() -{ - return "Trap event"; -} - -template <class Impl> -DefaultCommit<Impl>::DefaultCommit(Params *params) - : dcacheInterface(params->dcacheInterface), - squashCounter(0), - iewToCommitDelay(params->iewToCommitDelay), - commitToIEWDelay(params->commitToIEWDelay), - renameToROBDelay(params->renameToROBDelay), - fetchToCommitDelay(params->commitToFetchDelay), - renameWidth(params->renameWidth), - iewWidth(params->executeWidth), - commitWidth(params->commitWidth), - numThreads(params->numberOfThreads), - switchedOut(false), - trapLatency(params->trapLatency), - fetchTrapLatency(params->fetchTrapLatency) -{ - _status = Active; - _nextStatus = Inactive; - string policy = params->smtCommitPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Assign commit policy - if (policy == "aggressive"){ - commitPolicy = Aggressive; - - DPRINTF(Commit,"Commit Policy set to Aggressive."); - } else if (policy == "roundrobin"){ - commitPolicy = RoundRobin; - - //Set-Up Priority List - for (int tid=0; tid < numThreads; tid++) { - priority_list.push_back(tid); - } - - DPRINTF(Commit,"Commit Policy set to Round Robin."); - } else if (policy == "oldestready"){ - commitPolicy = OldestReady; - - DPRINTF(Commit,"Commit Policy set to Oldest Ready."); - } else { - assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive," - "RoundRobin,OldestReady}"); - } - - for (int i=0; i < numThreads; i++) { - commitStatus[i] = Idle; - changedROBNumEntries[i] = false; - trapSquash[i] = false; - xcSquash[i] = false; - } - - fetchFaultTick = 0; - fetchTrapWait = 0; -} - -template <class Impl> -std::string -DefaultCommit<Impl>::name() const -{ - return cpu->name() + ".commit"; -} - -template <class Impl> -void -DefaultCommit<Impl>::regStats() -{ - using namespace Stats; - commitCommittedInsts - .name(name() + ".commitCommittedInsts") - .desc("The number of committed instructions") - .prereq(commitCommittedInsts); - commitSquashedInsts - .name(name() + ".commitSquashedInsts") - .desc("The number of squashed insts skipped by commit") - .prereq(commitSquashedInsts); - commitSquashEvents - .name(name() + ".commitSquashEvents") - .desc("The number of times commit is told to squash") - .prereq(commitSquashEvents); - commitNonSpecStalls - .name(name() + ".commitNonSpecStalls") - .desc("The number of times commit has been forced to stall to " - "communicate backwards") - .prereq(commitNonSpecStalls); - branchMispredicts - .name(name() + ".branchMispredicts") - .desc("The number of times a branch was mispredicted") - .prereq(branchMispredicts); - numCommittedDist - .init(0,commitWidth,1) - .name(name() + ".COM:committed_per_cycle") - .desc("Number of insts commited each cycle") - .flags(Stats::pdf) - ; - - statComInst - .init(cpu->number_of_threads) - .name(name() + ".COM:count") - .desc("Number of instructions committed") - .flags(total) - ; - - statComSwp - .init(cpu->number_of_threads) - .name(name() + ".COM:swp_count") - .desc("Number of s/w prefetches committed") - .flags(total) - ; - - statComRefs - .init(cpu->number_of_threads) - .name(name() + ".COM:refs") - .desc("Number of memory references committed") - .flags(total) - ; - - statComLoads - .init(cpu->number_of_threads) - .name(name() + ".COM:loads") - .desc("Number of loads committed") - .flags(total) - ; - - statComMembars - .init(cpu->number_of_threads) - .name(name() + ".COM:membars") - .desc("Number of memory barriers committed") - .flags(total) - ; - - statComBranches - .init(cpu->number_of_threads) - .name(name() + ".COM:branches") - .desc("Number of branches committed") - .flags(total) - ; - - // - // Commit-Eligible instructions... - // - // -> The number of instructions eligible to commit in those - // cycles where we reached our commit BW limit (less the number - // actually committed) - // - // -> The average value is computed over ALL CYCLES... not just - // the BW limited cycles - // - // -> The standard deviation is computed only over cycles where - // we reached the BW limit - // - commitEligible - .init(cpu->number_of_threads) - .name(name() + ".COM:bw_limited") - .desc("number of insts not committed due to BW limits") - .flags(total) - ; - - commitEligibleSamples - .name(name() + ".COM:bw_lim_events") - .desc("number cycles where commit BW limit reached") - ; -} - -template <class Impl> -void -DefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Commit, "Commit: Setting CPU pointer.\n"); - cpu = cpu_ptr; - - // Commit must broadcast the number of free entries it has at the start of - // the simulation, so it starts as active. - cpu->activateStage(FullCPU::CommitIdx); - - trapLatency = cpu->cycles(trapLatency); - fetchTrapLatency = cpu->cycles(fetchTrapLatency); -} - -template <class Impl> -void -DefaultCommit<Impl>::setThreads(vector<Thread *> &threads) -{ - thread = threads; -} - -template <class Impl> -void -DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(Commit, "Commit: Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to send information back to IEW. - toIEW = timeBuffer->getWire(0); - - // Setup wire to read data from IEW (for the ROB). - robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) -{ - DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n"); - fetchQueue = fq_ptr; - - // Setup wire to get instructions from rename (for the ROB). - fromFetch = fetchQueue->getWire(-fetchToCommitDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) -{ - DPRINTF(Commit, "Commit: Setting rename queue pointer.\n"); - renameQueue = rq_ptr; - - // Setup wire to get instructions from rename (for the ROB). - fromRename = renameQueue->getWire(-renameToROBDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) -{ - DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n"); - iewQueue = iq_ptr; - - // Setup wire to get instructions from IEW. - fromIEW = iewQueue->getWire(-iewToCommitDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage) -{ - fetchStage = fetch_stage; -} - -template <class Impl> -void -DefaultCommit<Impl>::setIEWStage(IEW *iew_stage) -{ - iewStage = iew_stage; -} - -template<class Impl> -void -DefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Commit, "Commit: Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[]) -{ - DPRINTF(Commit, "Setting rename map pointers.\n"); - - for (int i=0; i < numThreads; i++) { - renameMap[i] = &rm_ptr[i]; - } -} - -template <class Impl> -void -DefaultCommit<Impl>::setROB(ROB *rob_ptr) -{ - DPRINTF(Commit, "Commit: Setting ROB pointer.\n"); - rob = rob_ptr; -} - -template <class Impl> -void -DefaultCommit<Impl>::initStage() -{ - rob->setActiveThreads(activeThreads); - rob->resetEntries(); - - // Broadcast the number of free entries. - for (int i=0; i < numThreads; i++) { - toIEW->commitInfo[i].usedROB = true; - toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i); - } - - cpu->activityThisCycle(); -} - -template <class Impl> -void -DefaultCommit<Impl>::switchOut() -{ - switchPending = true; -} - -template <class Impl> -void -DefaultCommit<Impl>::doSwitchOut() -{ - switchedOut = true; - switchPending = false; - rob->switchOut(); -} - -template <class Impl> -void -DefaultCommit<Impl>::takeOverFrom() -{ - switchedOut = false; - _status = Active; - _nextStatus = Inactive; - for (int i=0; i < numThreads; i++) { - commitStatus[i] = Idle; - changedROBNumEntries[i] = false; - trapSquash[i] = false; - xcSquash[i] = false; - } - squashCounter = 0; - rob->takeOverFrom(); -} - -template <class Impl> -void -DefaultCommit<Impl>::updateStatus() -{ - // reset ROB changed variable - list<unsigned>::iterator threads = (*activeThreads).begin(); - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - changedROBNumEntries[tid] = false; - - // Also check if any of the threads has a trap pending - if (commitStatus[tid] == TrapPending || - commitStatus[tid] == FetchTrapPending) { - _nextStatus = Active; - } - } - - if (_nextStatus == Inactive && _status == Active) { - DPRINTF(Activity, "Deactivating stage.\n"); - cpu->deactivateStage(FullCPU::CommitIdx); - } else if (_nextStatus == Active && _status == Inactive) { - DPRINTF(Activity, "Activating stage.\n"); - cpu->activateStage(FullCPU::CommitIdx); - } - - _status = _nextStatus; -} - -template <class Impl> -void -DefaultCommit<Impl>::setNextStatus() -{ - int squashes = 0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (commitStatus[tid] == ROBSquashing) { - squashes++; - } - } - - assert(squashes == squashCounter); - - // If commit is currently squashing, then it will have activity for the - // next cycle. Set its next status as active. - if (squashCounter) { - _nextStatus = Active; - } -} - -template <class Impl> -bool -DefaultCommit<Impl>::changedROBEntries() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (changedROBNumEntries[tid]) { - return true; - } - } - - return false; -} - -template <class Impl> -unsigned -DefaultCommit<Impl>::numROBFreeEntries(unsigned tid) -{ - return rob->numFreeEntries(tid); -} - -template <class Impl> -void -DefaultCommit<Impl>::generateTrapEvent(unsigned tid) -{ - DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid); - - TrapEvent *trap = new TrapEvent(this, tid); - - trap->schedule(curTick + trapLatency); - - thread[tid]->trapPending = true; -} - -template <class Impl> -void -DefaultCommit<Impl>::generateXCEvent(unsigned tid) -{ - DPRINTF(Commit, "Generating XC squash event for [tid:%i]\n", tid); - - xcSquash[tid] = true; -} - -template <class Impl> -void -DefaultCommit<Impl>::squashAll(unsigned tid) -{ - // If we want to include the squashing instruction in the squash, - // then use one older sequence number. - // Hopefully this doesn't mess things up. Basically I want to squash - // all instructions of this thread. - InstSeqNum squashed_inst = rob->isEmpty() ? - 0 : rob->readHeadInst(tid)->seqNum - 1;; - - // All younger instructions will be squashed. Set the sequence - // number as the youngest instruction in the ROB (0 in this case. - // Hopefully nothing breaks.) - youngestSeqNum[tid] = 0; - - rob->squash(squashed_inst, tid); - changedROBNumEntries[tid] = true; - - // Send back the sequence number of the squashed instruction. - toIEW->commitInfo[tid].doneSeqNum = squashed_inst; - - // Send back the squash signal to tell stages that they should - // squash. - toIEW->commitInfo[tid].squash = true; - - // Send back the rob squashing signal so other stages know that - // the ROB is in the process of squashing. - toIEW->commitInfo[tid].robSquashing = true; - - toIEW->commitInfo[tid].branchMispredict = false; - - toIEW->commitInfo[tid].nextPC = PC[tid]; -} - -template <class Impl> -void -DefaultCommit<Impl>::squashFromTrap(unsigned tid) -{ - squashAll(tid); - - DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]); - - thread[tid]->trapPending = false; - thread[tid]->inSyscall = false; - - trapSquash[tid] = false; - - commitStatus[tid] = ROBSquashing; - cpu->activityThisCycle(); - - ++squashCounter; -} - -template <class Impl> -void -DefaultCommit<Impl>::squashFromXC(unsigned tid) -{ - squashAll(tid); - - DPRINTF(Commit, "Squashing from XC, restarting at PC %#x\n", PC[tid]); - - thread[tid]->inSyscall = false; - assert(!thread[tid]->trapPending); - - commitStatus[tid] = ROBSquashing; - cpu->activityThisCycle(); - - xcSquash[tid] = false; - - ++squashCounter; -} - -template <class Impl> -void -DefaultCommit<Impl>::tick() -{ - wroteToTimeBuffer = false; - _nextStatus = Inactive; - - if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { - cpu->signalSwitched(); - return; - } - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - // Check if any of the threads are done squashing. Change the - // status if they are done. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (commitStatus[tid] == ROBSquashing) { - - if (rob->isDoneSquashing(tid)) { - commitStatus[tid] = Running; - --squashCounter; - } else { - DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" - "insts this cycle.\n", tid); - } - } - } - - commit(); - - markCompletedInsts(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { - // The ROB has more instructions it can commit. Its next status - // will be active. - _nextStatus = Active; - - DynInstPtr inst = rob->readHeadInst(tid); - - DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of" - " ROB and ready to commit\n", - tid, inst->seqNum, inst->readPC()); - - } else if (!rob->isEmpty(tid)) { - DynInstPtr inst = rob->readHeadInst(tid); - - DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " - "%#x is head of ROB and not ready\n", - tid, inst->seqNum, inst->readPC()); - } - - DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", - tid, rob->countInsts(tid), rob->numFreeEntries(tid)); - } - - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity This Cycle.\n"); - cpu->activityThisCycle(); - } - - updateStatus(); -} - -template <class Impl> -void -DefaultCommit<Impl>::commit() -{ - - ////////////////////////////////////// - // Check for interrupts - ////////////////////////////////////// - -#if FULL_SYSTEM - // Process interrupts if interrupts are enabled, not in PAL mode, - // and no other traps or external squashes are currently pending. - // @todo: Allow other threads to handle interrupts. - if (cpu->checkInterrupts && - cpu->check_interrupts() && - !cpu->inPalMode(readPC()) && - !trapSquash[0] && - !xcSquash[0]) { - // Tell fetch that there is an interrupt pending. This will - // make fetch wait until it sees a non PAL-mode PC, at which - // point it stops fetching instructions. - toIEW->commitInfo[0].interruptPending = true; - - // Wait until the ROB is empty and all stores have drained in - // order to enter the interrupt. - if (rob->isEmpty() && !iewStage->hasStoresToWB()) { - // Not sure which thread should be the one to interrupt. For now - // always do thread 0. - assert(!thread[0]->inSyscall); - thread[0]->inSyscall = true; - - // CPU will handle implementation of the interrupt. - cpu->processInterrupts(); - - // Now squash or record that I need to squash this cycle. - commitStatus[0] = TrapPending; - - // Exit state update mode to avoid accidental updating. - thread[0]->inSyscall = false; - - // Generate trap squash event. - generateTrapEvent(0); - - toIEW->commitInfo[0].clearInterrupt = true; - - DPRINTF(Commit, "Interrupt detected.\n"); - } else { - DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); - } - } -#endif // FULL_SYSTEM - - //////////////////////////////////// - // Check for any possible squashes, handle them first - //////////////////////////////////// - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (fromFetch->fetchFault && commitStatus[0] != TrapPending) { - // Record the fault. Wait until it's empty in the ROB. - // Then handle the trap. Ignore it if there's already a - // trap pending as fetch will be redirected. - fetchFault = fromFetch->fetchFault; - fetchFaultTick = curTick + fetchTrapLatency; - commitStatus[0] = FetchTrapPending; - DPRINTF(Commit, "Fault from fetch recorded. Will trap if the " - "ROB empties without squashing the fault.\n"); - fetchTrapWait = 0; - } - - // Fetch may tell commit to clear the trap if it's been squashed. - if (fromFetch->clearFetchFault) { - DPRINTF(Commit, "Received clear fetch fault signal\n"); - fetchTrapWait = 0; - if (commitStatus[0] == FetchTrapPending) { - DPRINTF(Commit, "Clearing fault from fetch\n"); - commitStatus[0] = Running; - } - } - - // Not sure which one takes priority. I think if we have - // both, that's a bad sign. - if (trapSquash[tid] == true) { - assert(!xcSquash[tid]); - squashFromTrap(tid); - } else if (xcSquash[tid] == true) { - squashFromXC(tid); - } - - // Squashed sequence number must be older than youngest valid - // instruction in the ROB. This prevents squashes from younger - // instructions overriding squashes from older instructions. - if (fromIEW->squash[tid] && - commitStatus[tid] != TrapPending && - fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { - - DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", - tid, - fromIEW->mispredPC[tid], - fromIEW->squashedSeqNum[tid]); - - DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", - tid, - fromIEW->nextPC[tid]); - - commitStatus[tid] = ROBSquashing; - - ++squashCounter; - - // If we want to include the squashing instruction in the squash, - // then use one older sequence number. - InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; - - if (fromIEW->includeSquashInst[tid] == true) - squashed_inst--; - - // All younger instructions will be squashed. Set the sequence - // number as the youngest instruction in the ROB. - youngestSeqNum[tid] = squashed_inst; - - rob->squash(squashed_inst, tid); - changedROBNumEntries[tid] = true; - - toIEW->commitInfo[tid].doneSeqNum = squashed_inst; - - toIEW->commitInfo[tid].squash = true; - - // Send back the rob squashing signal so other stages know that - // the ROB is in the process of squashing. - toIEW->commitInfo[tid].robSquashing = true; - - toIEW->commitInfo[tid].branchMispredict = - fromIEW->branchMispredict[tid]; - - toIEW->commitInfo[tid].branchTaken = - fromIEW->branchTaken[tid]; - - toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid]; - - toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; - - if (toIEW->commitInfo[tid].branchMispredict) { - ++branchMispredicts; - } - } - - } - - setNextStatus(); - - if (squashCounter != numThreads) { - // If we're not currently squashing, then get instructions. - getInsts(); - - // Try to commit any instructions. - commitInsts(); - } - - //Check for any activity - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (changedROBNumEntries[tid]) { - toIEW->commitInfo[tid].usedROB = true; - toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); - - if (rob->isEmpty(tid)) { - toIEW->commitInfo[tid].emptyROB = true; - } - - wroteToTimeBuffer = true; - changedROBNumEntries[tid] = false; - } - } -} - -template <class Impl> -void -DefaultCommit<Impl>::commitInsts() -{ - //////////////////////////////////// - // Handle commit - // Note that commit will be handled prior to putting new - // instructions in the ROB so that the ROB only tries to commit - // instructions it has in this current cycle, and not instructions - // it is writing in during this cycle. Can't commit and squash - // things at the same time... - //////////////////////////////////// - - DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); - - unsigned num_committed = 0; - - DynInstPtr head_inst; - - // Commit as many instructions as possible until the commit bandwidth - // limit is reached, or it becomes impossible to commit any more. - while (num_committed < commitWidth) { - int commit_thread = getCommittingThread(); - - if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) - break; - - head_inst = rob->readHeadInst(commit_thread); - - int tid = head_inst->threadNumber; - - assert(tid == commit_thread); - - DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", - head_inst->seqNum, tid); - - // If the head instruction is squashed, it is ready to retire - // (be removed from the ROB) at any time. - if (head_inst->isSquashed()) { - - DPRINTF(Commit, "Retiring squashed instruction from " - "ROB.\n"); - - rob->retireHead(commit_thread); - - ++commitSquashedInsts; - - // Record that the number of ROB entries has changed. - changedROBNumEntries[tid] = true; - } else { - PC[tid] = head_inst->readPC(); - nextPC[tid] = head_inst->readNextPC(); - - // Increment the total number of non-speculative instructions - // executed. - // Hack for now: it really shouldn't happen until after the - // commit is deemed to be successful, but this count is needed - // for syscalls. - thread[tid]->funcExeInst++; - - // Try to commit the head instruction. - bool commit_success = commitHead(head_inst, num_committed); - - if (commit_success) { - ++num_committed; - - changedROBNumEntries[tid] = true; - - // Set the doneSeqNum to the youngest committed instruction. - toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; - - ++commitCommittedInsts; - - // To match the old model, don't count nops and instruction - // prefetches towards the total commit count. - if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { - cpu->instDone(tid); - } - - PC[tid] = nextPC[tid]; - nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst); -#if FULL_SYSTEM - int count = 0; - Addr oldpc; - do { - // Debug statement. Checks to make sure we're not - // currently updating state while handling PC events. - if (count == 0) - assert(!thread[tid]->inSyscall && - !thread[tid]->trapPending); - oldpc = PC[tid]; - cpu->system->pcEventQueue.service( - thread[tid]->getXCProxy()); - count++; - } while (oldpc != PC[tid]); - if (count > 1) { - DPRINTF(Commit, "PC skip function event, stopping commit\n"); - break; - } -#endif - } else { - DPRINTF(Commit, "Unable to commit head instruction PC:%#x " - "[tid:%i] [sn:%i].\n", - head_inst->readPC(), tid ,head_inst->seqNum); - break; - } - } - } - - DPRINTF(CommitRate, "%i\n", num_committed); - numCommittedDist.sample(num_committed); - - if (num_committed == commitWidth) { - commitEligible[0]++; - } -} - -template <class Impl> -bool -DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) -{ - assert(head_inst); - - int tid = head_inst->threadNumber; - - // If the instruction is not executed yet, then it will need extra - // handling. Signal backwards that it should be executed. - if (!head_inst->isExecuted()) { - // Keep this number correct. We have not yet actually executed - // and committed this instruction. - thread[tid]->funcExeInst--; - - head_inst->reachedCommit = true; - - if (head_inst->isNonSpeculative() || - head_inst->isMemBarrier() || - head_inst->isWriteBarrier()) { - - DPRINTF(Commit, "Encountered a barrier or non-speculative " - "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", - head_inst->seqNum, head_inst->readPC()); - -#if !FULL_SYSTEM - // Hack to make sure syscalls/memory barriers/quiesces - // aren't executed until all stores write back their data. - // This direct communication shouldn't be used for - // anything other than this. - if (inst_num > 0 || iewStage->hasStoresToWB()) -#else - if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() || - head_inst->isQuiesce()) && - iewStage->hasStoresToWB()) -#endif - { - DPRINTF(Commit, "Waiting for all stores to writeback.\n"); - return false; - } - - toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; - - // Change the instruction so it won't try to commit again until - // it is executed. - head_inst->clearCanCommit(); - - ++commitNonSpecStalls; - - return false; - } else if (head_inst->isLoad()) { - DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n", - head_inst->seqNum, head_inst->readPC()); - - // Send back the non-speculative instruction's sequence - // number. Tell the lsq to re-execute the load. - toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; - toIEW->commitInfo[tid].uncached = true; - toIEW->commitInfo[tid].uncachedLoad = head_inst; - - head_inst->clearCanCommit(); - - return false; - } else { - panic("Trying to commit un-executed instruction " - "of unknown type!\n"); - } - } - - if (head_inst->isThreadSync()) { - // Not handled for now. - panic("Thread sync instructions are not handled yet.\n"); - } - - // Stores mark themselves as completed. - if (!head_inst->isStore()) { - head_inst->setCompleted(); - } - - // Use checker prior to updating anything due to traps or PC - // based events. - if (cpu->checker) { - cpu->checker->tick(head_inst); - } - - // Check if the instruction caused a fault. If so, trap. - Fault inst_fault = head_inst->getFault(); - - if (inst_fault != NoFault) { - head_inst->setCompleted(); -#if FULL_SYSTEM - DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", - head_inst->seqNum, head_inst->readPC()); - - if (iewStage->hasStoresToWB() || inst_num > 0) { - DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); - return false; - } - - if (cpu->checker && head_inst->isStore()) { - cpu->checker->tick(head_inst); - } - - assert(!thread[tid]->inSyscall); - - // Mark that we're in state update mode so that the trap's - // execution doesn't generate extra squashes. - thread[tid]->inSyscall = true; - - // DTB will sometimes need the machine instruction for when - // faults happen. So we will set it here, prior to the DTB - // possibly needing it for its fault. - thread[tid]->setInst( - static_cast<TheISA::MachInst>(head_inst->staticInst->machInst)); - - // Execute the trap. Although it's slightly unrealistic in - // terms of timing (as it doesn't wait for the full timing of - // the trap event to complete before updating state), it's - // needed to update the state as soon as possible. This - // prevents external agents from changing any specific state - // that the trap need. - cpu->trap(inst_fault, tid); - - // Exit state update mode to avoid accidental updating. - thread[tid]->inSyscall = false; - - commitStatus[tid] = TrapPending; - - // Generate trap squash event. - generateTrapEvent(tid); - - return false; -#else // !FULL_SYSTEM - panic("fault (%d) detected @ PC %08p", inst_fault, - head_inst->PC); -#endif // FULL_SYSTEM - } - - updateComInstStats(head_inst); - - if (head_inst->traceData) { - head_inst->traceData->setFetchSeq(head_inst->seqNum); - head_inst->traceData->setCPSeq(thread[tid]->numInst); - head_inst->traceData->finalize(); - head_inst->traceData = NULL; - } - - // Update the commit rename map - for (int i = 0; i < head_inst->numDestRegs(); i++) { - renameMap[tid]->setEntry(head_inst->destRegIdx(i), - head_inst->renamedDestRegIdx(i)); - } - - // Finally clear the head ROB entry. - rob->retireHead(tid); - - // Return true to indicate that we have committed an instruction. - return true; -} - -template <class Impl> -void -DefaultCommit<Impl>::getInsts() -{ - // Read any renamed instructions and place them into the ROB. - int insts_to_process = min((int)renameWidth, fromRename->size); - - for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) - { - DynInstPtr inst = fromRename->insts[inst_num]; - int tid = inst->threadNumber; - - if (!inst->isSquashed() && - commitStatus[tid] != ROBSquashing) { - changedROBNumEntries[tid] = true; - - DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n", - inst->readPC(), inst->seqNum, tid); - - rob->insertInst(inst); - - assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid)); - - youngestSeqNum[tid] = inst->seqNum; - } else { - DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was " - "squashed, skipping.\n", - inst->readPC(), inst->seqNum, tid); - } - } -} - -template <class Impl> -void -DefaultCommit<Impl>::markCompletedInsts() -{ - // Grab completed insts out of the IEW instruction queue, and mark - // instructions completed within the ROB. - for (int inst_num = 0; - inst_num < fromIEW->size && fromIEW->insts[inst_num]; - ++inst_num) - { - if (!fromIEW->insts[inst_num]->isSquashed()) { - DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready " - "within ROB.\n", - fromIEW->insts[inst_num]->threadNumber, - fromIEW->insts[inst_num]->readPC(), - fromIEW->insts[inst_num]->seqNum); - - // Mark the instruction as ready to commit. - fromIEW->insts[inst_num]->setCanCommit(); - } - } -} - -template <class Impl> -bool -DefaultCommit<Impl>::robDoneSquashing() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (!rob->isDoneSquashing(tid)) - return false; - } - - return true; -} - -template <class Impl> -void -DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst) -{ - unsigned thread = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) { - statComSwp[thread]++; - } else { - statComInst[thread]++; - } -#else - statComInst[thread]++; -#endif - - // - // Control Instructions - // - if (inst->isControl()) - statComBranches[thread]++; - - // - // Memory references - // - if (inst->isMemRef()) { - statComRefs[thread]++; - - if (inst->isLoad()) { - statComLoads[thread]++; - } - } - - if (inst->isMemBarrier()) { - statComMembars[thread]++; - } -} - -//////////////////////////////////////// -// // -// SMT COMMIT POLICY MAINTAINED HERE // -// // -//////////////////////////////////////// -template <class Impl> -int -DefaultCommit<Impl>::getCommittingThread() -{ - if (numThreads > 1) { - switch (commitPolicy) { - - case Aggressive: - //If Policy is Aggressive, commit will call - //this function multiple times per - //cycle - return oldestReady(); - - case RoundRobin: - return roundRobin(); - - case OldestReady: - return oldestReady(); - - default: - return -1; - } - } else { - int tid = (*activeThreads).front(); - - if (commitStatus[tid] == Running || - commitStatus[tid] == Idle || - commitStatus[tid] == FetchTrapPending) { - return tid; - } else { - return -1; - } - } -} - -template<class Impl> -int -DefaultCommit<Impl>::roundRobin() -{ - list<unsigned>::iterator pri_iter = priority_list.begin(); - list<unsigned>::iterator end = priority_list.end(); - - while (pri_iter != end) { - unsigned tid = *pri_iter; - - if (commitStatus[tid] == Running || - commitStatus[tid] == Idle) { - - if (rob->isHeadReady(tid)) { - priority_list.erase(pri_iter); - priority_list.push_back(tid); - - return tid; - } - } - - pri_iter++; - } - - return -1; -} - -template<class Impl> -int -DefaultCommit<Impl>::oldestReady() -{ - unsigned oldest = 0; - bool first = true; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (!rob->isEmpty(tid) && - (commitStatus[tid] == Running || - commitStatus[tid] == Idle || - commitStatus[tid] == FetchTrapPending)) { - - if (rob->isHeadReady(tid)) { - - DynInstPtr head_inst = rob->readHeadInst(tid); - - if (first) { - oldest = tid; - first = false; - } else if (head_inst->seqNum < oldest) { - oldest = tid; - } - } - } - } - - if (!first) { - return oldest; - } else { - return -1; - } -} diff --git a/cpu/o3/cpu.cc b/cpu/o3/cpu.cc deleted file mode 100644 index 8d72bdc41..000000000 --- a/cpu/o3/cpu.cc +++ /dev/null @@ -1,1183 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config/full_system.hh" - -#if FULL_SYSTEM -#include "sim/system.hh" -#else -#include "sim/process.hh" -#endif - -#include "cpu/activity.hh" -#include "cpu/checker/cpu.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/cpu.hh" - -#include "sim/root.hh" -#include "sim/stat_control.hh" - -using namespace std; - -BaseFullCPU::BaseFullCPU(Params *params) - : BaseCPU(params), cpu_id(0) -{ -} - -void -BaseFullCPU::regStats() -{ - BaseCPU::regStats(); -} - -template <class Impl> -FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -template <class Impl> -void -FullO3CPU<Impl>::TickEvent::process() -{ - cpu->tick(); -} - -template <class Impl> -const char * -FullO3CPU<Impl>::TickEvent::description() -{ - return "FullO3CPU tick event"; -} - -template <class Impl> -FullO3CPU<Impl>::FullO3CPU(Params *params) - : BaseFullCPU(params), - tickEvent(this), - removeInstsThisCycle(false), - fetch(params), - decode(params), - rename(params), - iew(params), - commit(params), - - regFile(params->numPhysIntRegs, params->numPhysFloatRegs), - - freeList(params->numberOfThreads,//number of activeThreads - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs), - - rob(params->numROBEntries, params->squashWidth, - params->smtROBPolicy, params->smtROBThreshold, - params->numberOfThreads), - - scoreboard(params->numberOfThreads,//number of activeThreads - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs, - TheISA::NumMiscRegs * number_of_threads, - TheISA::ZeroReg), - - // For now just have these time buffers be pretty big. - // @todo: Make these time buffer sizes parameters or derived - // from latencies - timeBuffer(5, 5), - fetchQueue(5, 5), - decodeQueue(5, 5), - renameQueue(5, 5), - iewQueue(5, 5), - activityRec(NumStages, 10, params->activity), - - globalSeqNum(1), - -#if FULL_SYSTEM - system(params->system), - memCtrl(system->memctrl), - physmem(system->physmem), - mem(params->mem), -#else -// pTable(params->pTable), - mem(params->workload[0]->getMemory()), -#endif // FULL_SYSTEM - switchCount(0), - icacheInterface(params->icacheInterface), - dcacheInterface(params->dcacheInterface), - deferRegistration(params->deferRegistration), - numThreads(number_of_threads) -{ - _status = Idle; - - if (params->checker) { - BaseCPU *temp_checker = params->checker; - checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); - checker->setMemory(mem); -#if FULL_SYSTEM - checker->setSystem(params->system); -#endif - } else { - checker = NULL; - } - -#if !FULL_SYSTEM - thread.resize(number_of_threads); - tids.resize(number_of_threads); -#endif - - // The stages also need their CPU pointer setup. However this - // must be done at the upper level CPU because they have pointers - // to the upper level CPU, and not this FullO3CPU. - - // Set up Pointers to the activeThreads list for each stage - fetch.setActiveThreads(&activeThreads); - decode.setActiveThreads(&activeThreads); - rename.setActiveThreads(&activeThreads); - iew.setActiveThreads(&activeThreads); - commit.setActiveThreads(&activeThreads); - - // Give each of the stages the time buffer they will use. - fetch.setTimeBuffer(&timeBuffer); - decode.setTimeBuffer(&timeBuffer); - rename.setTimeBuffer(&timeBuffer); - iew.setTimeBuffer(&timeBuffer); - commit.setTimeBuffer(&timeBuffer); - - // Also setup each of the stages' queues. - fetch.setFetchQueue(&fetchQueue); - decode.setFetchQueue(&fetchQueue); - commit.setFetchQueue(&fetchQueue); - decode.setDecodeQueue(&decodeQueue); - rename.setDecodeQueue(&decodeQueue); - rename.setRenameQueue(&renameQueue); - iew.setRenameQueue(&renameQueue); - iew.setIEWQueue(&iewQueue); - commit.setIEWQueue(&iewQueue); - commit.setRenameQueue(&renameQueue); - - commit.setFetchStage(&fetch); - commit.setIEWStage(&iew); - rename.setIEWStage(&iew); - rename.setCommitStage(&commit); - -#if !FULL_SYSTEM - int active_threads = params->workload.size(); -#else - int active_threads = 1; -#endif - - //Make Sure That this a Valid Architeture - assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); - assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); - - rename.setScoreboard(&scoreboard); - iew.setScoreboard(&scoreboard); - - // Setup the rename map for whichever stages need it. - PhysRegIndex lreg_idx = 0; - PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs - - for (int tid=0; tid < numThreads; tid++) { - bool bindRegs = (tid <= active_threads - 1); - - commitRenameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - false); - - renameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - bindRegs); - } - - rename.setRenameMap(renameMap); - commit.setRenameMap(commitRenameMap); - - // Give renameMap & rename stage access to the freeList; - for (int i=0; i < numThreads; i++) { - renameMap[i].setFreeList(&freeList); - } - rename.setFreeList(&freeList); - - // Setup the page table for whichever stages need it. -#if !FULL_SYSTEM -// fetch.setPageTable(pTable); -// iew.setPageTable(pTable); -#endif - - // Setup the ROB for whichever stages need it. - commit.setROB(&rob); - - lastRunningCycle = curTick; - - contextSwitch = false; -} - -template <class Impl> -FullO3CPU<Impl>::~FullO3CPU() -{ -} - -template <class Impl> -void -FullO3CPU<Impl>::fullCPURegStats() -{ - BaseFullCPU::regStats(); - - // Register any of the FullCPU's stats here. - timesIdled - .name(name() + ".timesIdled") - .desc("Number of times that the entire CPU went into an idle state and" - " unscheduled itself") - .prereq(timesIdled); - - idleCycles - .name(name() + ".idleCycles") - .desc("Total number of cycles that the CPU has spent unscheduled due " - "to idling") - .prereq(idleCycles); - - // Number of Instructions simulated - // -------------------------------- - // Should probably be in Base CPU but need templated - // MaxThreads so put in here instead - committedInsts - .init(numThreads) - .name(name() + ".committedInsts") - .desc("Number of Instructions Simulated"); - - totalCommittedInsts - .name(name() + ".committedInsts_total") - .desc("Number of Instructions Simulated"); - - cpi - .name(name() + ".cpi") - .desc("CPI: Cycles Per Instruction") - .precision(6); - cpi = simTicks / committedInsts; - - totalCpi - .name(name() + ".cpi_total") - .desc("CPI: Total CPI of All Threads") - .precision(6); - totalCpi = simTicks / totalCommittedInsts; - - ipc - .name(name() + ".ipc") - .desc("IPC: Instructions Per Cycle") - .precision(6); - ipc = committedInsts / simTicks; - - totalIpc - .name(name() + ".ipc_total") - .desc("IPC: Total IPC of All Threads") - .precision(6); - totalIpc = totalCommittedInsts / simTicks; - -} - -template <class Impl> -void -FullO3CPU<Impl>::tick() -{ - DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); - - ++numCycles; - -// activity = false; - - //Tick each of the stages - fetch.tick(); - - decode.tick(); - - rename.tick(); - - iew.tick(); - - commit.tick(); - -#if !FULL_SYSTEM - doContextSwitch(); -#endif - - // Now advance the time buffers - timeBuffer.advance(); - - fetchQueue.advance(); - decodeQueue.advance(); - renameQueue.advance(); - iewQueue.advance(); - - activityRec.advance(); - - if (removeInstsThisCycle) { - cleanUpRemovedInsts(); - } - - if (!tickEvent.scheduled()) { - if (_status == SwitchedOut) { - // increment stat - lastRunningCycle = curTick; - } else if (!activityRec.active()) { - lastRunningCycle = curTick; - timesIdled++; - } else { - tickEvent.schedule(curTick + cycles(1)); - } - } - -#if !FULL_SYSTEM - updateThreadPriority(); -#endif - -} - -template <class Impl> -void -FullO3CPU<Impl>::init() -{ - if (!deferRegistration) { - registerExecContexts(); - } - - // Set inSyscall so that the CPU doesn't squash when initially - // setting up registers. - for (int i = 0; i < number_of_threads; ++i) - thread[i]->inSyscall = true; - - for (int tid=0; tid < number_of_threads; tid++) { -#if FULL_SYSTEM - ExecContext *src_xc = execContexts[tid]; -#else - ExecContext *src_xc = thread[tid]->getXCProxy(); -#endif - // Threads start in the Suspended State - if (src_xc->status() != ExecContext::Suspended) { - continue; - } - -#if FULL_SYSTEM - TheISA::initCPU(src_xc, src_xc->readCpuId()); -#endif - } - - // Clear inSyscall. - for (int i = 0; i < number_of_threads; ++i) - thread[i]->inSyscall = false; - - // Initialize stages. - fetch.initStage(); - iew.initStage(); - rename.initStage(); - commit.initStage(); - - commit.setThreads(thread); -} - -template <class Impl> -void -FullO3CPU<Impl>::insertThread(unsigned tid) -{ - DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); - // Will change now that the PC and thread state is internal to the CPU - // and not in the CPUExecContext. -#if 0 -#if FULL_SYSTEM - ExecContext *src_xc = system->execContexts[tid]; -#else - CPUExecContext *src_xc = thread[tid]; -#endif - - //Bind Int Regs to Rename Map - for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { - PhysRegIndex phys_reg = freeList.getIntReg(); - - renameMap[tid].setEntry(ireg,phys_reg); - scoreboard.setReg(phys_reg); - } - - //Bind Float Regs to Rename Map - for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { - PhysRegIndex phys_reg = freeList.getFloatReg(); - - renameMap[tid].setEntry(freg,phys_reg); - scoreboard.setReg(phys_reg); - } - - //Copy Thread Data Into RegFile - this->copyFromXC(tid); - - //Set PC/NPC - regFile.pc[tid] = src_xc->readPC(); - regFile.npc[tid] = src_xc->readNextPC(); - - src_xc->setStatus(ExecContext::Active); - - activateContext(tid,1); - - //Reset ROB/IQ/LSQ Entries - commit.rob->resetEntries(); - iew.resetEntries(); -#endif -} - -template <class Impl> -void -FullO3CPU<Impl>::removeThread(unsigned tid) -{ - DPRINTF(FullCPU,"[tid:%i] Removing thread data"); -#if 0 - //Unbind Int Regs from Rename Map - for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { - PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); - - scoreboard.unsetReg(phys_reg); - freeList.addReg(phys_reg); - } - - //Unbind Float Regs from Rename Map - for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { - PhysRegIndex phys_reg = renameMap[tid].lookup(freg); - - scoreboard.unsetReg(phys_reg); - freeList.addReg(phys_reg); - } - - //Copy Thread Data From RegFile - /* Fix Me: - * Do we really need to do this if we are removing a thread - * in the sense that it's finished (exiting)? If the thread is just - * being suspended we might... - */ -// this->copyToXC(tid); - - //Squash Throughout Pipeline - fetch.squash(0,tid); - decode.squash(tid); - rename.squash(tid); - - assert(iew.ldstQueue.getCount(tid) == 0); - - //Reset ROB/IQ/LSQ Entries - if (activeThreads.size() >= 1) { - commit.rob->resetEntries(); - iew.resetEntries(); - } -#endif -} - - -template <class Impl> -void -FullO3CPU<Impl>::activateWhenReady(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" - "(e.g. PhysRegs/ROB/IQ/LSQ) \n", - tid); - - bool ready = true; - - if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "Phys. Int. Regs.\n", - tid); - ready = false; - } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "Phys. Float. Regs.\n", - tid); - ready = false; - } else if (commit.rob->numFreeEntries() >= - commit.rob->entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "ROB entries.\n", - tid); - ready = false; - } else if (iew.instQueue.numFreeEntries() >= - iew.instQueue.entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "IQ entries.\n", - tid); - ready = false; - } else if (iew.ldstQueue.numFreeEntries() >= - iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "LSQ entries.\n", - tid); - ready = false; - } - - if (ready) { - insertThread(tid); - - contextSwitch = false; - - cpuWaitList.remove(tid); - } else { - suspendContext(tid); - - //blocks fetch - contextSwitch = true; - - //do waitlist - cpuWaitList.push_back(tid); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::activateContext(int tid, int delay) -{ - // Needs to set each stage to running as well. - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive == activeThreads.end()) { - //May Need to Re-code this if the delay variable is the - //delay needed for thread to activate - DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", - tid); - - activeThreads.push_back(tid); - } - - assert(_status == Idle || _status == SwitchedOut); - - scheduleTickEvent(delay); - - // Be sure to signal that there's some activity so the CPU doesn't - // deschedule itself. - activityRec.activity(); - fetch.wakeFromQuiesce(); - - _status = Running; -} - -template <class Impl> -void -FullO3CPU<Impl>::suspendContext(int tid) -{ - DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); - unscheduleTickEvent(); - _status = Idle; -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::deallocateContext(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::haltContext(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::switchOut(Sampler *_sampler) -{ - sampler = _sampler; - switchCount = 0; - fetch.switchOut(); - decode.switchOut(); - rename.switchOut(); - iew.switchOut(); - commit.switchOut(); - - // Wake the CPU and record activity so everything can drain out if - // the CPU is currently idle. - wakeCPU(); - activityRec.activity(); -} - -template <class Impl> -void -FullO3CPU<Impl>::signalSwitched() -{ - if (++switchCount == NumStages) { - fetch.doSwitchOut(); - rename.doSwitchOut(); - commit.doSwitchOut(); - instList.clear(); - while (!removeList.empty()) { - removeList.pop(); - } - - if (checker) - checker->switchOut(sampler); - - if (tickEvent.scheduled()) - tickEvent.squash(); - sampler->signalSwitched(); - _status = SwitchedOut; - } - assert(switchCount <= 5); -} - -template <class Impl> -void -FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) -{ - // Flush out any old data from the time buffers. - for (int i = 0; i < 10; ++i) { - timeBuffer.advance(); - fetchQueue.advance(); - decodeQueue.advance(); - renameQueue.advance(); - iewQueue.advance(); - } - - activityRec.reset(); - - BaseCPU::takeOverFrom(oldCPU); - - fetch.takeOverFrom(); - decode.takeOverFrom(); - rename.takeOverFrom(); - iew.takeOverFrom(); - commit.takeOverFrom(); - - assert(!tickEvent.scheduled()); - - // @todo: Figure out how to properly select the tid to put onto - // the active threads list. - int tid = 0; - - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive == activeThreads.end()) { - //May Need to Re-code this if the delay variable is the delay - //needed for thread to activate - DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", - tid); - - activeThreads.push_back(tid); - } - - // Set all statuses to active, schedule the CPU's tick event. - // @todo: Fix up statuses so this is handled properly - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } - if (!tickEvent.scheduled()) - tickEvent.schedule(curTick); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readIntReg(int reg_idx) -{ - return regFile.readIntReg(reg_idx); -} - -template <class Impl> -float -FullO3CPU<Impl>::readFloatRegSingle(int reg_idx) -{ - return regFile.readFloatRegSingle(reg_idx); -} - -template <class Impl> -double -FullO3CPU<Impl>::readFloatRegDouble(int reg_idx) -{ - return regFile.readFloatRegDouble(reg_idx); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readFloatRegInt(int reg_idx) -{ - return regFile.readFloatRegInt(reg_idx); -} - -template <class Impl> -void -FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) -{ - regFile.setIntReg(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegSingle(int reg_idx, float val) -{ - regFile.setFloatRegSingle(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegDouble(int reg_idx, double val) -{ - regFile.setFloatRegDouble(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegInt(int reg_idx, uint64_t val) -{ - regFile.setFloatRegInt(reg_idx, val); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - return regFile.readIntReg(phys_reg); -} - -template <class Impl> -float -FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegSingle(phys_reg); -} - -template <class Impl> -double -FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegDouble(phys_reg); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegInt(phys_reg); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setIntReg(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegSingle(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegDouble(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegInt(phys_reg, val); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readPC(unsigned tid) -{ - return commit.readPC(tid); -} - -template <class Impl> -void -FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) -{ - commit.setPC(new_PC, tid); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readNextPC(unsigned tid) -{ - return commit.readNextPC(tid); -} - -template <class Impl> -void -FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) -{ - commit.setNextPC(val, tid); -} - -template <class Impl> -typename FullO3CPU<Impl>::ListIt -FullO3CPU<Impl>::addInst(DynInstPtr &inst) -{ - instList.push_back(inst); - - return --(instList.end()); -} - -template <class Impl> -void -FullO3CPU<Impl>::instDone(unsigned tid) -{ - // Keep an instruction count. - thread[tid]->numInst++; - thread[tid]->numInsts++; - committedInsts[tid]++; - totalCommittedInsts++; - - // Check for instruction-count-based events. - comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); -} - -template <class Impl> -void -FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) -{ - removeInstsThisCycle = true; - - removeList.push(inst->getInstListIt()); -} - -template <class Impl> -void -FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) -{ - DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " - "[sn:%lli]\n", - inst->threadNumber, inst->readPC(), inst->seqNum); - - removeInstsThisCycle = true; - - // Remove the front instruction. - removeList.push(inst->getInstListIt()); -} - -template <class Impl> -void -FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) -{ - DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" - " list.\n", tid); - - ListIt end_it; - - bool rob_empty = false; - - if (instList.empty()) { - return; - } else if (rob.isEmpty(/*tid*/)) { - DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); - end_it = instList.begin(); - rob_empty = true; - } else { - end_it = (rob.readTailInst(tid))->getInstListIt(); - DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); - } - - removeInstsThisCycle = true; - - ListIt inst_it = instList.end(); - - inst_it--; - - // Walk through the instruction list, removing any instructions - // that were inserted after the given instruction iterator, end_it. - while (inst_it != end_it) { - assert(!instList.empty()); - - squashInstIt(inst_it, tid); - - inst_it--; - } - - // If the ROB was empty, then we actually need to remove the first - // instruction as well. - if (rob_empty) { - squashInstIt(inst_it, tid); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, - unsigned tid) -{ - assert(!instList.empty()); - - removeInstsThisCycle = true; - - ListIt inst_iter = instList.end(); - - inst_iter--; - - DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " - "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", - tid, seq_num, (*inst_iter)->seqNum); - - while ((*inst_iter)->seqNum > seq_num) { - - bool break_loop = (inst_iter == instList.begin()); - - squashInstIt(inst_iter, tid); - - inst_iter--; - - if (break_loop) - break; - } -} - -template <class Impl> -inline void -FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) -{ - if ((*instIt)->threadNumber == tid) { - DPRINTF(FullCPU, "FullCPU: Squashing instruction, " - "[tid:%i] [sn:%lli] PC %#x\n", - (*instIt)->threadNumber, - (*instIt)->seqNum, - (*instIt)->readPC()); - - // Mark it as squashed. - (*instIt)->setSquashed(); - - // @todo: Formulate a consistent method for deleting - // instructions from the instruction list - // Remove the instruction from the list. - removeList.push(instIt); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::cleanUpRemovedInsts() -{ - while (!removeList.empty()) { - DPRINTF(FullCPU, "FullCPU: Removing instruction, " - "[tid:%i] [sn:%lli] PC %#x\n", - (*removeList.front())->threadNumber, - (*removeList.front())->seqNum, - (*removeList.front())->readPC()); - - instList.erase(removeList.front()); - - removeList.pop(); - } - - removeInstsThisCycle = false; -} -/* -template <class Impl> -void -FullO3CPU<Impl>::removeAllInsts() -{ - instList.clear(); -} -*/ -template <class Impl> -void -FullO3CPU<Impl>::dumpInsts() -{ - int num = 0; - - ListIt inst_list_it = instList.begin(); - - cprintf("Dumping Instruction List\n"); - - while (inst_list_it != instList.end()) { - cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" - "Squashed:%i\n\n", - num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, - (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - inst_list_it++; - ++num; - } -} -/* -template <class Impl> -void -FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) -{ - iew.wakeDependents(inst); -} -*/ -template <class Impl> -void -FullO3CPU<Impl>::wakeCPU() -{ - if (activityRec.active() || tickEvent.scheduled()) { - DPRINTF(Activity, "CPU already running.\n"); - return; - } - - DPRINTF(Activity, "Waking up CPU\n"); - - idleCycles += (curTick - 1) - lastRunningCycle; - - tickEvent.schedule(curTick); -} - -template <class Impl> -int -FullO3CPU<Impl>::getFreeTid() -{ - for (int i=0; i < numThreads; i++) { - if (!tids[i]) { - tids[i] = true; - return i; - } - } - - return -1; -} - -template <class Impl> -void -FullO3CPU<Impl>::doContextSwitch() -{ - if (contextSwitch) { - - //ADD CODE TO DEACTIVE THREAD HERE (???) - - for (int tid=0; tid < cpuWaitList.size(); tid++) { - activateWhenReady(tid); - } - - if (cpuWaitList.size() == 0) - contextSwitch = true; - } -} - -template <class Impl> -void -FullO3CPU<Impl>::updateThreadPriority() -{ - if (activeThreads.size() > 1) - { - //DEFAULT TO ROUND ROBIN SCHEME - //e.g. Move highest priority to end of thread list - list<unsigned>::iterator list_begin = activeThreads.begin(); - list<unsigned>::iterator list_end = activeThreads.end(); - - unsigned high_thread = *list_begin; - - activeThreads.erase(list_begin); - - activeThreads.push_back(high_thread); - } -} - -// Forward declaration of FullO3CPU. -template class FullO3CPU<AlphaSimpleImpl>; diff --git a/cpu/o3/cpu.hh b/cpu/o3/cpu.hh deleted file mode 100644 index 8db65d501..000000000 --- a/cpu/o3/cpu.hh +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_CPU_HH__ -#define __CPU_O3_CPU_HH__ - -#include <iostream> -#include <list> -#include <queue> -#include <set> -#include <vector> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/activity.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/cpu_policy.hh" -#include "cpu/o3/scoreboard.hh" -#include "cpu/o3/thread_state.hh" -#include "sim/process.hh" - -template <class> -class Checker; -class ExecContext; -class MemInterface; -class Process; - -class BaseFullCPU : public BaseCPU -{ - //Stuff that's pretty ISA independent will go here. - public: - typedef BaseCPU::Params Params; - - BaseFullCPU(Params *params); - - void regStats(); - - protected: - int cpu_id; -}; - -template <class Impl> -class FullO3CPU : public BaseFullCPU -{ - public: - // Typedefs from the Impl here. - typedef typename Impl::CPUPol CPUPolicy; - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef O3ThreadState<Impl> Thread; - - typedef typename std::list<DynInstPtr>::iterator ListIt; - - public: - enum Status { - Running, - Idle, - Halted, - Blocked, - SwitchedOut - }; - - /** Overall CPU status. */ - Status _status; - - private: - class TickEvent : public Event - { - private: - /** Pointer to the CPU. */ - FullO3CPU<Impl> *cpu; - - public: - /** Constructs a tick event. */ - TickEvent(FullO3CPU<Impl> *c); - - /** Processes a tick event, calling tick() on the CPU. */ - void process(); - /** Returns the description of the tick event. */ - const char *description(); - }; - - /** The tick event used for scheduling CPU ticks. */ - TickEvent tickEvent; - - /** Schedule tick event, regardless of its current state. */ - void scheduleTickEvent(int delay) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(delay)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(delay)); - } - - /** Unschedule tick event, regardless of its current state. */ - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - public: - /** Constructs a CPU with the given parameters. */ - FullO3CPU(Params *params); - /** Destructor. */ - ~FullO3CPU(); - - /** Registers statistics. */ - void fullCPURegStats(); - - /** Ticks CPU, calling tick() on each stage, and checking the overall - * activity to see if the CPU should deschedule itself. - */ - void tick(); - - /** Initialize the CPU */ - void init(); - - /** Setup CPU to insert a thread's context */ - void insertThread(unsigned tid); - - /** Remove all of a thread's context from CPU */ - void removeThread(unsigned tid); - - /** Count the Total Instructions Committed in the CPU. */ - virtual Counter totalInstructions() const - { - Counter total(0); - - for (int i=0; i < thread.size(); i++) - total += thread[i]->numInst; - - return total; - } - - /** Add Thread to Active Threads List. */ - void activateContext(int tid, int delay); - - /** Remove Thread from Active Threads List */ - void suspendContext(int tid); - - /** Remove Thread from Active Threads List && - * Remove Thread Context from CPU. - */ - void deallocateContext(int tid); - - /** Remove Thread from Active Threads List && - * Remove Thread Context from CPU. - */ - void haltContext(int tid); - - /** Activate a Thread When CPU Resources are Available. */ - void activateWhenReady(int tid); - - /** Add or Remove a Thread Context in the CPU. */ - void doContextSwitch(); - - /** Update The Order In Which We Process Threads. */ - void updateThreadPriority(); - - /** Executes a syscall on this cycle. - * --------------------------------------- - * Note: this is a virtual function. CPU-Specific - * functionality defined in derived classes - */ - virtual void syscall(int tid) { panic("Unimplemented!"); } - - /** Check if there are any system calls pending. */ - void checkSyscalls(); - - /** Switches out this CPU. - */ - void switchOut(Sampler *sampler); - - void signalSwitched(); - - /** Takes over from another CPU. - */ - void takeOverFrom(BaseCPU *oldCPU); - - /** Get the current instruction sequence number, and increment it. */ - InstSeqNum getAndIncrementInstSeq() - { return globalSeqNum++; } - -#if FULL_SYSTEM - /** Check if this address is a valid instruction address. */ - bool validInstAddr(Addr addr) { return true; } - - /** Check if this address is a valid data address. */ - bool validDataAddr(Addr addr) { return true; } - - /** Get instruction asid. */ - int getInstAsid(unsigned tid) - { return regFile.miscRegs[tid].getInstAsid(); } - - /** Get data asid. */ - int getDataAsid(unsigned tid) - { return regFile.miscRegs[tid].getDataAsid(); } -#else - /** Check if this address is a valid instruction address. */ - bool validInstAddr(Addr addr,unsigned tid) - { return thread[tid]->validInstAddr(addr); } - - /** Check if this address is a valid data address. */ - bool validDataAddr(Addr addr,unsigned tid) - { return thread[tid]->validDataAddr(addr); } - - /** Get instruction asid. */ - int getInstAsid(unsigned tid) - { return thread[tid]->asid; } - - /** Get data asid. */ - int getDataAsid(unsigned tid) - { return thread[tid]->asid; } - -#endif - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx); - - float readFloatRegSingle(int reg_idx); - - double readFloatRegDouble(int reg_idx); - - uint64_t readFloatRegInt(int reg_idx); - - void setIntReg(int reg_idx, uint64_t val); - - void setFloatRegSingle(int reg_idx, float val); - - void setFloatRegDouble(int reg_idx, double val); - - void setFloatRegInt(int reg_idx, uint64_t val); - - uint64_t readArchIntReg(int reg_idx, unsigned tid); - - float readArchFloatRegSingle(int reg_idx, unsigned tid); - - double readArchFloatRegDouble(int reg_idx, unsigned tid); - - uint64_t readArchFloatRegInt(int reg_idx, unsigned tid); - - void setArchIntReg(int reg_idx, uint64_t val, unsigned tid); - - void setArchFloatRegSingle(int reg_idx, float val, unsigned tid); - - void setArchFloatRegDouble(int reg_idx, double val, unsigned tid); - - void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid); - - uint64_t readPC(unsigned tid); - - void setPC(Addr new_PC,unsigned tid); - - uint64_t readNextPC(unsigned tid); - - void setNextPC(uint64_t val,unsigned tid); - - /** Function to add instruction onto the head of the list of the - * instructions. Used when new instructions are fetched. - */ - ListIt addInst(DynInstPtr &inst); - - /** Function to tell the CPU that an instruction has completed. */ - void instDone(unsigned tid); - - /** Add Instructions to the CPU Remove List*/ - void addToRemoveList(DynInstPtr &inst); - - /** Remove an instruction from the front end of the list. There's - * no restriction on location of the instruction. - */ - void removeFrontInst(DynInstPtr &inst); - - /** Remove all instructions that are not currently in the ROB. */ - void removeInstsNotInROB(unsigned tid); - - /** Remove all instructions younger than the given sequence number. */ - void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); - - inline void squashInstIt(const ListIt &instIt, const unsigned &tid); - - void cleanUpRemovedInsts(); - - /** Remove all instructions from the list. */ -// void removeAllInsts(); - - void dumpInsts(); - - /** Basically a wrapper function so that instructions executed at - * commit can tell the instruction queue that they have - * completed. Eventually this hack should be removed. - */ -// void wakeDependents(DynInstPtr &inst); - - public: - /** List of all the instructions in flight. */ - std::list<DynInstPtr> instList; - - /** List of all the instructions that will be removed at the end of this - * cycle. - */ - std::queue<ListIt> removeList; - -#ifdef DEBUG - std::set<InstSeqNum> snList; -#endif - - /** Records if instructions need to be removed this cycle due to - * being retired or squashed. - */ - bool removeInstsThisCycle; - - protected: - /** The fetch stage. */ - typename CPUPolicy::Fetch fetch; - - /** The decode stage. */ - typename CPUPolicy::Decode decode; - - /** The dispatch stage. */ - typename CPUPolicy::Rename rename; - - /** The issue/execute/writeback stages. */ - typename CPUPolicy::IEW iew; - - /** The commit stage. */ - typename CPUPolicy::Commit commit; - - /** The register file. */ - typename CPUPolicy::RegFile regFile; - - /** The free list. */ - typename CPUPolicy::FreeList freeList; - - /** The rename map. */ - typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads]; - - /** The commit rename map. */ - typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads]; - - /** The re-order buffer. */ - typename CPUPolicy::ROB rob; - - /** Active Threads List */ - std::list<unsigned> activeThreads; - - /** Integer Register Scoreboard */ - Scoreboard scoreboard; - - public: - /** Enum to give each stage a specific index, so when calling - * activateStage() or deactivateStage(), they can specify which stage - * is being activated/deactivated. - */ - enum StageIdx { - FetchIdx, - DecodeIdx, - RenameIdx, - IEWIdx, - CommitIdx, - NumStages }; - - /** Typedefs from the Impl to get the structs that each of the - * time buffers should use. - */ - typedef typename CPUPolicy::TimeStruct TimeStruct; - - typedef typename CPUPolicy::FetchStruct FetchStruct; - - typedef typename CPUPolicy::DecodeStruct DecodeStruct; - - typedef typename CPUPolicy::RenameStruct RenameStruct; - - typedef typename CPUPolicy::IEWStruct IEWStruct; - - /** The main time buffer to do backwards communication. */ - TimeBuffer<TimeStruct> timeBuffer; - - /** The fetch stage's instruction queue. */ - TimeBuffer<FetchStruct> fetchQueue; - - /** The decode stage's instruction queue. */ - TimeBuffer<DecodeStruct> decodeQueue; - - /** The rename stage's instruction queue. */ - TimeBuffer<RenameStruct> renameQueue; - - /** The IEW stage's instruction queue. */ - TimeBuffer<IEWStruct> iewQueue; - - public: - ActivityRecorder activityRec; - - void activityThisCycle() { activityRec.activity(); } - - void activateStage(const StageIdx idx) - { activityRec.activateStage(idx); } - - void deactivateStage(const StageIdx idx) - { activityRec.deactivateStage(idx); } - - /** Wakes the CPU, rescheduling the CPU if it's not already active. */ - void wakeCPU(); - - /** Gets a free thread id. Use if thread ids change across system. */ - int getFreeTid(); - - public: - /** Temporary function to get pointer to exec context. */ - ExecContext *xcBase(unsigned tid) - { - return thread[tid]->getXCProxy(); - } - - /** The global sequence number counter. */ - InstSeqNum globalSeqNum; - - Checker<DynInstPtr> *checker; - -#if FULL_SYSTEM - /** Pointer to the system. */ - System *system; - - /** Pointer to the memory controller. */ - MemoryController *memCtrl; - /** Pointer to physical memory. */ - PhysicalMemory *physmem; -#endif - - /** Pointer to memory. */ - FunctionalMemory *mem; - - Sampler *sampler; - - int switchCount; - - // List of all ExecContexts. - std::vector<Thread *> thread; - -#if 0 - /** Page table pointer. */ - PageTable *pTable; -#endif - - /** Pointer to the icache interface. */ - MemInterface *icacheInterface; - /** Pointer to the dcache interface. */ - MemInterface *dcacheInterface; - - /** Whether or not the CPU should defer its registration. */ - bool deferRegistration; - - /** Is there a context switch pending? */ - bool contextSwitch; - - /** Threads Scheduled to Enter CPU */ - std::list<int> cpuWaitList; - - /** The cycle that the CPU was last running, used for statistics. */ - Tick lastRunningCycle; - - /** Number of Threads CPU can process */ - unsigned numThreads; - - /** Mapping for system thread id to cpu id */ - std::map<unsigned,unsigned> threadMap; - - /** Available thread ids in the cpu*/ - std::vector<unsigned> tids; - - /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; - /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; - /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; - /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; - /** Stat for the CPI per thread. */ - Stats::Formula cpi; - /** Stat for the total CPI. */ - Stats::Formula totalCpi; - /** Stat for the IPC per thread. */ - Stats::Formula ipc; - /** Stat for the total IPC. */ - Stats::Formula totalIpc; -}; - -#endif // __CPU_O3_CPU_HH__ diff --git a/cpu/o3/cpu_policy.hh b/cpu/o3/cpu_policy.hh deleted file mode 100644 index 52227013e..000000000 --- a/cpu/o3/cpu_policy.hh +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_CPU_POLICY_HH__ -#define __CPU_O3_CPU_POLICY_HH__ - -#include "cpu/o3/bpred_unit.hh" -#include "cpu/o3/free_list.hh" -#include "cpu/o3/inst_queue.hh" -#include "cpu/o3/lsq.hh" -#include "cpu/o3/lsq_unit.hh" -#include "cpu/o3/mem_dep_unit.hh" -#include "cpu/o3/regfile.hh" -#include "cpu/o3/rename_map.hh" -#include "cpu/o3/rob.hh" -#include "cpu/o3/store_set.hh" - -#include "cpu/o3/commit.hh" -#include "cpu/o3/decode.hh" -#include "cpu/o3/fetch.hh" -#include "cpu/o3/iew.hh" -#include "cpu/o3/rename.hh" - -#include "cpu/o3/comm.hh" - -template<class Impl> -struct SimpleCPUPolicy -{ - typedef TwobitBPredUnit<Impl> BPredUnit; - typedef PhysRegFile<Impl> RegFile; - typedef SimpleFreeList FreeList; - typedef SimpleRenameMap RenameMap; - typedef ROB<Impl> ROB; - typedef InstructionQueue<Impl> IQ; - typedef MemDepUnit<StoreSet, Impl> MemDepUnit; - typedef LSQ<Impl> LSQ; - typedef LSQUnit<Impl> LSQUnit; - - - typedef DefaultFetch<Impl> Fetch; - typedef DefaultDecode<Impl> Decode; - typedef DefaultRename<Impl> Rename; - typedef DefaultIEW<Impl> IEW; - typedef DefaultCommit<Impl> Commit; - - /** The struct for communication between fetch and decode. */ - typedef DefaultFetchDefaultDecode<Impl> FetchStruct; - - /** The struct for communication between decode and rename. */ - typedef DefaultDecodeDefaultRename<Impl> DecodeStruct; - - /** The struct for communication between rename and IEW. */ - typedef DefaultRenameDefaultIEW<Impl> RenameStruct; - - /** The struct for communication between IEW and commit. */ - typedef DefaultIEWDefaultCommit<Impl> IEWStruct; - - /** The struct for communication within the IEW stage. */ - typedef IssueStruct<Impl> IssueStruct; - - /** The struct for all backwards communication. */ - typedef TimeBufStruct<Impl> TimeStruct; - -}; - -#endif //__CPU_O3_CPU_POLICY_HH__ diff --git a/cpu/o3/decode.cc b/cpu/o3/decode.cc deleted file mode 100644 index b14fbb7a3..000000000 --- a/cpu/o3/decode.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/decode_impl.hh" - -template class DefaultDecode<AlphaSimpleImpl>; diff --git a/cpu/o3/decode.hh b/cpu/o3/decode.hh deleted file mode 100644 index 3035b3387..000000000 --- a/cpu/o3/decode.hh +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_DECODE_HH__ -#define __CPU_O3_DECODE_HH__ - -#include <queue> - -#include "base/statistics.hh" -#include "base/timebuf.hh" - -/** - * DefaultDecode class handles both single threaded and SMT - * decode. Its width is specified by the parameters; each cycles it - * tries to decode that many instructions. Because instructions are - * actually decoded when the StaticInst is created, this stage does - * not do much other than check any PC-relative branches. - */ -template<class Impl> -class DefaultDecode -{ - private: - // Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - typedef typename Impl::CPUPol CPUPol; - - // Typedefs from the CPU policy. - typedef typename CPUPol::FetchStruct FetchStruct; - typedef typename CPUPol::DecodeStruct DecodeStruct; - typedef typename CPUPol::TimeStruct TimeStruct; - - public: - /** Overall decode stage status. Used to determine if the CPU can - * deschedule itself due to a lack of activity. - */ - enum DecodeStatus { - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - StartSquash, - Squashing, - Blocked, - Unblocking - }; - - private: - /** Decode status. */ - DecodeStatus _status; - - /** Per-thread status. */ - ThreadStatus decodeStatus[Impl::MaxThreads]; - - public: - /** DefaultDecode constructor. */ - DefaultDecode(Params *params); - - /** Returns the name of decode. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the main backwards communication time buffer pointer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Sets pointer to time buffer used to communicate to the next stage. */ - void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr); - - /** Sets pointer to time buffer coming from fetch. */ - void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - void switchOut(); - - void takeOverFrom(); - /** Ticks decode, processing all input signals and decoding as many - * instructions as possible. - */ - void tick(); - - /** Determines what to do based on decode's current status. - * @param status_change decode() sets this variable if there was a status - * change (ie switching from from blocking to unblocking). - * @param tid Thread id to decode instructions from. - */ - void decode(bool &status_change, unsigned tid); - - /** Processes instructions from fetch and passes them on to rename. - * Decoding of instructions actually happens when they are created in - * fetch, so this function mostly checks if PC-relative branches are - * correct. - */ - void decodeInsts(unsigned tid); - - private: - /** Inserts a thread's instructions into the skid buffer, to be decoded - * once decode unblocks. - */ - void skidInsert(unsigned tid); - - /** Returns if all of the skid buffers are empty. */ - bool skidsEmpty(); - - /** Updates overall decode status based on all of the threads' statuses. */ - void updateStatus(); - - /** Separates instructions from fetch into individual lists of instructions - * sorted by thread. - */ - void sortInsts(); - - /** Reads all stall signals from the backwards communication timebuffer. */ - void readStallSignals(unsigned tid); - - /** Checks all input signals and updates decode's status appropriately. */ - bool checkSignalsAndUpdate(unsigned tid); - - /** Checks all stall signals, and returns if any are true. */ - bool checkStall(unsigned tid) const; - - /** Returns if there any instructions from fetch on this cycle. */ - inline bool fetchInstsValid(); - - /** Switches decode to blocking, and signals back that decode has - * become blocked. - * @return Returns true if there is a status change. - */ - bool block(unsigned tid); - - /** Switches decode to unblocking if the skid buffer is empty, and - * signals back that decode has unblocked. - * @return Returns true if there is a status change. - */ - bool unblock(unsigned tid); - - /** Squashes if there is a PC-relative branch that was predicted - * incorrectly. Sends squash information back to fetch. - */ - void squash(DynInstPtr &inst, unsigned tid); - - public: - /** Squashes due to commit signalling a squash. Changes status to - * squashing and clears block/unblock signals as needed. - */ - unsigned squash(unsigned tid); - - private: - // Interfaces to objects outside of decode. - /** CPU interface. */ - FullCPU *cpu; - - /** Time buffer interface. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to get rename's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromRename; - - /** Wire to get iew's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromIEW; - - /** Wire to get commit's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Wire to write information heading to previous stages. */ - // Might not be the best name as not only fetch will read it. - typename TimeBuffer<TimeStruct>::wire toFetch; - - /** Decode instruction queue. */ - TimeBuffer<DecodeStruct> *decodeQueue; - - /** Wire used to write any information heading to rename. */ - typename TimeBuffer<DecodeStruct>::wire toRename; - - /** Fetch instruction queue interface. */ - TimeBuffer<FetchStruct> *fetchQueue; - - /** Wire to get fetch's output from fetch queue. */ - typename TimeBuffer<FetchStruct>::wire fromFetch; - - /** Queue of all instructions coming from fetch this cycle. */ - std::queue<DynInstPtr> insts[Impl::MaxThreads]; - - /** Skid buffer between fetch and decode. */ - std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads]; - - /** Variable that tracks if decode has written to the time buffer this - * cycle. Used to tell CPU if there is activity this cycle. - */ - bool wroteToTimeBuffer; - - /** Source of possible stalls. */ - struct Stalls { - bool rename; - bool iew; - bool commit; - }; - - /** Tracks which stages are telling decode to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** Rename to decode delay, in ticks. */ - unsigned renameToDecodeDelay; - - /** IEW to decode delay, in ticks. */ - unsigned iewToDecodeDelay; - - /** Commit to decode delay, in ticks. */ - unsigned commitToDecodeDelay; - - /** Fetch to decode delay, in ticks. */ - unsigned fetchToDecodeDelay; - - /** The width of decode, in instructions. */ - unsigned decodeWidth; - - /** Index of instructions being sent to rename. */ - unsigned toRenameIndex; - - /** number of Active Threads*/ - unsigned numThreads; - - /** List of active thread ids */ - std::list<unsigned> *activeThreads; - - /** Number of branches in flight. */ - unsigned branchCount[Impl::MaxThreads]; - - /** Maximum size of the skid buffer. */ - unsigned skidBufferMax; - - /** Stat for total number of idle cycles. */ - Stats::Scalar<> decodeIdleCycles; - /** Stat for total number of blocked cycles. */ - Stats::Scalar<> decodeBlockedCycles; - /** Stat for total number of normal running cycles. */ - Stats::Scalar<> decodeRunCycles; - /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> decodeUnblockCycles; - /** Stat for total number of squashing cycles. */ - Stats::Scalar<> decodeSquashCycles; - /** Stat for number of times a branch is resolved at decode. */ - Stats::Scalar<> decodeBranchResolved; - /** Stat for number of times a branch mispredict is detected. */ - Stats::Scalar<> decodeBranchMispred; - /** Stat for number of times decode detected a non-control instruction - * incorrectly predicted as a branch. - */ - Stats::Scalar<> decodeControlMispred; - /** Stat for total number of decoded instructions. */ - Stats::Scalar<> decodeDecodedInsts; - /** Stat for total number of squashed instructions. */ - Stats::Scalar<> decodeSquashedInsts; -}; - -#endif // __CPU_O3_DECODE_HH__ diff --git a/cpu/o3/decode_impl.hh b/cpu/o3/decode_impl.hh deleted file mode 100644 index 2ed7ec6fc..000000000 --- a/cpu/o3/decode_impl.hh +++ /dev/null @@ -1,741 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/decode.hh" - -using namespace std; - -template<class Impl> -DefaultDecode<Impl>::DefaultDecode(Params *params) - : renameToDecodeDelay(params->renameToDecodeDelay), - iewToDecodeDelay(params->iewToDecodeDelay), - commitToDecodeDelay(params->commitToDecodeDelay), - fetchToDecodeDelay(params->fetchToDecodeDelay), - decodeWidth(params->decodeWidth), - numThreads(params->numberOfThreads) -{ - _status = Inactive; - - for (int i = 0; i < numThreads; ++i) { - decodeStatus[i] = Idle; - - stalls[i].rename = false; - stalls[i].iew = false; - stalls[i].commit = false; - } - - // @todo: Make into a parameter - skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; -} - -template <class Impl> -std::string -DefaultDecode<Impl>::name() const -{ - return cpu->name() + ".decode"; -} - -template <class Impl> -void -DefaultDecode<Impl>::regStats() -{ - decodeIdleCycles - .name(name() + ".DECODE:IdleCycles") - .desc("Number of cycles decode is idle") - .prereq(decodeIdleCycles); - decodeBlockedCycles - .name(name() + ".DECODE:BlockedCycles") - .desc("Number of cycles decode is blocked") - .prereq(decodeBlockedCycles); - decodeRunCycles - .name(name() + ".DECODE:RunCycles") - .desc("Number of cycles decode is running") - .prereq(decodeRunCycles); - decodeUnblockCycles - .name(name() + ".DECODE:UnblockCycles") - .desc("Number of cycles decode is unblocking") - .prereq(decodeUnblockCycles); - decodeSquashCycles - .name(name() + ".DECODE:SquashCycles") - .desc("Number of cycles decode is squashing") - .prereq(decodeSquashCycles); - decodeBranchResolved - .name(name() + ".DECODE:BranchResolved") - .desc("Number of times decode resolved a branch") - .prereq(decodeBranchResolved); - decodeBranchMispred - .name(name() + ".DECODE:BranchMispred") - .desc("Number of times decode detected a branch misprediction") - .prereq(decodeBranchMispred); - decodeControlMispred - .name(name() + ".DECODE:ControlMispred") - .desc("Number of times decode detected an instruction incorrectly" - " predicted as a control") - .prereq(decodeControlMispred); - decodeDecodedInsts - .name(name() + ".DECODE:DecodedInsts") - .desc("Number of instructions handled by decode") - .prereq(decodeDecodedInsts); - decodeSquashedInsts - .name(name() + ".DECODE:SquashedInsts") - .desc("Number of squashed instructions handled by decode") - .prereq(decodeSquashedInsts); -} - -template<class Impl> -void -DefaultDecode<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Decode, "Setting CPU pointer.\n"); - cpu = cpu_ptr; -} - -template<class Impl> -void -DefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(Decode, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to write information back to fetch. - toFetch = timeBuffer->getWire(0); - - // Create wires to get information from proper places in time buffer. - fromRename = timeBuffer->getWire(-renameToDecodeDelay); - fromIEW = timeBuffer->getWire(-iewToDecodeDelay); - fromCommit = timeBuffer->getWire(-commitToDecodeDelay); -} - -template<class Impl> -void -DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) -{ - DPRINTF(Decode, "Setting decode queue pointer.\n"); - decodeQueue = dq_ptr; - - // Setup wire to write information to proper place in decode queue. - toRename = decodeQueue->getWire(0); -} - -template<class Impl> -void -DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) -{ - DPRINTF(Decode, "Setting fetch queue pointer.\n"); - fetchQueue = fq_ptr; - - // Setup wire to read information from fetch queue. - fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); -} - -template<class Impl> -void -DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Decode, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -DefaultDecode<Impl>::switchOut() -{ - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultDecode<Impl>::takeOverFrom() -{ - _status = Inactive; - - for (int i = 0; i < numThreads; ++i) { - decodeStatus[i] = Idle; - - stalls[i].rename = false; - stalls[i].iew = false; - stalls[i].commit = false; - while (!insts[i].empty()) - insts[i].pop(); - while (!skidBuffer[i].empty()) - skidBuffer[i].pop(); - branchCount[i] = 0; - } - wroteToTimeBuffer = false; -} - -template<class Impl> -bool -DefaultDecode<Impl>::checkStall(unsigned tid) const -{ - bool ret_val = false; - - if (stalls[tid].rename) { - DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); - ret_val = true; - } else if (stalls[tid].iew) { - DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); - ret_val = true; - } else if (stalls[tid].commit) { - DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); - ret_val = true; - } - - return ret_val; -} - -template<class Impl> -inline bool -DefaultDecode<Impl>::fetchInstsValid() -{ - return fromFetch->size > 0; -} - -template<class Impl> -bool -DefaultDecode<Impl>::block(unsigned tid) -{ - DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); - - // If the decode status is blocked or unblocking then decode has not yet - // signalled fetch to unblock. In that case, there is no need to tell - // fetch to block. - if (decodeStatus[tid] != Blocked && - decodeStatus[tid] != Unblocking) { - toFetch->decodeBlock[tid] = true; - wroteToTimeBuffer = true; - } - - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - - if (decodeStatus[tid] != Blocked) { - // Set the status to Blocked. - decodeStatus[tid] = Blocked; - return true; - } - - return false; -} - -template<class Impl> -bool -DefaultDecode<Impl>::unblock(unsigned tid) -{ - // Decode is done unblocking only if the skid buffer is empty. - if (skidBuffer[tid].empty()) { - DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); - toFetch->decodeUnblock[tid] = true; - wroteToTimeBuffer = true; - - decodeStatus[tid] = Running; - return true; - } - - DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); - - return false; -} - -template<class Impl> -void -DefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction " - "detected at decode.\n", tid); - - toFetch->decodeInfo[tid].branchMispredict = true; - toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; - toFetch->decodeInfo[tid].predIncorrect = true; - toFetch->decodeInfo[tid].squash = true; - toFetch->decodeInfo[tid].nextPC = inst->readNextPC(); - toFetch->decodeInfo[tid].branchTaken = true; - - if (decodeStatus[tid] == Blocked || - decodeStatus[tid] == Unblocking) { - toFetch->decodeUnblock[tid] = 1; - } - - // Set status to squashing. - decodeStatus[tid] = Squashing; - - for (int i=0; i<fromFetch->size; i++) { - if (fromFetch->insts[i]->threadNumber == tid && - fromFetch->insts[i]->seqNum > inst->seqNum) { - fromFetch->insts[i]->squashed = true; - } - } - - while (!insts[tid].empty()) { - insts[tid].pop(); - } - - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer[tid].empty()) { - skidBuffer[tid].pop(); - } - - // Squash instructions up until this one - cpu->removeInstsUntil(inst->seqNum, tid); -} - -template<class Impl> -unsigned -DefaultDecode<Impl>::squash(unsigned tid) -{ - DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); - - if (decodeStatus[tid] == Blocked || - decodeStatus[tid] == Unblocking) { -#if !FULL_SYSTEM - // In syscall emulation, we can have both a block and a squash due - // to a syscall in the same cycle. This would cause both signals to - // be high. This shouldn't happen in full system. - // @todo: Determine if this still happens. - if (toFetch->decodeBlock[tid]) { - toFetch->decodeBlock[tid] = 0; - } else { - toFetch->decodeUnblock[tid] = 1; - } -#else - toFetch->decodeUnblock[tid] = 1; -#endif - } - - // Set status to squashing. - decodeStatus[tid] = Squashing; - - // Go through incoming instructions from fetch and squash them. - unsigned squash_count = 0; - - for (int i=0; i<fromFetch->size; i++) { - if (fromFetch->insts[i]->threadNumber == tid) { - fromFetch->insts[i]->squashed = true; - squash_count++; - } - } - - while (!insts[tid].empty()) { - insts[tid].pop(); - } - - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer[tid].empty()) { - skidBuffer[tid].pop(); - } - - return squash_count; -} - -template<class Impl> -void -DefaultDecode<Impl>::skidInsert(unsigned tid) -{ - DynInstPtr inst = NULL; - - while (!insts[tid].empty()) { - inst = insts[tid].front(); - - insts[tid].pop(); - - assert(tid == inst->threadNumber); - - DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n", - inst->seqNum, inst->readPC(), inst->threadNumber); - - skidBuffer[tid].push(inst); - } - - // @todo: Eventually need to enforce this by not letting a thread - // fetch past its skidbuffer - assert(skidBuffer[tid].size() <= skidBufferMax); -} - -template<class Impl> -bool -DefaultDecode<Impl>::skidsEmpty() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - -template<class Impl> -void -DefaultDecode<Impl>::updateStatus() -{ - bool any_unblocking = false; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (decodeStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // Decode will have activity if it's unblocking. - if (any_unblocking) { - if (_status == Inactive) { - _status = Active; - - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(FullCPU::DecodeIdx); - } - } else { - // If it's not unblocking, then decode will not have any internal - // activity. Switch it to inactive. - if (_status == Active) { - _status = Inactive; - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::DecodeIdx); - } - } -} - -template <class Impl> -void -DefaultDecode<Impl>::sortInsts() -{ - int insts_from_fetch = fromFetch->size; -#ifdef DEBUG - for (int i=0; i < numThreads; i++) - assert(insts[i].empty()); -#endif - for (int i = 0; i < insts_from_fetch; ++i) { - insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); - } -} - -template<class Impl> -void -DefaultDecode<Impl>::readStallSignals(unsigned tid) -{ - if (fromRename->renameBlock[tid]) { - stalls[tid].rename = true; - } - - if (fromRename->renameUnblock[tid]) { - assert(stalls[tid].rename); - stalls[tid].rename = false; - } - - if (fromIEW->iewBlock[tid]) { - stalls[tid].iew = true; - } - - if (fromIEW->iewUnblock[tid]) { - assert(stalls[tid].iew); - stalls[tid].iew = false; - } - - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - stalls[tid].commit = false; - } -} - -template <class Impl> -bool -DefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Check if there's a squash signal, squash if there is. - // Check stall signals, block if necessary. - // If status was blocked - // Check if stall conditions have passed - // if so then go to unblocking - // If status was Squashing - // check if squashing is not high. Switch to running this cycle. - - // Update the per thread stall statuses. - readStallSignals(tid); - - // Check squash signals from commit. - if (fromCommit->commitInfo[tid].squash) { - - DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " - "from commit.\n", tid); - - squash(tid); - - return true; - } - - // Check ROB squash signals from commit. - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(Decode, "[tid:%]: ROB is still squashing.\n",tid); - - // Continue to squash. - decodeStatus[tid] = Squashing; - - return true; - } - - if (checkStall(tid)) { - return block(tid); - } - - if (decodeStatus[tid] == Blocked) { - DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", - tid); - - decodeStatus[tid] = Unblocking; - - unblock(tid); - - return true; - } - - if (decodeStatus[tid] == Squashing) { - // Switch status to running if decode isn't being told to block or - // squash this cycle. - DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", - tid); - - decodeStatus[tid] = Running; - - return false; - } - - // If we've reached this point, we have not gotten any signals that - // cause decode to change its status. Decode remains the same as before. - return false; -} - -template<class Impl> -void -DefaultDecode<Impl>::tick() -{ - wroteToTimeBuffer = false; - - bool status_change = false; - - toRenameIndex = 0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - sortInsts(); - - //Check stall and squash signals. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - DPRINTF(Decode,"Processing [tid:%i]\n",tid); - status_change = checkSignalsAndUpdate(tid) || status_change; - - decode(status_change, tid); - } - - if (status_change) { - updateStatus(); - } - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - - cpu->activityThisCycle(); - } -} - -template<class Impl> -void -DefaultDecode<Impl>::decode(bool &status_change, unsigned tid) -{ - // If status is Running or idle, - // call decodeInsts() - // If status is Unblocking, - // buffer any instructions coming from fetch - // continue trying to empty skid buffer - // check if stall conditions have passed - - if (decodeStatus[tid] == Blocked) { - ++decodeBlockedCycles; - } else if (decodeStatus[tid] == Squashing) { - ++decodeSquashCycles; - } - - // Decode should try to decode as many instructions as its bandwidth - // will allow, as long as it is not currently blocked. - if (decodeStatus[tid] == Running || - decodeStatus[tid] == Idle) { - DPRINTF(Decode, "[tid:%u] Not blocked, so attempting to run " - "stage.\n",tid); - - decodeInsts(tid); - } else if (decodeStatus[tid] == Unblocking) { - // Make sure that the skid buffer has something in it if the - // status is unblocking. - assert(!skidsEmpty()); - - // If the status was unblocking, then instructions from the skid - // buffer were used. Remove those instructions and handle - // the rest of unblocking. - decodeInsts(tid); - - if (fetchInstsValid()) { - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - } - - status_change = unblock(tid) || status_change; - } -} - -template <class Impl> -void -DefaultDecode<Impl>::decodeInsts(unsigned tid) -{ - // Instructions can come either from the skid buffer or the list of - // instructions coming from fetch, depending on decode's status. - int insts_available = decodeStatus[tid] == Unblocking ? - skidBuffer[tid].size() : insts[tid].size(); - - if (insts_available == 0) { - DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" - " early.\n",tid); - // Should I change the status to idle? - ++decodeIdleCycles; - return; - } else if (decodeStatus[tid] == Unblocking) { - DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " - "buffer.\n",tid); - ++decodeUnblockCycles; - } else if (decodeStatus[tid] == Running) { - ++decodeRunCycles; - } - - DynInstPtr inst; - - std::queue<DynInstPtr> - &insts_to_decode = decodeStatus[tid] == Unblocking ? - skidBuffer[tid] : insts[tid]; - - DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); - - while (insts_available > 0 && toRenameIndex < decodeWidth) { - assert(!insts_to_decode.empty()); - - inst = insts_to_decode.front(); - - insts_to_decode.pop(); - - DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " - "PC %#x\n", - tid, inst->seqNum, inst->readPC()); - - if (inst->isSquashed()) { - DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is " - "squashed, skipping.\n", - tid, inst->seqNum, inst->readPC()); - - ++decodeSquashedInsts; - - --insts_available; - - continue; - } - - // Also check if instructions have no source registers. Mark - // them as ready to issue at any time. Not sure if this check - // should exist here or at a later stage; however it doesn't matter - // too much for function correctness. - if (inst->numSrcRegs() == 0) { - inst->setCanIssue(); - } - - // This current instruction is valid, so add it into the decode - // queue. The next instruction may not be valid, so check to - // see if branches were predicted correctly. - toRename->insts[toRenameIndex] = inst; - - ++(toRename->size); - ++toRenameIndex; - ++decodeDecodedInsts; - --insts_available; - - // Ensure that if it was predicted as a branch, it really is a - // branch. - if (inst->predTaken() && !inst->isControl()) { - panic("Instruction predicted as a branch!"); - - ++decodeControlMispred; - - // Might want to set some sort of boolean and just do - // a check at the end - squash(inst, inst->threadNumber); - - break; - } - - // Go ahead and compute any PC-relative branches. - if (inst->isDirectCtrl() && inst->isUncondCtrl()) { - ++decodeBranchResolved; - inst->setNextPC(inst->branchTarget()); - - if (inst->mispredicted()) { - ++decodeBranchMispred; - - // Might want to set some sort of boolean and just do - // a check at the end - squash(inst, inst->threadNumber); - - break; - } - } - } - - // If we didn't process all instructions, then we will need to block - // and put all those instructions into the skid buffer. - if (!insts_to_decode.empty()) { - block(tid); - } - - // Record that decode has written to the time buffer for activity - // tracking. - if (toRenameIndex) { - wroteToTimeBuffer = true; - } -} diff --git a/cpu/o3/fetch.cc b/cpu/o3/fetch.cc deleted file mode 100644 index 7959416be..000000000 --- a/cpu/o3/fetch.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/fetch_impl.hh" - -template class DefaultFetch<AlphaSimpleImpl>; diff --git a/cpu/o3/fetch.hh b/cpu/o3/fetch.hh deleted file mode 100644 index 3fcfdc3a1..000000000 --- a/cpu/o3/fetch.hh +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_FETCH_HH__ -#define __CPU_O3_FETCH_HH__ - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/pc_event.hh" -#include "mem/mem_interface.hh" -#include "sim/eventq.hh" - -class Sampler; - -/** - * DefaultFetch class handles both single threaded and SMT fetch. Its - * width is specified by the parameters; each cycle it tries to fetch - * that many instructions. It supports using a branch predictor to - * predict direction and targets. - * It supports the idling functionalitiy of the CPU by indicating to - * the CPU when it is active and inactive. - */ -template <class Impl> -class DefaultFetch -{ - public: - /** Typedefs from Impl. */ - typedef typename Impl::CPUPol CPUPol; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::Params Params; - - /** Typedefs from the CPU policy. */ - typedef typename CPUPol::BPredUnit BPredUnit; - typedef typename CPUPol::FetchStruct FetchStruct; - typedef typename CPUPol::TimeStruct TimeStruct; - - /** Typedefs from ISA. */ - typedef TheISA::MachInst MachInst; - typedef TheISA::ExtMachInst ExtMachInst; - - public: - /** Overall fetch status. Used to determine if the CPU can - * deschedule itsef due to a lack of activity. - */ - enum FetchStatus { - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - Squashing, - Blocked, - Fetching, - TrapPending, - QuiescePending, - SwitchOut, - IcacheMissStall, - IcacheMissComplete - }; - - /** Fetching Policy, Add new policies here.*/ - enum FetchPriority { - SingleThread, - RoundRobin, - Branch, - IQ, - LSQ - }; - - private: - /** Fetch status. */ - FetchStatus _status; - - /** Per-thread status. */ - ThreadStatus fetchStatus[Impl::MaxThreads]; - - /** Fetch policy. */ - FetchPriority fetchPolicy; - - /** List that has the threads organized by priority. */ - std::list<unsigned> priorityList; - - public: - class CacheCompletionEvent : public Event - { - private: - MemReqPtr req; - /** Pointer to fetch. */ - DefaultFetch *fetch; - /** Thread id. */ -// unsigned threadId; - - public: - /** Constructs a cache completion event, which tells fetch when the - * cache miss is complete. - */ - CacheCompletionEvent(MemReqPtr &_req, DefaultFetch *_fetch); - - /** Processes cache completion event. */ - virtual void process(); - /** Returns the description of the cache completion event. */ - virtual const char *description(); - }; - - public: - /** DefaultFetch constructor. */ - DefaultFetch(Params *params); - - /** Returns the name of fetch. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the main backwards communication time buffer pointer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to time buffer used to communicate to the next stage. */ - void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); - - /** Sets pointer to page table. */ -// void setPageTable(PageTable *pt_ptr); - - /** Initialize stage. */ - void initStage(); - - /** Processes cache completion event. */ - void processCacheCompletion(MemReqPtr &req); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - void wakeFromQuiesce(); - - private: - /** Changes the status of this stage to active, and indicates this - * to the CPU. - */ - inline void switchToActive(); - - /** Changes the status of this stage to inactive, and indicates - * this to the CPU. - */ - inline void switchToInactive(); - - /** - * Looks up in the branch predictor to see if the next PC should be - * either next PC+=MachInst or a branch target. - * @param next_PC Next PC variable passed in by reference. It is - * expected to be set to the current PC; it will be updated with what - * the next PC will be. - * @return Whether or not a branch was predicted as taken. - */ - bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC); - - /** - * Fetches the cache line that contains fetch_PC. Returns any - * fault that happened. Puts the data into the class variable - * cacheData. - * @param fetch_PC The PC address that is being fetched from. - * @param ret_fault The fault reference that will be set to the result of - * the icache access. - * @param tid Thread id. - * @return Any fault that occured. - */ - bool fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid); - - /** Squashes a specific thread and resets the PC. */ - inline void doSquash(const Addr &new_PC, unsigned tid); - - /** Squashes a specific thread and resets the PC. Also tells the CPU to - * remove any instructions between fetch and decode that should be sqaushed. - */ - void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num, - unsigned tid); - - /** Checks if a thread is stalled. */ - bool checkStall(unsigned tid) const; - - /** Updates overall fetch stage status; to be called at the end of each - * cycle. */ - FetchStatus updateFetchStatus(); - - public: - /** Squashes a specific thread and resets the PC. Also tells the CPU to - * remove any instructions that are not in the ROB. The source of this - * squash should be the commit stage. - */ - void squash(const Addr &new_PC, unsigned tid); - - /** Ticks the fetch stage, processing all inputs signals and fetching - * as many instructions as possible. - */ - void tick(); - - /** Checks all input signals and updates the status as necessary. - * @return: Returns if the status has changed due to input signals. - */ - bool checkSignalsAndUpdate(unsigned tid); - - /** Does the actual fetching of instructions and passing them on to the - * next stage. - * @param status_change fetch() sets this variable if there was a status - * change (ie switching to IcacheMissStall). - */ - void fetch(bool &status_change); - - /** Align a PC to the start of an I-cache block. */ - Addr icacheBlockAlignPC(Addr addr) - { - addr = TheISA::realPCToFetchPC(addr); - return (addr & ~(cacheBlkMask)); - } - - private: - /** Returns the appropriate thread to fetch, given the fetch policy. */ - int getFetchingThread(FetchPriority &fetch_priority); - - /** Returns the appropriate thread to fetch using a round robin policy. */ - int roundRobin(); - - /** Returns the appropriate thread to fetch using the IQ count policy. */ - int iqCount(); - - /** Returns the appropriate thread to fetch using the LSQ count policy. */ - int lsqCount(); - - /** Returns the appropriate thread to fetch using the branch count policy. */ - int branchCount(); - - private: - /** Pointer to the FullCPU. */ - FullCPU *cpu; - - /** Time buffer interface. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to get decode's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromDecode; - - /** Wire to get rename's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromRename; - - /** Wire to get iew's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromIEW; - - /** Wire to get commit's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Internal fetch instruction queue. */ - TimeBuffer<FetchStruct> *fetchQueue; - - //Might be annoying how this name is different than the queue. - /** Wire used to write any information heading to decode. */ - typename TimeBuffer<FetchStruct>::wire toDecode; - - /** Icache interface. */ - MemInterface *icacheInterface; - - /** BPredUnit. */ - BPredUnit branchPred; - - Addr PC[Impl::MaxThreads]; - - Addr nextPC[Impl::MaxThreads]; - - /** Memory request used to access cache. */ - MemReqPtr memReq[Impl::MaxThreads]; - - /** Variable that tracks if fetch has written to the time buffer this - * cycle. Used to tell CPU if there is activity this cycle. - */ - bool wroteToTimeBuffer; - - /** Tracks how many instructions has been fetched this cycle. */ - int numInst; - - /** Source of possible stalls. */ - struct Stalls { - bool decode; - bool rename; - bool iew; - bool commit; - }; - - /** Tracks which stages are telling fetch to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** Decode to fetch delay, in ticks. */ - unsigned decodeToFetchDelay; - - /** Rename to fetch delay, in ticks. */ - unsigned renameToFetchDelay; - - /** IEW to fetch delay, in ticks. */ - unsigned iewToFetchDelay; - - /** Commit to fetch delay, in ticks. */ - unsigned commitToFetchDelay; - - /** The width of fetch in instructions. */ - unsigned fetchWidth; - - /** Cache block size. */ - int cacheBlkSize; - - /** Mask to get a cache block's address. */ - Addr cacheBlkMask; - - /** The cache line being fetched. */ - uint8_t *cacheData[Impl::MaxThreads]; - - /** Size of instructions. */ - int instSize; - - /** Icache stall statistics. */ - Counter lastIcacheStall[Impl::MaxThreads]; - - /** List of Active Threads */ - std::list<unsigned> *activeThreads; - - /** Number of threads. */ - unsigned numThreads; - - /** Number of threads that are actively fetching. */ - unsigned numFetchingThreads; - - /** Thread ID being fetched. */ - int threadFetched; - - bool interruptPending; - - bool switchedOut; - -#if !FULL_SYSTEM - /** Page table pointer. */ -// PageTable *pTable; -#endif - - // @todo: Consider making these vectors and tracking on a per thread basis. - /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; - /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; - Stats::Scalar<> fetchedBranches; - /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; - /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; - /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; - /** Stat for total number of cycles spent blocked due to other stages in - * the pipeline. - */ - Stats::Scalar<> fetchIdleCycles; - Stats::Scalar<> fetchBlockedCycles; - - Stats::Scalar<> fetchMiscStallCycles; - /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; - - Stats::Scalar<> fetchIcacheSquashes; - /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; - Stats::Formula idleRate; - Stats::Formula branchRate; - Stats::Formula fetchRate; -}; - -#endif //__CPU_O3_FETCH_HH__ diff --git a/cpu/o3/fetch_impl.hh b/cpu/o3/fetch_impl.hh deleted file mode 100644 index 1c5e508f6..000000000 --- a/cpu/o3/fetch_impl.hh +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/isa_traits.hh" -#include "cpu/exetrace.hh" -#include "cpu/o3/fetch.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "mem/mem_req.hh" -#include "sim/byteswap.hh" -#include "sim/root.hh" - -#if FULL_SYSTEM -#include "arch/tlb.hh" -#include "arch/vtophys.hh" -#include "base/remote_gdb.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#endif // FULL_SYSTEM - -#include <algorithm> - -using namespace std; - -template<class Impl> -DefaultFetch<Impl>::CacheCompletionEvent::CacheCompletionEvent(MemReqPtr &_req, - DefaultFetch *_fetch) - : Event(&mainEventQueue, Delayed_Writeback_Pri), - req(_req), - fetch(_fetch) -{ - this->setFlags(Event::AutoDelete); -} - -template<class Impl> -void -DefaultFetch<Impl>::CacheCompletionEvent::process() -{ - fetch->processCacheCompletion(req); -} - -template<class Impl> -const char * -DefaultFetch<Impl>::CacheCompletionEvent::description() -{ - return "DefaultFetch cache completion event"; -} - -template<class Impl> -DefaultFetch<Impl>::DefaultFetch(Params *params) - : icacheInterface(params->icacheInterface), - branchPred(params), - decodeToFetchDelay(params->decodeToFetchDelay), - renameToFetchDelay(params->renameToFetchDelay), - iewToFetchDelay(params->iewToFetchDelay), - commitToFetchDelay(params->commitToFetchDelay), - fetchWidth(params->fetchWidth), - numThreads(params->numberOfThreads), - numFetchingThreads(params->smtNumFetchingThreads), - interruptPending(false) -{ - if (numThreads > Impl::MaxThreads) - fatal("numThreads is not a valid value\n"); - - DPRINTF(Fetch, "Fetch constructor called\n"); - - // Set fetch stage's status to inactive. - _status = Inactive; - - string policy = params->smtFetchPolicy; - - // Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - // Figure out fetch policy - if (policy == "singlethread") { - fetchPolicy = SingleThread; - } else if (policy == "roundrobin") { - fetchPolicy = RoundRobin; - DPRINTF(Fetch, "Fetch policy set to Round Robin\n"); - } else if (policy == "branch") { - fetchPolicy = Branch; - DPRINTF(Fetch, "Fetch policy set to Branch Count\n"); - } else if (policy == "iqcount") { - fetchPolicy = IQ; - DPRINTF(Fetch, "Fetch policy set to IQ count\n"); - } else if (policy == "lsqcount") { - fetchPolicy = LSQ; - DPRINTF(Fetch, "Fetch policy set to LSQ count\n"); - } else { - fatal("Invalid Fetch Policy. Options Are: {SingleThread," - " RoundRobin,LSQcount,IQcount}\n"); - } - - // Size of cache block. - cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64; - - // Create mask to get rid of offset bits. - cacheBlkMask = (cacheBlkSize - 1); - - for (int tid=0; tid < numThreads; tid++) { - - fetchStatus[tid] = Running; - - priorityList.push_back(tid); - - // Create a new memory request. - memReq[tid] = NULL; - - // Create space to store a cache line. - cacheData[tid] = new uint8_t[cacheBlkSize]; - - stalls[tid].decode = 0; - stalls[tid].rename = 0; - stalls[tid].iew = 0; - stalls[tid].commit = 0; - } - - // Get the size of an instruction. - instSize = sizeof(MachInst); -} - -template <class Impl> -std::string -DefaultFetch<Impl>::name() const -{ - return cpu->name() + ".fetch"; -} - -template <class Impl> -void -DefaultFetch<Impl>::regStats() -{ - icacheStallCycles - .name(name() + ".FETCH:icacheStallCycles") - .desc("Number of cycles fetch is stalled on an Icache miss") - .prereq(icacheStallCycles); - - fetchedInsts - .name(name() + ".FETCH:Insts") - .desc("Number of instructions fetch has processed") - .prereq(fetchedInsts); - - fetchedBranches - .name(name() + ".FETCH:Branches") - .desc("Number of branches that fetch encountered") - .prereq(fetchedBranches); - - predictedBranches - .name(name() + ".FETCH:predictedBranches") - .desc("Number of branches that fetch has predicted taken") - .prereq(predictedBranches); - - fetchCycles - .name(name() + ".FETCH:Cycles") - .desc("Number of cycles fetch has run and was not squashing or" - " blocked") - .prereq(fetchCycles); - - fetchSquashCycles - .name(name() + ".FETCH:SquashCycles") - .desc("Number of cycles fetch has spent squashing") - .prereq(fetchSquashCycles); - - fetchIdleCycles - .name(name() + ".FETCH:IdleCycles") - .desc("Number of cycles fetch was idle") - .prereq(fetchIdleCycles); - - fetchBlockedCycles - .name(name() + ".FETCH:BlockedCycles") - .desc("Number of cycles fetch has spent blocked") - .prereq(fetchBlockedCycles); - - fetchedCacheLines - .name(name() + ".FETCH:CacheLines") - .desc("Number of cache lines fetched") - .prereq(fetchedCacheLines); - - fetchMiscStallCycles - .name(name() + ".FETCH:MiscStallCycles") - .desc("Number of cycles fetch has spent waiting on interrupts, or " - "bad addresses, or out of MSHRs") - .prereq(fetchMiscStallCycles); - - fetchIcacheSquashes - .name(name() + ".FETCH:IcacheSquashes") - .desc("Number of outstanding Icache misses that were squashed") - .prereq(fetchIcacheSquashes); - - fetchNisnDist - .init(/* base value */ 0, - /* last value */ fetchWidth, - /* bucket size */ 1) - .name(name() + ".FETCH:rateDist") - .desc("Number of instructions fetched each cycle (Total)") - .flags(Stats::pdf); - - idleRate - .name(name() + ".FETCH:idleRate") - .desc("Percent of cycles fetch was idle") - .prereq(idleRate); - idleRate = fetchIdleCycles * 100 / cpu->numCycles; - - branchRate - .name(name() + ".FETCH:branchRate") - .desc("Number of branch fetches per cycle") - .flags(Stats::total); - branchRate = predictedBranches / cpu->numCycles; - - fetchRate - .name(name() + ".FETCH:rate") - .desc("Number of inst fetches per cycle") - .flags(Stats::total); - fetchRate = fetchedInsts / cpu->numCycles; - - branchPred.regStats(); -} - -template<class Impl> -void -DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Fetch, "Setting the CPU pointer.\n"); - cpu = cpu_ptr; - - // Fetch needs to start fetching instructions at the very beginning, - // so it must start up in active state. - switchToActive(); -} - -template<class Impl> -void -DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer) -{ - DPRINTF(Fetch, "Setting the time buffer pointer.\n"); - timeBuffer = time_buffer; - - // Create wires to get information from proper places in time buffer. - fromDecode = timeBuffer->getWire(-decodeToFetchDelay); - fromRename = timeBuffer->getWire(-renameToFetchDelay); - fromIEW = timeBuffer->getWire(-iewToFetchDelay); - fromCommit = timeBuffer->getWire(-commitToFetchDelay); -} - -template<class Impl> -void -DefaultFetch<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Fetch, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template<class Impl> -void -DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) -{ - DPRINTF(Fetch, "Setting the fetch queue pointer.\n"); - fetchQueue = fq_ptr; - - // Create wire to write information to proper place in fetch queue. - toDecode = fetchQueue->getWire(0); -} - -#if 0 -template<class Impl> -void -DefaultFetch<Impl>::setPageTable(PageTable *pt_ptr) -{ - DPRINTF(Fetch, "Setting the page table pointer.\n"); -#if !FULL_SYSTEM - pTable = pt_ptr; -#endif -} -#endif - -template<class Impl> -void -DefaultFetch<Impl>::initStage() -{ - for (int tid = 0; tid < numThreads; tid++) { - PC[tid] = cpu->readPC(tid); - nextPC[tid] = cpu->readNextPC(tid); - } -} - -template<class Impl> -void -DefaultFetch<Impl>::processCacheCompletion(MemReqPtr &req) -{ - unsigned tid = req->thread_num; - - DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); - - // Only change the status if it's still waiting on the icache access - // to return. - // Can keep track of how many cache accesses go unused due to - // misspeculation here. - if (fetchStatus[tid] != IcacheMissStall || - req != memReq[tid] || - isSwitchedOut()) { - ++fetchIcacheSquashes; - return; - } - - // Wake up the CPU (if it went to sleep and was waiting on this completion - // event). - cpu->wakeCPU(); - - DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n", - tid); - - switchToActive(); - - // Only switch to IcacheMissComplete if we're not stalled as well. - if (checkStall(tid)) { - fetchStatus[tid] = Blocked; - } else { - fetchStatus[tid] = IcacheMissComplete; - } - -// memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size); - - // Reset the mem req to NULL. - memReq[tid] = NULL; -} - -template <class Impl> -void -DefaultFetch<Impl>::switchOut() -{ - switchedOut = true; - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultFetch<Impl>::doSwitchOut() -{ - branchPred.switchOut(); -} - -template <class Impl> -void -DefaultFetch<Impl>::takeOverFrom() -{ - // Reset all state - for (int i = 0; i < Impl::MaxThreads; ++i) { - stalls[i].decode = 0; - stalls[i].rename = 0; - stalls[i].iew = 0; - stalls[i].commit = 0; - PC[i] = cpu->readPC(i); - nextPC[i] = cpu->readNextPC(i); - fetchStatus[i] = Running; - } - numInst = 0; - wroteToTimeBuffer = false; - _status = Inactive; - switchedOut = false; - branchPred.takeOverFrom(); -} - -template <class Impl> -void -DefaultFetch<Impl>::wakeFromQuiesce() -{ - DPRINTF(Fetch, "Waking up from quiesce\n"); - // Hopefully this is safe - fetchStatus[0] = Running; -} - -template <class Impl> -inline void -DefaultFetch<Impl>::switchToActive() -{ - if (_status == Inactive) { - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(FullCPU::FetchIdx); - - _status = Active; - } -} - -template <class Impl> -inline void -DefaultFetch<Impl>::switchToInactive() -{ - if (_status == Active) { - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::FetchIdx); - - _status = Inactive; - } -} - -template <class Impl> -bool -DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC) -{ - // Do branch prediction check here. - // A bit of a misnomer...next_PC is actually the current PC until - // this function updates it. - bool predict_taken; - - if (!inst->isControl()) { - next_PC = next_PC + instSize; - inst->setPredTarg(next_PC); - return false; - } - - predict_taken = branchPred.predict(inst, next_PC, inst->threadNumber); - - ++fetchedBranches; - - if (predict_taken) { - ++predictedBranches; - } - - return predict_taken; -} - -template <class Impl> -bool -DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid) -{ - Fault fault = NoFault; - -#if FULL_SYSTEM - // Flag to say whether or not address is physical addr. - unsigned flags = cpu->inPalMode(fetch_PC) ? PHYSICAL : 0; -#else - unsigned flags = 0; -#endif // FULL_SYSTEM - - if (interruptPending && flags == 0 || switchedOut) { - // Hold off fetch from getting new instructions while an interrupt - // is pending. - return false; - } - - // Align the fetch PC so it's at the start of a cache block. - fetch_PC = icacheBlockAlignPC(fetch_PC); - - // Setup the memReq to do a read of the first instruction's address. - // Set the appropriate read size and flags as well. - memReq[tid] = new MemReq(); - - memReq[tid]->asid = tid; - memReq[tid]->thread_num = tid; - memReq[tid]->data = new uint8_t[64]; - memReq[tid]->xc = cpu->xcBase(tid); - memReq[tid]->cmd = Read; - memReq[tid]->reset(fetch_PC, cacheBlkSize, flags); - - // Translate the instruction request. -//#if FULL_SYSTEM - fault = cpu->translateInstReq(memReq[tid]); -//#else -// fault = pTable->translate(memReq[tid]); -//#endif - - // In the case of faults, the fetch stage may need to stall and wait - // for the ITB miss to be handled. - - // If translation was successful, attempt to read the first - // instruction. - if (fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) || - memReq[tid]->flags & UNCACHEABLE) { - DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a " - "misspeculating path)!", - memReq[tid]->paddr); - ret_fault = TheISA::genMachineCheckFault(); - return false; - } -#endif - - DPRINTF(Fetch, "Fetch: Doing instruction read.\n"); - fault = cpu->mem->read(memReq[tid], cacheData[tid]); - // This read may change when the mem interface changes. - - // Now do the timing access to see whether or not the instruction - // exists within the cache. - if (icacheInterface && !icacheInterface->isBlocked()) { - DPRINTF(Fetch, "Doing cache access.\n"); - - memReq[tid]->completionEvent = NULL; - - memReq[tid]->time = curTick; - - MemAccessResult result = icacheInterface->access(memReq[tid]); - - fetchedCacheLines++; - - // If the cache missed, then schedule an event to wake - // up this stage once the cache miss completes. - // @todo: Possibly allow for longer than 1 cycle cache hits. - if (result != MA_HIT && icacheInterface->doEvents()) { - - memReq[tid]->completionEvent = - new CacheCompletionEvent(memReq[tid], this); - - lastIcacheStall[tid] = curTick; - - DPRINTF(Activity, "[tid:%i]: Activity: Stalling due to I-cache " - "miss.\n", tid); - - fetchStatus[tid] = IcacheMissStall; - } else { - DPRINTF(Fetch, "[tid:%i]: I-Cache hit. Doing Instruction " - "read.\n", tid); - -// memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size); - } - } else { - DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid); - ret_fault = NoFault; - return false; - } - } - - ret_fault = fault; - return true; -} - -template <class Impl> -inline void -DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid) -{ - DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n", - tid, new_PC); - - PC[tid] = new_PC; - nextPC[tid] = new_PC + instSize; - - // Clear the icache miss if it's outstanding. - if (fetchStatus[tid] == IcacheMissStall && icacheInterface) { - DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n", - tid); - memReq[tid] = NULL; - } - - fetchStatus[tid] = Squashing; - - ++fetchSquashCycles; -} - -template<class Impl> -void -DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, - const InstSeqNum &seq_num, - unsigned tid) -{ - DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid); - - doSquash(new_PC, tid); - - // Tell the CPU to remove any instructions that are in flight between - // fetch and decode. - cpu->removeInstsUntil(seq_num, tid); -} - -template<class Impl> -bool -DefaultFetch<Impl>::checkStall(unsigned tid) const -{ - bool ret_val = false; - - if (cpu->contextSwitch) { - DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid); - ret_val = true; - } else if (stalls[tid].decode) { - DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid); - ret_val = true; - } else if (stalls[tid].rename) { - DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid); - ret_val = true; - } else if (stalls[tid].iew) { - DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid); - ret_val = true; - } else if (stalls[tid].commit) { - DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid); - ret_val = true; - } - - return ret_val; -} - -template<class Impl> -typename DefaultFetch<Impl>::FetchStatus -DefaultFetch<Impl>::updateFetchStatus() -{ - //Check Running - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - - unsigned tid = *threads++; - - if (fetchStatus[tid] == Running || - fetchStatus[tid] == Squashing || - fetchStatus[tid] == IcacheMissComplete) { - - if (_status == Inactive) { - DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid); - - if (fetchStatus[tid] == IcacheMissComplete) { - DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache" - "completion\n",tid); - } - - cpu->activateStage(FullCPU::FetchIdx); - } - - return Active; - } - } - - // Stage is switching from active to inactive, notify CPU of it. - if (_status == Active) { - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::FetchIdx); - } - - return Inactive; -} - -template <class Impl> -void -DefaultFetch<Impl>::squash(const Addr &new_PC, unsigned tid) -{ - DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid); - - doSquash(new_PC, tid); - - // Tell the CPU to remove any instructions that are not in the ROB. - cpu->removeInstsNotInROB(tid); -} - -template <class Impl> -void -DefaultFetch<Impl>::tick() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - bool status_change = false; - - wroteToTimeBuffer = false; - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - // Check the signals for each thread to determine the proper status - // for each thread. - bool updated_status = checkSignalsAndUpdate(tid); - status_change = status_change || updated_status; - } - - DPRINTF(Fetch, "Running stage.\n"); - - // Reset the number of the instruction we're fetching. - numInst = 0; - - if (fromCommit->commitInfo[0].interruptPending) { - interruptPending = true; - } - if (fromCommit->commitInfo[0].clearInterrupt) { - interruptPending = false; - } - - for (threadFetched = 0; threadFetched < numFetchingThreads; - threadFetched++) { - // Fetch each of the actively fetching threads. - fetch(status_change); - } - - // Record number of instructions fetched this cycle for distribution. - fetchNisnDist.sample(numInst); - - if (status_change) { - // Change the fetch stage status if there was a status change. - _status = updateFetchStatus(); - } - - // If there was activity this cycle, inform the CPU of it. - if (wroteToTimeBuffer || cpu->contextSwitch) { - DPRINTF(Activity, "Activity this cycle.\n"); - - cpu->activityThisCycle(); - } -} - -template <class Impl> -bool -DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Update the per thread stall statuses. - if (fromDecode->decodeBlock[tid]) { - stalls[tid].decode = true; - } - - if (fromDecode->decodeUnblock[tid]) { - assert(stalls[tid].decode); - assert(!fromDecode->decodeBlock[tid]); - stalls[tid].decode = false; - } - - if (fromRename->renameBlock[tid]) { - stalls[tid].rename = true; - } - - if (fromRename->renameUnblock[tid]) { - assert(stalls[tid].rename); - assert(!fromRename->renameBlock[tid]); - stalls[tid].rename = false; - } - - if (fromIEW->iewBlock[tid]) { - stalls[tid].iew = true; - } - - if (fromIEW->iewUnblock[tid]) { - assert(stalls[tid].iew); - assert(!fromIEW->iewBlock[tid]); - stalls[tid].iew = false; - } - - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - assert(!fromCommit->commitBlock[tid]); - stalls[tid].commit = false; - } - - // Check squash signals from commit. - if (fromCommit->commitInfo[tid].squash) { - - DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " - "from commit.\n",tid); - - // In any case, squash. - squash(fromCommit->commitInfo[tid].nextPC,tid); - - // Also check if there's a mispredict that happened. - if (fromCommit->commitInfo[tid].branchMispredict) { - branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, - fromCommit->commitInfo[tid].nextPC, - fromCommit->commitInfo[tid].branchTaken, - tid); - } else { - branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, - tid); - } - - return true; - } else if (fromCommit->commitInfo[tid].doneSeqNum) { - // Update the branch predictor if it wasn't a squashed instruction - // that was broadcasted. - branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid); - } - - // Check ROB squash signals from commit. - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(Fetch, "[tid:%u]: ROB is still squashing Thread %u.\n", tid); - - // Continue to squash. - fetchStatus[tid] = Squashing; - - return true; - } - - // Check squash signals from decode. - if (fromDecode->decodeInfo[tid].squash) { - DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " - "from decode.\n",tid); - - // Update the branch predictor. - if (fromDecode->decodeInfo[tid].branchMispredict) { - branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, - fromDecode->decodeInfo[tid].nextPC, - fromDecode->decodeInfo[tid].branchTaken, - tid); - } else { - branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, - tid); - } - - if (fetchStatus[tid] != Squashing) { - // Squash unless we're already squashing - squashFromDecode(fromDecode->decodeInfo[tid].nextPC, - fromDecode->decodeInfo[tid].doneSeqNum, - tid); - - return true; - } - } - - if (checkStall(tid) && fetchStatus[tid] != IcacheMissStall) { - DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid); - - fetchStatus[tid] = Blocked; - - return true; - } - - if (fetchStatus[tid] == Blocked || - fetchStatus[tid] == Squashing) { - // Switch status to running if fetch isn't being told to block or - // squash this cycle. - DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n", - tid); - - fetchStatus[tid] = Running; - - return true; - } - - // If we've reached this point, we have not gotten any signals that - // cause fetch to change its status. Fetch remains the same as before. - return false; -} - -template<class Impl> -void -DefaultFetch<Impl>::fetch(bool &status_change) -{ - ////////////////////////////////////////// - // Start actual fetch - ////////////////////////////////////////// - int tid = getFetchingThread(fetchPolicy); - - if (tid == -1) { - DPRINTF(Fetch,"There are no more threads available to fetch from.\n"); - - // Breaks looping condition in tick() - threadFetched = numFetchingThreads; - return; - } - - // The current PC. - Addr &fetch_PC = PC[tid]; - - // Fault code for memory access. - Fault fault = NoFault; - - // If returning from the delay of a cache miss, then update the status - // to running, otherwise do the cache access. Possibly move this up - // to tick() function. - if (fetchStatus[tid] == IcacheMissComplete) { - DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n", - tid); - - fetchStatus[tid] = Running; - status_change = true; - } else if (fetchStatus[tid] == Running) { - DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read " - "instruction, starting at PC %08p.\n", - tid, fetch_PC); - - bool fetch_success = fetchCacheLine(fetch_PC, fault, tid); - if (!fetch_success) { - ++fetchMiscStallCycles; - return; - } - } else { - if (fetchStatus[tid] == Idle) { - ++fetchIdleCycles; - } else if (fetchStatus[tid] == Blocked) { - ++fetchBlockedCycles; - } else if (fetchStatus[tid] == Squashing) { - ++fetchSquashCycles; - } else if (fetchStatus[tid] == IcacheMissStall) { - ++icacheStallCycles; - } - - // Status is Idle, Squashing, Blocked, or IcacheMissStall, so - // fetch should do nothing. - return; - } - - ++fetchCycles; - - // If we had a stall due to an icache miss, then return. - if (fetchStatus[tid] == IcacheMissStall) { - ++icacheStallCycles; - status_change = true; - return; - } - - Addr next_PC = fetch_PC; - InstSeqNum inst_seq; - MachInst inst; - ExtMachInst ext_inst; - // @todo: Fix this hack. - unsigned offset = (fetch_PC & cacheBlkMask) & ~3; - - if (fault == NoFault) { - // If the read of the first instruction was successful, then grab the - // instructions from the rest of the cache line and put them into the - // queue heading to decode. - - DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to " - "decode.\n",tid); - - // Need to keep track of whether or not a predicted branch - // ended this fetch block. - bool predicted_branch = false; - - for (; - offset < cacheBlkSize && - numInst < fetchWidth && - !predicted_branch; - ++numInst) { - - // Get a sequence number. - inst_seq = cpu->getAndIncrementInstSeq(); - - // Make sure this is a valid index. - assert(offset <= cacheBlkSize - instSize); - - // Get the instruction from the array of the cache line. - inst = gtoh(*reinterpret_cast<MachInst *> - (&cacheData[tid][offset])); - - ext_inst = TheISA::makeExtMI(inst, fetch_PC); - - // Create a new DynInst from the instruction fetched. - DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, - next_PC, - inst_seq, cpu); - instruction->setThread(tid); - - instruction->setASID(tid); - - instruction->setState(cpu->thread[tid]); - - DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created " - "[sn:%lli]\n", - tid, instruction->readPC(), inst_seq); - - DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", - tid, instruction->staticInst->disassemble(fetch_PC)); - - instruction->traceData = - Trace::getInstRecord(curTick, cpu->xcBase(tid), cpu, - instruction->staticInst, - instruction->readPC(),tid); - - predicted_branch = lookupAndUpdateNextPC(instruction, next_PC); - - // Add instruction to the CPU's list of instructions. - instruction->setInstListIt(cpu->addInst(instruction)); - - // Write the instruction to the first slot in the queue - // that heads to decode. - toDecode->insts[numInst] = instruction; - - toDecode->size++; - - // Increment stat of fetched instructions. - ++fetchedInsts; - - // Move to the next instruction, unless we have a branch. - fetch_PC = next_PC; - - if (instruction->isQuiesce()) { - warn("%lli: Quiesce instruction encountered, halting fetch!", - curTick); - fetchStatus[tid] = QuiescePending; - ++numInst; - status_change = true; - break; - } - - offset+= instSize; - } - } - - if (numInst > 0) { - wroteToTimeBuffer = true; - } - - // Now that fetching is completed, update the PC to signify what the next - // cycle will be. - if (fault == NoFault) { - DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n",tid, next_PC); - - PC[tid] = next_PC; - nextPC[tid] = next_PC + instSize; - } else { - // We shouldn't be in an icache miss and also have a fault (an ITB - // miss) - if (fetchStatus[tid] == IcacheMissStall) { - panic("Fetch should have exited prior to this!"); - } - - // Send the fault to commit. This thread will not do anything - // until commit handles the fault. The only other way it can - // wake up is if a squash comes along and changes the PC. -#if FULL_SYSTEM - assert(numInst != fetchWidth); - // Get a sequence number. - inst_seq = cpu->getAndIncrementInstSeq(); - // We will use a nop in order to carry the fault. - ext_inst = TheISA::NoopMachInst; - - // Create a new DynInst from the dummy nop. - DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, - next_PC, - inst_seq, cpu); - instruction->setPredTarg(next_PC + instSize); - instruction->setThread(tid); - - instruction->setASID(tid); - - instruction->setState(cpu->thread[tid]); - - instruction->traceData = NULL; - - instruction->setInstListIt(cpu->addInst(instruction)); - - instruction->fault = fault; - - toDecode->insts[numInst] = instruction; - toDecode->size++; - - DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid); - - fetchStatus[tid] = TrapPending; - status_change = true; - - warn("%lli fault (%d) detected @ PC %08p", curTick, fault, PC[tid]); -#else // !FULL_SYSTEM - fatal("fault (%d) detected @ PC %08p", fault, PC[tid]); -#endif // FULL_SYSTEM - } -} - - -/////////////////////////////////////// -// // -// SMT FETCH POLICY MAINTAINED HERE // -// // -/////////////////////////////////////// -template<class Impl> -int -DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority) -{ - if (numThreads > 1) { - switch (fetch_priority) { - - case SingleThread: - return 0; - - case RoundRobin: - return roundRobin(); - - case IQ: - return iqCount(); - - case LSQ: - return lsqCount(); - - case Branch: - return branchCount(); - - default: - return -1; - } - } else { - int tid = *((*activeThreads).begin()); - - if (fetchStatus[tid] == Running || - fetchStatus[tid] == IcacheMissComplete || - fetchStatus[tid] == Idle) { - return tid; - } else { - return -1; - } - } - -} - - -template<class Impl> -int -DefaultFetch<Impl>::roundRobin() -{ - list<unsigned>::iterator pri_iter = priorityList.begin(); - list<unsigned>::iterator end = priorityList.end(); - - int high_pri; - - while (pri_iter != end) { - high_pri = *pri_iter; - - assert(high_pri <= numThreads); - - if (fetchStatus[high_pri] == Running || - fetchStatus[high_pri] == IcacheMissComplete || - fetchStatus[high_pri] == Idle) { - - priorityList.erase(pri_iter); - priorityList.push_back(high_pri); - - return high_pri; - } - - pri_iter++; - } - - return -1; -} - -template<class Impl> -int -DefaultFetch<Impl>::iqCount() -{ - priority_queue<unsigned> PQ; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - PQ.push(fromIEW->iewInfo[tid].iqCount); - } - - while (!PQ.empty()) { - - unsigned high_pri = PQ.top(); - - if (fetchStatus[high_pri] == Running || - fetchStatus[high_pri] == IcacheMissComplete || - fetchStatus[high_pri] == Idle) - return high_pri; - else - PQ.pop(); - - } - - return -1; -} - -template<class Impl> -int -DefaultFetch<Impl>::lsqCount() -{ - priority_queue<unsigned> PQ; - - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - PQ.push(fromIEW->iewInfo[tid].ldstqCount); - } - - while (!PQ.empty()) { - - unsigned high_pri = PQ.top(); - - if (fetchStatus[high_pri] == Running || - fetchStatus[high_pri] == IcacheMissComplete || - fetchStatus[high_pri] == Idle) - return high_pri; - else - PQ.pop(); - - } - - return -1; -} - -template<class Impl> -int -DefaultFetch<Impl>::branchCount() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - return *threads; -} diff --git a/cpu/o3/free_list.cc b/cpu/o3/free_list.cc deleted file mode 100644 index bd0f4f034..000000000 --- a/cpu/o3/free_list.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/trace.hh" - -#include "cpu/o3/free_list.hh" - -SimpleFreeList::SimpleFreeList(unsigned activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs) - : numLogicalIntRegs(_numLogicalIntRegs), - numPhysicalIntRegs(_numPhysicalIntRegs), - numLogicalFloatRegs(_numLogicalFloatRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs), - numPhysicalRegs(numPhysicalIntRegs + numPhysicalFloatRegs) -{ - DPRINTF(FreeList, "Creating new free list object.\n"); - - // Put all of the extra physical registers onto the free list. This - // means excluding all of the base logical registers. - for (PhysRegIndex i = numLogicalIntRegs * activeThreads; - i < numPhysicalIntRegs; ++i) - { - freeIntRegs.push(i); - } - - // Put all of the extra physical registers onto the free list. This - // means excluding all of the base logical registers. Because the - // float registers' indices start where the physical registers end, - // some math must be done to determine where the free registers start. - PhysRegIndex i = numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads); - - for ( ; i < numPhysicalRegs; ++i) - { - freeFloatRegs.push(i); - } -} - -std::string -SimpleFreeList::name() const -{ - return "cpu.freelist"; -} diff --git a/cpu/o3/free_list.hh b/cpu/o3/free_list.hh deleted file mode 100644 index 29e84cd44..000000000 --- a/cpu/o3/free_list.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_FREE_LIST_HH__ -#define __CPU_O3_FREE_LIST_HH__ - -#include <iostream> -#include <queue> - -#include "arch/isa_traits.hh" -#include "base/trace.hh" -#include "base/traceflags.hh" -#include "cpu/o3/comm.hh" - -/** - * FreeList class that simply holds the list of free integer and floating - * point registers. Can request for a free register of either type, and - * also send back free registers of either type. This is a very simple - * class, but it should be sufficient for most implementations. Like all - * other classes, it assumes that the indices for the floating point - * registers starts after the integer registers end. Hence the variable - * numPhysicalIntRegs is logically equivalent to the baseFP dependency. - * Note that while this most likely should be called FreeList, the name - * "FreeList" is used in a typedef within the CPU Policy, and therefore no - * class can be named simply "FreeList". - * @todo: Give a better name to the base FP dependency. - */ -class SimpleFreeList -{ - private: - /** The list of free integer registers. */ - std::queue<PhysRegIndex> freeIntRegs; - - /** The list of free floating point registers. */ - std::queue<PhysRegIndex> freeFloatRegs; - - /** Number of logical integer registers. */ - int numLogicalIntRegs; - - /** Number of physical integer registers. */ - int numPhysicalIntRegs; - - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; - - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; - - /** Total number of physical registers. */ - int numPhysicalRegs; - - public: - /** Constructs a free list. - * @param activeThreads Number of active threads. - * @param _numLogicalIntRegs Number of logical integer registers. - * @param _numPhysicalIntRegs Number of physical integer registers. - * @param _numLogicalFloatRegs Number of logical fp registers. - * @param _numPhysicalFloatRegs Number of physical fp registers. - */ - SimpleFreeList(unsigned activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs); - - /** Gives the name of the freelist. */ - std::string name() const; - - /** Gets a free integer register. */ - inline PhysRegIndex getIntReg(); - - /** Gets a free fp register. */ - inline PhysRegIndex getFloatReg(); - - /** Adds a register back to the free list. */ - inline void addReg(PhysRegIndex freed_reg); - - /** Adds an integer register back to the free list. */ - inline void addIntReg(PhysRegIndex freed_reg); - - /** Adds a fp register back to the free list. */ - inline void addFloatReg(PhysRegIndex freed_reg); - - /** Checks if there are any free integer registers. */ - bool hasFreeIntRegs() - { return !freeIntRegs.empty(); } - - /** Checks if there are any free fp registers. */ - bool hasFreeFloatRegs() - { return !freeFloatRegs.empty(); } - - /** Returns the number of free integer registers. */ - int numFreeIntRegs() - { return freeIntRegs.size(); } - - /** Returns the number of free fp registers. */ - int numFreeFloatRegs() - { return freeFloatRegs.size(); } -}; - -inline PhysRegIndex -SimpleFreeList::getIntReg() -{ - DPRINTF(FreeList, "Trying to get free integer register.\n"); - - if (freeIntRegs.empty()) { - panic("No free integer registers!"); - } - - PhysRegIndex free_reg = freeIntRegs.front(); - - freeIntRegs.pop(); - - return(free_reg); -} - -inline PhysRegIndex -SimpleFreeList::getFloatReg() -{ - DPRINTF(FreeList, "Trying to get free float register.\n"); - - if (freeFloatRegs.empty()) { - panic("No free integer registers!"); - } - - PhysRegIndex free_reg = freeFloatRegs.front(); - - freeFloatRegs.pop(); - - return(free_reg); -} - -inline void -SimpleFreeList::addReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing register %i.\n", freed_reg); - //Might want to add in a check for whether or not this register is - //already in there. A bit vector or something similar would be useful. - if (freed_reg < numPhysicalIntRegs) { - if (freed_reg != TheISA::ZeroReg) - freeIntRegs.push(freed_reg); - } else if (freed_reg < numPhysicalRegs) { - if (freed_reg != (TheISA::ZeroReg + numPhysicalIntRegs)) - freeFloatRegs.push(freed_reg); - } -} - -inline void -SimpleFreeList::addIntReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing int register %i.\n", freed_reg); - - freeIntRegs.push(freed_reg); -} - -inline void -SimpleFreeList::addFloatReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing float register %i.\n", freed_reg); - - freeFloatRegs.push(freed_reg); -} - -#endif // __CPU_O3_FREE_LIST_HH__ diff --git a/cpu/o3/iew.cc b/cpu/o3/iew.cc deleted file mode 100644 index 90d035f71..000000000 --- a/cpu/o3/iew.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/iew_impl.hh" -#include "cpu/o3/inst_queue.hh" - -template class DefaultIEW<AlphaSimpleImpl>; diff --git a/cpu/o3/iew.hh b/cpu/o3/iew.hh deleted file mode 100644 index 935320628..000000000 --- a/cpu/o3/iew.hh +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_IEW_HH__ -#define __CPU_O3_IEW_HH__ - -#include <queue> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/scoreboard.hh" -#include "cpu/o3/lsq.hh" - -class FUPool; - -/** - * DefaultIEW handles both single threaded and SMT IEW - * (issue/execute/writeback). It handles the dispatching of - * instructions to the LSQ/IQ as part of the issue stage, and has the - * IQ try to issue instructions each cycle. The execute latency is - * actually tied into the issue latency to allow the IQ to be able to - * do back-to-back scheduling without having to speculatively schedule - * instructions. This happens by having the IQ have access to the - * functional units, and the IQ gets the execution latencies from the - * FUs when it issues instructions. Instructions reach the execute - * stage on the last cycle of their execution, which is when the IQ - * knows to wake up any dependent instructions, allowing back to back - * scheduling. The execute portion of IEW separates memory - * instructions from non-memory instructions, either telling the LSQ - * to execute the instruction, or executing the instruction directly. - * The writeback portion of IEW completes the instructions by waking - * up any dependents, and marking the register ready on the - * scoreboard. - */ -template<class Impl> -class DefaultIEW -{ - private: - //Typedefs from Impl - typedef typename Impl::CPUPol CPUPol; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::Params Params; - - typedef typename CPUPol::IQ IQ; - typedef typename CPUPol::RenameMap RenameMap; - typedef typename CPUPol::LSQ LSQ; - - typedef typename CPUPol::TimeStruct TimeStruct; - typedef typename CPUPol::IEWStruct IEWStruct; - typedef typename CPUPol::RenameStruct RenameStruct; - typedef typename CPUPol::IssueStruct IssueStruct; - - friend class Impl::FullCPU; - friend class CPUPol::IQ; - - public: - /** Overall IEW stage status. Used to determine if the CPU can - * deschedule itself due to a lack of activity. - */ - enum Status { - Active, - Inactive - }; - - /** Status for Issue, Execute, and Writeback stages. */ - enum StageStatus { - Running, - Blocked, - Idle, - StartSquash, - Squashing, - Unblocking - }; - - private: - /** Overall stage status. */ - Status _status; - /** Dispatch status. */ - StageStatus dispatchStatus[Impl::MaxThreads]; - /** Execute status. */ - StageStatus exeStatus; - /** Writeback status. */ - StageStatus wbStatus; - - public: - /** LdWriteback event for a load completion. */ - class LdWritebackEvent : public Event { - private: - /** Instruction that is writing back data to the register file. */ - DynInstPtr inst; - /** Pointer to IEW stage. */ - DefaultIEW<Impl> *iewStage; - - public: - /** Constructs a load writeback event. */ - LdWritebackEvent(DynInstPtr &_inst, DefaultIEW<Impl> *_iew); - - /** Processes writeback event. */ - virtual void process(); - /** Returns the description of the writeback event. */ - virtual const char *description(); - }; - - public: - /** Constructs a DefaultIEW with the given parameters. */ - DefaultIEW(Params *params); - - /** Returns the name of the DefaultIEW stage. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Initializes stage; sends back the number of free IQ and LSQ entries. */ - void initStage(); - - /** Sets CPU pointer for IEW, IQ, and LSQ. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets main time buffer used for backwards communication. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Sets time buffer for getting instructions coming from rename. */ - void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); - - /** Sets time buffer to pass on instructions to commit. */ - void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to the scoreboard. */ - void setScoreboard(Scoreboard *sb_ptr); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - /** Sets page table pointer within LSQ. */ -// void setPageTable(PageTable *pt_ptr); - - /** Squashes instructions in IEW for a specific thread. */ - void squash(unsigned tid); - - /** Wakes all dependents of a completed instruction. */ - void wakeDependents(DynInstPtr &inst); - - /** Tells memory dependence unit that a memory instruction needs to be - * rescheduled. It will re-execute once replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &inst); - - /** Re-executes all rescheduled memory instructions. */ - void replayMemInst(DynInstPtr &inst); - - /** Sends an instruction to commit through the time buffer. */ - void instToCommit(DynInstPtr &inst); - - /** Inserts unused instructions of a thread into the skid buffer. */ - void skidInsert(unsigned tid); - - /** Returns the max of the number of entries in all of the skid buffers. */ - int skidCount(); - - /** Returns if all of the skid buffers are empty. */ - bool skidsEmpty(); - - /** Updates overall IEW status based on all of the stages' statuses. */ - void updateStatus(); - - /** Resets entries of the IQ and the LSQ. */ - void resetEntries(); - - /** Tells the CPU to wakeup if it has descheduled itself due to no - * activity. Used mainly by the LdWritebackEvent. - */ - void wakeCPU(); - - /** Reports to the CPU that there is activity this cycle. */ - void activityThisCycle(); - - /** Tells CPU that the IEW stage is active and running. */ - inline void activateStage(); - - /** Tells CPU that the IEW stage is inactive and idle. */ - inline void deactivateStage(); - - /** Returns if the LSQ has any stores to writeback. */ - bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); } - - private: - /** Sends commit proper information for a squash due to a branch - * mispredict. - */ - void squashDueToBranch(DynInstPtr &inst, unsigned thread_id); - - /** Sends commit proper information for a squash due to a memory order - * violation. - */ - void squashDueToMemOrder(DynInstPtr &inst, unsigned thread_id); - - /** Sends commit proper information for a squash due to memory becoming - * blocked (younger issued instructions must be retried). - */ - void squashDueToMemBlocked(DynInstPtr &inst, unsigned thread_id); - - /** Sets Dispatch to blocked, and signals back to other stages to block. */ - void block(unsigned thread_id); - - /** Unblocks Dispatch if the skid buffer is empty, and signals back to - * other stages to unblock. - */ - void unblock(unsigned thread_id); - - /** Determines proper actions to take given Dispatch's status. */ - void dispatch(unsigned tid); - - /** Dispatches instructions to IQ and LSQ. */ - void dispatchInsts(unsigned tid); - - /** Executes instructions. In the case of memory operations, it informs the - * LSQ to execute the instructions. Also handles any redirects that occur - * due to the executed instructions. - */ - void executeInsts(); - - /** Writebacks instructions. In our model, the instruction's execute() - * function atomically reads registers, executes, and writes registers. - * Thus this writeback only wakes up dependent instructions, and informs - * the scoreboard of registers becoming ready. - */ - void writebackInsts(); - - /** Returns the number of valid, non-squashed instructions coming from - * rename to dispatch. - */ - unsigned validInstsFromRename(); - - /** Reads the stall signals. */ - void readStallSignals(unsigned tid); - - /** Checks if any of the stall conditions are currently true. */ - bool checkStall(unsigned tid); - - /** Processes inputs and changes state accordingly. */ - void checkSignalsAndUpdate(unsigned tid); - - /** Sorts instructions coming from rename into lists separated by thread. */ - void sortInsts(); - - public: - /** Ticks IEW stage, causing Dispatch, the IQ, the LSQ, Execute, and - * Writeback to run for one cycle. - */ - void tick(); - - private: - void updateExeInstStats(DynInstPtr &inst); - - /** Pointer to main time buffer used for backwards communication. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to write information heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toFetch; - - /** Wire to get commit's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Wire to write information heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toRename; - - /** Rename instruction queue interface. */ - TimeBuffer<RenameStruct> *renameQueue; - - /** Wire to get rename's output from rename queue. */ - typename TimeBuffer<RenameStruct>::wire fromRename; - - /** Issue stage queue. */ - TimeBuffer<IssueStruct> issueToExecQueue; - - /** Wire to read information from the issue stage time queue. */ - typename TimeBuffer<IssueStruct>::wire fromIssue; - - /** - * IEW stage time buffer. Holds ROB indices of instructions that - * can be marked as completed. - */ - TimeBuffer<IEWStruct> *iewQueue; - - /** Wire to write infromation heading to commit. */ - typename TimeBuffer<IEWStruct>::wire toCommit; - - /** Queue of all instructions coming from rename this cycle. */ - std::queue<DynInstPtr> insts[Impl::MaxThreads]; - - /** Skid buffer between rename and IEW. */ - std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads]; - - /** Scoreboard pointer. */ - Scoreboard* scoreboard; - - public: - /** Instruction queue. */ - IQ instQueue; - - /** Load / store queue. */ - LSQ ldstQueue; - - /** Pointer to the functional unit pool. */ - FUPool *fuPool; - - private: - /** CPU pointer. */ - FullCPU *cpu; - - /** Records if IEW has written to the time buffer this cycle, so that the - * CPU can deschedule itself if there is no activity. - */ - bool wroteToTimeBuffer; - - /** Source of possible stalls. */ - struct Stalls { - bool commit; - }; - - /** Stages that are telling IEW to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** Debug function to print instructions that are issued this cycle. */ - void printAvailableInsts(); - - public: - /** Records if the LSQ needs to be updated on the next cycle, so that - * IEW knows if there will be activity on the next cycle. - */ - bool updateLSQNextCycle; - - private: - /** Records if there is a fetch redirect on this cycle for each thread. */ - bool fetchRedirect[Impl::MaxThreads]; - - /** Used to track if all instructions have been dispatched this cycle. - * If they have not, then blocking must have occurred, and the instructions - * would already be added to the skid buffer. - * @todo: Fix this hack. - */ - bool dispatchedAllInsts; - - /** Records if the queues have been changed (inserted or issued insts), - * so that IEW knows to broadcast the updated amount of free entries. - */ - bool updatedQueues; - - /** Commit to IEW delay, in ticks. */ - unsigned commitToIEWDelay; - - /** Rename to IEW delay, in ticks. */ - unsigned renameToIEWDelay; - - /** - * Issue to execute delay, in ticks. What this actually represents is - * the amount of time it takes for an instruction to wake up, be - * scheduled, and sent to a FU for execution. - */ - unsigned issueToExecuteDelay; - - /** Width of issue's read path, in instructions. The read path is both - * the skid buffer and the rename instruction queue. - * Note to self: is this really different than issueWidth? - */ - unsigned issueReadWidth; - - /** Width of issue, in instructions. */ - unsigned issueWidth; - - /** Width of execute, in instructions. Might make more sense to break - * down into FP vs int. - */ - unsigned executeWidth; - - /** Index into queue of instructions being written back. */ - unsigned wbNumInst; - - /** Cycle number within the queue of instructions being written back. - * Used in case there are too many instructions writing back at the current - * cycle and writesbacks need to be scheduled for the future. See comments - * in instToCommit(). - */ - unsigned wbCycle; - - /** Number of active threads. */ - unsigned numThreads; - - /** Pointer to list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Maximum size of the skid buffer. */ - unsigned skidBufferMax; - - bool switchedOut; - - /** Stat for total number of idle cycles. */ - Stats::Scalar<> iewIdleCycles; - /** Stat for total number of squashing cycles. */ - Stats::Scalar<> iewSquashCycles; - /** Stat for total number of blocking cycles. */ - Stats::Scalar<> iewBlockCycles; - /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> iewUnblockCycles; - /** Stat for total number of instructions dispatched. */ - Stats::Scalar<> iewDispatchedInsts; - /** Stat for total number of squashed instructions dispatch skips. */ - Stats::Scalar<> iewDispSquashedInsts; - /** Stat for total number of dispatched load instructions. */ - Stats::Scalar<> iewDispLoadInsts; - /** Stat for total number of dispatched store instructions. */ - Stats::Scalar<> iewDispStoreInsts; - /** Stat for total number of dispatched non speculative instructions. */ - Stats::Scalar<> iewDispNonSpecInsts; - /** Stat for number of times the IQ becomes full. */ - Stats::Scalar<> iewIQFullEvents; - /** Stat for number of times the LSQ becomes full. */ - Stats::Scalar<> iewLSQFullEvents; - /** Stat for total number of executed instructions. */ - Stats::Scalar<> iewExecutedInsts; - /** Stat for total number of executed load instructions. */ - Stats::Vector<> iewExecLoadInsts; - /** Stat for total number of executed store instructions. */ -// Stats::Scalar<> iewExecStoreInsts; - /** Stat for total number of squashed instructions skipped at execute. */ - Stats::Scalar<> iewExecSquashedInsts; - /** Stat for total number of memory ordering violation events. */ - Stats::Scalar<> memOrderViolationEvents; - /** Stat for total number of incorrect predicted taken branches. */ - Stats::Scalar<> predictedTakenIncorrect; - /** Stat for total number of incorrect predicted not taken branches. */ - Stats::Scalar<> predictedNotTakenIncorrect; - /** Stat for total number of mispredicted branches detected at execute. */ - Stats::Formula branchMispredicts; - - Stats::Vector<> exeSwp; - Stats::Vector<> exeNop; - Stats::Vector<> exeRefs; - Stats::Vector<> exeBranches; - -// Stats::Vector<> issued_ops; -/* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; -*/ - Stats::Formula issueRate; - Stats::Formula iewExecStoreInsts; -// Stats::Formula issue_op_rate; -// Stats::Formula fu_busy_rate; - - Stats::Vector<> iewInstsToCommit; - Stats::Vector<> writebackCount; - Stats::Vector<> producerInst; - Stats::Vector<> consumerInst; - Stats::Vector<> wbPenalized; - - Stats::Formula wbRate; - Stats::Formula wbFanout; - Stats::Formula wbPenalizedRate; -}; - -#endif // __CPU_O3_IEW_HH__ diff --git a/cpu/o3/iew_impl.hh b/cpu/o3/iew_impl.hh deleted file mode 100644 index b0137d7fc..000000000 --- a/cpu/o3/iew_impl.hh +++ /dev/null @@ -1,1578 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @todo: Fix the instantaneous communication among all the stages within -// iew. There's a clear delay between issue and execute, yet backwards -// communication happens simultaneously. - -#include <queue> - -#include "base/timebuf.hh" -#include "cpu/o3/fu_pool.hh" -#include "cpu/o3/iew.hh" - -using namespace std; - -template<class Impl> -DefaultIEW<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst, - DefaultIEW<Impl> *_iew) - : Event(&mainEventQueue), inst(_inst), iewStage(_iew) -{ - this->setFlags(Event::AutoDelete); -} - -template<class Impl> -void -DefaultIEW<Impl>::LdWritebackEvent::process() -{ - DPRINTF(IEW, "Load writeback event [sn:%lli]\n", inst->seqNum); - DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum); - - //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); - - if (iewStage->isSwitchedOut()) { - inst = NULL; - return; - } else if (inst->isSquashed()) { - iewStage->wakeCPU(); - inst = NULL; - return; - } - - iewStage->wakeCPU(); - - if (!inst->isExecuted()) { - inst->setExecuted(); - - // Complete access to copy data to proper place. - if (inst->isStore()) { - inst->completeAcc(); - } - } - - // Need to insert instruction into queue to commit - iewStage->instToCommit(inst); - - iewStage->activityThisCycle(); - - inst = NULL; -} - -template<class Impl> -const char * -DefaultIEW<Impl>::LdWritebackEvent::description() -{ - return "Load writeback event"; -} - -template<class Impl> -DefaultIEW<Impl>::DefaultIEW(Params *params) - : // @todo: Make this into a parameter. - issueToExecQueue(5, 5), - instQueue(params), - ldstQueue(params), - fuPool(params->fuPool), - commitToIEWDelay(params->commitToIEWDelay), - renameToIEWDelay(params->renameToIEWDelay), - issueToExecuteDelay(params->issueToExecuteDelay), - issueReadWidth(params->issueWidth), - issueWidth(params->issueWidth), - executeWidth(params->executeWidth), - numThreads(params->numberOfThreads), - switchedOut(false) -{ - _status = Active; - exeStatus = Running; - wbStatus = Idle; - - // Setup wire to read instructions coming from issue. - fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay); - - // Instruction queue needs the queue between issue and execute. - instQueue.setIssueToExecuteQueue(&issueToExecQueue); - - instQueue.setIEW(this); - ldstQueue.setIEW(this); - - for (int i=0; i < numThreads; i++) { - dispatchStatus[i] = Running; - stalls[i].commit = false; - fetchRedirect[i] = false; - } - - updateLSQNextCycle = false; - - skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth; -} - -template <class Impl> -std::string -DefaultIEW<Impl>::name() const -{ - return cpu->name() + ".iew"; -} - -template <class Impl> -void -DefaultIEW<Impl>::regStats() -{ - using namespace Stats; - - instQueue.regStats(); - - iewIdleCycles - .name(name() + ".iewIdleCycles") - .desc("Number of cycles IEW is idle"); - - iewSquashCycles - .name(name() + ".iewSquashCycles") - .desc("Number of cycles IEW is squashing"); - - iewBlockCycles - .name(name() + ".iewBlockCycles") - .desc("Number of cycles IEW is blocking"); - - iewUnblockCycles - .name(name() + ".iewUnblockCycles") - .desc("Number of cycles IEW is unblocking"); - - iewDispatchedInsts - .name(name() + ".iewDispatchedInsts") - .desc("Number of instructions dispatched to IQ"); - - iewDispSquashedInsts - .name(name() + ".iewDispSquashedInsts") - .desc("Number of squashed instructions skipped by dispatch"); - - iewDispLoadInsts - .name(name() + ".iewDispLoadInsts") - .desc("Number of dispatched load instructions"); - - iewDispStoreInsts - .name(name() + ".iewDispStoreInsts") - .desc("Number of dispatched store instructions"); - - iewDispNonSpecInsts - .name(name() + ".iewDispNonSpecInsts") - .desc("Number of dispatched non-speculative instructions"); - - iewIQFullEvents - .name(name() + ".iewIQFullEvents") - .desc("Number of times the IQ has become full, causing a stall"); - - iewLSQFullEvents - .name(name() + ".iewLSQFullEvents") - .desc("Number of times the LSQ has become full, causing a stall"); - - iewExecutedInsts - .name(name() + ".iewExecutedInsts") - .desc("Number of executed instructions"); - - iewExecLoadInsts - .init(cpu->number_of_threads) - .name(name() + ".iewExecLoadInsts") - .desc("Number of load instructions executed") - .flags(total); - - iewExecSquashedInsts - .name(name() + ".iewExecSquashedInsts") - .desc("Number of squashed instructions skipped in execute"); - - memOrderViolationEvents - .name(name() + ".memOrderViolationEvents") - .desc("Number of memory order violations"); - - predictedTakenIncorrect - .name(name() + ".predictedTakenIncorrect") - .desc("Number of branches that were predicted taken incorrectly"); - - predictedNotTakenIncorrect - .name(name() + ".predictedNotTakenIncorrect") - .desc("Number of branches that were predicted not taken incorrectly"); - - branchMispredicts - .name(name() + ".branchMispredicts") - .desc("Number of branch mispredicts detected at execute"); - - branchMispredicts = predictedTakenIncorrect + predictedNotTakenIncorrect; - - exeSwp - .init(cpu->number_of_threads) - .name(name() + ".EXEC:swp") - .desc("number of swp insts executed") - .flags(total) - ; - - exeNop - .init(cpu->number_of_threads) - .name(name() + ".EXEC:nop") - .desc("number of nop insts executed") - .flags(total) - ; - - exeRefs - .init(cpu->number_of_threads) - .name(name() + ".EXEC:refs") - .desc("number of memory reference insts executed") - .flags(total) - ; - - exeBranches - .init(cpu->number_of_threads) - .name(name() + ".EXEC:branches") - .desc("Number of branches executed") - .flags(total) - ; - - issueRate - .name(name() + ".EXEC:rate") - .desc("Inst execution rate") - .flags(total) - ; - issueRate = iewExecutedInsts / cpu->numCycles; - - iewExecStoreInsts - .name(name() + ".EXEC:stores") - .desc("Number of stores executed") - .flags(total) - ; - iewExecStoreInsts = exeRefs - iewExecLoadInsts; -/* - for (int i=0; i<Num_OpClasses; ++i) { - stringstream subname; - subname << opClassStrings[i] << "_delay"; - issue_delay_dist.subname(i, subname.str()); - } -*/ - // - // Other stats - // - - iewInstsToCommit - .init(cpu->number_of_threads) - .name(name() + ".WB:sent") - .desc("cumulative count of insts sent to commit") - .flags(total) - ; - - writebackCount - .init(cpu->number_of_threads) - .name(name() + ".WB:count") - .desc("cumulative count of insts written-back") - .flags(total) - ; - - producerInst - .init(cpu->number_of_threads) - .name(name() + ".WB:producers") - .desc("num instructions producing a value") - .flags(total) - ; - - consumerInst - .init(cpu->number_of_threads) - .name(name() + ".WB:consumers") - .desc("num instructions consuming a value") - .flags(total) - ; - - wbPenalized - .init(cpu->number_of_threads) - .name(name() + ".WB:penalized") - .desc("number of instrctions required to write to 'other' IQ") - .flags(total) - ; - - wbPenalizedRate - .name(name() + ".WB:penalized_rate") - .desc ("fraction of instructions written-back that wrote to 'other' IQ") - .flags(total) - ; - - wbPenalizedRate = wbPenalized / writebackCount; - - wbFanout - .name(name() + ".WB:fanout") - .desc("average fanout of values written-back") - .flags(total) - ; - - wbFanout = producerInst / consumerInst; - - wbRate - .name(name() + ".WB:rate") - .desc("insts written-back per cycle") - .flags(total) - ; - wbRate = writebackCount / cpu->numCycles; -} - -template<class Impl> -void -DefaultIEW<Impl>::initStage() -{ - for (int tid=0; tid < numThreads; tid++) { - toRename->iewInfo[tid].usedIQ = true; - toRename->iewInfo[tid].freeIQEntries = - instQueue.numFreeEntries(tid); - - toRename->iewInfo[tid].usedLSQ = true; - toRename->iewInfo[tid].freeLSQEntries = - ldstQueue.numFreeEntries(tid); - } -} - -template<class Impl> -void -DefaultIEW<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(IEW, "Setting CPU pointer.\n"); - cpu = cpu_ptr; - - instQueue.setCPU(cpu_ptr); - ldstQueue.setCPU(cpu_ptr); - - cpu->activateStage(FullCPU::IEWIdx); -} - -template<class Impl> -void -DefaultIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(IEW, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to read information from time buffer, from commit. - fromCommit = timeBuffer->getWire(-commitToIEWDelay); - - // Setup wire to write information back to previous stages. - toRename = timeBuffer->getWire(0); - - toFetch = timeBuffer->getWire(0); - - // Instruction queue also needs main time buffer. - instQueue.setTimeBuffer(tb_ptr); -} - -template<class Impl> -void -DefaultIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) -{ - DPRINTF(IEW, "Setting rename queue pointer.\n"); - renameQueue = rq_ptr; - - // Setup wire to read information from rename queue. - fromRename = renameQueue->getWire(-renameToIEWDelay); -} - -template<class Impl> -void -DefaultIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) -{ - DPRINTF(IEW, "Setting IEW queue pointer.\n"); - iewQueue = iq_ptr; - - // Setup wire to write instructions to commit. - toCommit = iewQueue->getWire(0); -} - -template<class Impl> -void -DefaultIEW<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(IEW, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; - - ldstQueue.setActiveThreads(at_ptr); - instQueue.setActiveThreads(at_ptr); -} - -template<class Impl> -void -DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr) -{ - DPRINTF(IEW, "Setting scoreboard pointer.\n"); - scoreboard = sb_ptr; -} - -#if 0 -template<class Impl> -void -DefaultIEW<Impl>::setPageTable(PageTable *pt_ptr) -{ - ldstQueue.setPageTable(pt_ptr); -} -#endif - -template <class Impl> -void -DefaultIEW<Impl>::switchOut() -{ - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultIEW<Impl>::doSwitchOut() -{ - switchedOut = true; - - instQueue.switchOut(); - ldstQueue.switchOut(); - fuPool->switchOut(); - - for (int i = 0; i < numThreads; i++) { - while (!insts[i].empty()) - insts[i].pop(); - while (!skidBuffer[i].empty()) - skidBuffer[i].pop(); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::takeOverFrom() -{ - _status = Active; - exeStatus = Running; - wbStatus = Idle; - switchedOut = false; - - instQueue.takeOverFrom(); - ldstQueue.takeOverFrom(); - fuPool->takeOverFrom(); - - initStage(); - cpu->activityThisCycle(); - - for (int i=0; i < numThreads; i++) { - dispatchStatus[i] = Running; - stalls[i].commit = false; - fetchRedirect[i] = false; - } - - updateLSQNextCycle = false; - - // @todo: Fix hardcoded number - for (int i = 0; i < 6; ++i) { - issueToExecQueue.advance(); - } -} - -template<class Impl> -void -DefaultIEW<Impl>::squash(unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Squashing all instructions.\n", - tid); - - // Tell the IQ to start squashing. - instQueue.squash(tid); - - // Tell the LDSTQ to start squashing. - ldstQueue.squash(fromCommit->commitInfo[tid].doneSeqNum, tid); - - updatedQueues = true; - - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer[tid].empty()) { - - if (skidBuffer[tid].front()->isLoad() || - skidBuffer[tid].front()->isStore() ) { - toRename->iewInfo[tid].dispatchedToLSQ++; - } - - toRename->iewInfo[tid].dispatched++; - - skidBuffer[tid].pop(); - } - - while (!insts[tid].empty()) { - if (insts[tid].front()->isLoad() || - insts[tid].front()->isStore() ) { - toRename->iewInfo[tid].dispatchedToLSQ++; - } - - toRename->iewInfo[tid].dispatched++; - - insts[tid].pop(); - } -} - -template<class Impl> -void -DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, PC: %#x " - "[sn:%i].\n", tid, inst->readPC(), inst->seqNum); - - toCommit->squash[tid] = true; - toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->mispredPC[tid] = inst->readPC(); - toCommit->nextPC[tid] = inst->readNextPC(); - toCommit->branchMispredict[tid] = true; - toCommit->branchTaken[tid] = inst->readNextPC() != - (inst->readPC() + sizeof(TheISA::MachInst)); - - toCommit->includeSquashInst[tid] = false; - - wroteToTimeBuffer = true; -} - -template<class Impl> -void -DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, " - "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum); - - toCommit->squash[tid] = true; - toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->nextPC[tid] = inst->readNextPC(); - - toCommit->includeSquashInst[tid] = false; - - wroteToTimeBuffer = true; -} - -template<class Impl> -void -DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Memory blocked, squashing load and younger insts, " - "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum); - - toCommit->squash[tid] = true; - toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->nextPC[tid] = inst->readPC(); - - toCommit->includeSquashInst[tid] = true; - - ldstQueue.setLoadBlockedHandled(tid); - - wroteToTimeBuffer = true; -} - -template<class Impl> -void -DefaultIEW<Impl>::block(unsigned tid) -{ - DPRINTF(IEW, "[tid:%u]: Blocking.\n", tid); - - if (dispatchStatus[tid] != Blocked && - dispatchStatus[tid] != Unblocking) { - toRename->iewBlock[tid] = true; - wroteToTimeBuffer = true; - } - - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - - dispatchStatus[tid] = Blocked; -} - -template<class Impl> -void -DefaultIEW<Impl>::unblock(unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Reading instructions out of the skid " - "buffer %u.\n",tid, tid); - - // If the skid bufffer is empty, signal back to previous stages to unblock. - // Also switch status to running. - if (skidBuffer[tid].empty()) { - toRename->iewUnblock[tid] = true; - wroteToTimeBuffer = true; - DPRINTF(IEW, "[tid:%i]: Done unblocking.\n",tid); - dispatchStatus[tid] = Running; - } -} - -template<class Impl> -void -DefaultIEW<Impl>::wakeDependents(DynInstPtr &inst) -{ - instQueue.wakeDependents(inst); -} - -template<class Impl> -void -DefaultIEW<Impl>::rescheduleMemInst(DynInstPtr &inst) -{ - instQueue.rescheduleMemInst(inst); -} - -template<class Impl> -void -DefaultIEW<Impl>::replayMemInst(DynInstPtr &inst) -{ - instQueue.replayMemInst(inst); -} - -template<class Impl> -void -DefaultIEW<Impl>::instToCommit(DynInstPtr &inst) -{ - // First check the time slot that this instruction will write - // to. If there are free write ports at the time, then go ahead - // and write the instruction to that time. If there are not, - // keep looking back to see where's the first time there's a - // free slot. - while ((*iewQueue)[wbCycle].insts[wbNumInst]) { - ++wbNumInst; - if (wbNumInst == issueWidth) { - ++wbCycle; - wbNumInst = 0; - } - - assert(wbCycle < 5); - } - - // Add finished instruction to queue to commit. - (*iewQueue)[wbCycle].insts[wbNumInst] = inst; - (*iewQueue)[wbCycle].size++; -} - -template <class Impl> -unsigned -DefaultIEW<Impl>::validInstsFromRename() -{ - unsigned inst_count = 0; - - for (int i=0; i<fromRename->size; i++) { - if (!fromRename->insts[i]->squashed) - inst_count++; - } - - return inst_count; -} - -template<class Impl> -void -DefaultIEW<Impl>::skidInsert(unsigned tid) -{ - DynInstPtr inst = NULL; - - while (!insts[tid].empty()) { - inst = insts[tid].front(); - - insts[tid].pop(); - - DPRINTF(Decode,"[tid:%i]: Inserting [sn:%lli] PC:%#x into " - "dispatch skidBuffer %i\n",tid, inst->seqNum, - inst->readPC(),tid); - - skidBuffer[tid].push(inst); - } - - assert(skidBuffer[tid].size() <= skidBufferMax && - "Skidbuffer Exceeded Max Size"); -} - -template<class Impl> -int -DefaultIEW<Impl>::skidCount() -{ - int max=0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned thread_count = skidBuffer[*threads++].size(); - if (max < thread_count) - max = thread_count; - } - - return max; -} - -template<class Impl> -bool -DefaultIEW<Impl>::skidsEmpty() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - -template <class Impl> -void -DefaultIEW<Impl>::updateStatus() -{ - bool any_unblocking = false; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (dispatchStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // If there are no ready instructions waiting to be scheduled by the IQ, - // and there's no stores waiting to write back, and dispatch is not - // unblocking, then there is no internal activity for the IEW stage. - if (_status == Active && !instQueue.hasReadyInsts() && - !ldstQueue.willWB() && !any_unblocking) { - DPRINTF(IEW, "IEW switching to idle\n"); - - deactivateStage(); - - _status = Inactive; - } else if (_status == Inactive && (instQueue.hasReadyInsts() || - ldstQueue.willWB() || - any_unblocking)) { - // Otherwise there is internal activity. Set to active. - DPRINTF(IEW, "IEW switching to active\n"); - - activateStage(); - - _status = Active; - } -} - -template <class Impl> -void -DefaultIEW<Impl>::resetEntries() -{ - instQueue.resetEntries(); - ldstQueue.resetEntries(); -} - -template <class Impl> -void -DefaultIEW<Impl>::readStallSignals(unsigned tid) -{ - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - stalls[tid].commit = false; - } -} - -template <class Impl> -bool -DefaultIEW<Impl>::checkStall(unsigned tid) -{ - bool ret_val(false); - - if (stalls[tid].commit) { - DPRINTF(IEW,"[tid:%i]: Stall from Commit stage detected.\n",tid); - ret_val = true; - } else if (instQueue.isFull(tid)) { - DPRINTF(IEW,"[tid:%i]: Stall: IQ is full.\n",tid); - ret_val = true; - } else if (ldstQueue.isFull(tid)) { - DPRINTF(IEW,"[tid:%i]: Stall: LSQ is full\n",tid); - - if (ldstQueue.numLoads(tid) > 0 ) { - - DPRINTF(IEW,"[tid:%i]: LSQ oldest load: [sn:%i] \n", - tid,ldstQueue.getLoadHeadSeqNum(tid)); - } - - if (ldstQueue.numStores(tid) > 0) { - - DPRINTF(IEW,"[tid:%i]: LSQ oldest store: [sn:%i] \n", - tid,ldstQueue.getStoreHeadSeqNum(tid)); - } - - ret_val = true; - } else if (ldstQueue.isStalled(tid)) { - DPRINTF(IEW,"[tid:%i]: Stall: LSQ stall detected.\n",tid); - ret_val = true; - } - - return ret_val; -} - -template <class Impl> -void -DefaultIEW<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Check if there's a squash signal, squash if there is - // Check stall signals, block if there is. - // If status was Blocked - // if so then go to unblocking - // If status was Squashing - // check if squashing is not high. Switch to running this cycle. - - readStallSignals(tid); - - if (fromCommit->commitInfo[tid].squash) { - squash(tid); - - if (dispatchStatus[tid] == Blocked || - dispatchStatus[tid] == Unblocking) { - toRename->iewUnblock[tid] = true; - wroteToTimeBuffer = true; - } - - dispatchStatus[tid] = Squashing; - - fetchRedirect[tid] = false; - return; - } - - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(IEW, "[tid:%i]: ROB is still squashing.\n"); - - dispatchStatus[tid] = Squashing; - - return; - } - - if (checkStall(tid)) { - block(tid); - dispatchStatus[tid] = Blocked; - return; - } - - if (dispatchStatus[tid] == Blocked) { - // Status from previous cycle was blocked, but there are no more stall - // conditions. Switch over to unblocking. - DPRINTF(IEW, "[tid:%i]: Done blocking, switching to unblocking.\n", - tid); - - dispatchStatus[tid] = Unblocking; - - unblock(tid); - - return; - } - - if (dispatchStatus[tid] == Squashing) { - // Switch status to running if rename isn't being told to block or - // squash this cycle. - DPRINTF(IEW, "[tid:%i]: Done squashing, switching to running.\n", - tid); - - dispatchStatus[tid] = Running; - - return; - } -} - -template <class Impl> -void -DefaultIEW<Impl>::sortInsts() -{ - int insts_from_rename = fromRename->size; -#ifdef DEBUG - for (int i = 0; i < numThreads; i++) - assert(insts[i].empty()); -#endif - for (int i = 0; i < insts_from_rename; ++i) { - insts[fromRename->insts[i]->threadNumber].push(fromRename->insts[i]); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::wakeCPU() -{ - cpu->wakeCPU(); -} - -template <class Impl> -void -DefaultIEW<Impl>::activityThisCycle() -{ - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); -} - -template <class Impl> -inline void -DefaultIEW<Impl>::activateStage() -{ - DPRINTF(Activity, "Activating stage.\n"); - cpu->activateStage(FullCPU::IEWIdx); -} - -template <class Impl> -inline void -DefaultIEW<Impl>::deactivateStage() -{ - DPRINTF(Activity, "Deactivating stage.\n"); - cpu->deactivateStage(FullCPU::IEWIdx); -} - -template<class Impl> -void -DefaultIEW<Impl>::dispatch(unsigned tid) -{ - // If status is Running or idle, - // call dispatchInsts() - // If status is Unblocking, - // buffer any instructions coming from rename - // continue trying to empty skid buffer - // check if stall conditions have passed - - if (dispatchStatus[tid] == Blocked) { - ++iewBlockCycles; - - } else if (dispatchStatus[tid] == Squashing) { - ++iewSquashCycles; - } - - // Dispatch should try to dispatch as many instructions as its bandwidth - // will allow, as long as it is not currently blocked. - if (dispatchStatus[tid] == Running || - dispatchStatus[tid] == Idle) { - DPRINTF(IEW, "[tid:%i] Not blocked, so attempting to run " - "dispatch.\n", tid); - - dispatchInsts(tid); - } else if (dispatchStatus[tid] == Unblocking) { - // Make sure that the skid buffer has something in it if the - // status is unblocking. - assert(!skidsEmpty()); - - // If the status was unblocking, then instructions from the skid - // buffer were used. Remove those instructions and handle - // the rest of unblocking. - dispatchInsts(tid); - - ++iewUnblockCycles; - - if (validInstsFromRename() && dispatchedAllInsts) { - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - } - - unblock(tid); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::dispatchInsts(unsigned tid) -{ - dispatchedAllInsts = true; - - // Obtain instructions from skid buffer if unblocking, or queue from rename - // otherwise. - std::queue<DynInstPtr> &insts_to_dispatch = - dispatchStatus[tid] == Unblocking ? - skidBuffer[tid] : insts[tid]; - - int insts_to_add = insts_to_dispatch.size(); - - DynInstPtr inst; - bool add_to_iq = false; - int dis_num_inst = 0; - - // Loop through the instructions, putting them in the instruction - // queue. - for ( ; dis_num_inst < insts_to_add && - dis_num_inst < issueReadWidth; - ++dis_num_inst) - { - inst = insts_to_dispatch.front(); - - if (dispatchStatus[tid] == Unblocking) { - DPRINTF(IEW, "[tid:%i]: Issue: Examining instruction from skid " - "buffer\n", tid); - } - - // Make sure there's a valid instruction there. - assert(inst); - - DPRINTF(IEW, "[tid:%i]: Issue: Adding PC %#x [sn:%lli] [tid:%i] to " - "IQ.\n", - tid, inst->readPC(), inst->seqNum, inst->threadNumber); - - // Be sure to mark these instructions as ready so that the - // commit stage can go ahead and execute them, and mark - // them as issued so the IQ doesn't reprocess them. - - // Check for squashed instructions. - if (inst->isSquashed()) { - DPRINTF(IEW, "[tid:%i]: Issue: Squashed instruction encountered, " - "not adding to IQ.\n", tid); - - ++iewDispSquashedInsts; - - insts_to_dispatch.pop(); - - //Tell Rename That An Instruction has been processed - if (inst->isLoad() || inst->isStore()) { - toRename->iewInfo[tid].dispatchedToLSQ++; - } - toRename->iewInfo[tid].dispatched++; - - continue; - } - - // Check for full conditions. - if (instQueue.isFull(tid)) { - DPRINTF(IEW, "[tid:%i]: Issue: IQ has become full.\n", tid); - - // Call function to start blocking. - block(tid); - - // Set unblock to false. Special case where we are using - // skidbuffer (unblocking) instructions but then we still - // get full in the IQ. - toRename->iewUnblock[tid] = false; - - dispatchedAllInsts = false; - - ++iewIQFullEvents; - break; - } else if (ldstQueue.isFull(tid)) { - DPRINTF(IEW, "[tid:%i]: Issue: LSQ has become full.\n",tid); - - // Call function to start blocking. - block(tid); - - // Set unblock to false. Special case where we are using - // skidbuffer (unblocking) instructions but then we still - // get full in the IQ. - toRename->iewUnblock[tid] = false; - - dispatchedAllInsts = false; - - ++iewLSQFullEvents; - break; - } - - // Otherwise issue the instruction just fine. - if (inst->isLoad()) { - DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction " - "encountered, adding to LSQ.\n", tid); - - // Reserve a spot in the load store queue for this - // memory access. - ldstQueue.insertLoad(inst); - - ++iewDispLoadInsts; - - add_to_iq = true; - - toRename->iewInfo[tid].dispatchedToLSQ++; - } else if (inst->isStore()) { - DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction " - "encountered, adding to LSQ.\n", tid); - - ldstQueue.insertStore(inst); - - ++iewDispStoreInsts; - - if (inst->isStoreConditional()) { - // Store conditionals need to be set as "canCommit()" - // so that commit can process them when they reach the - // head of commit. - inst->setCanCommit(); - instQueue.insertNonSpec(inst); - add_to_iq = false; - - ++iewDispNonSpecInsts; - } else { - add_to_iq = true; - } - - toRename->iewInfo[tid].dispatchedToLSQ++; -#if FULL_SYSTEM - } else if (inst->isMemBarrier() || inst->isWriteBarrier()) { - // Same as non-speculative stores. - inst->setCanCommit(); - instQueue.insertBarrier(inst); - add_to_iq = false; -#endif - } else if (inst->isNonSpeculative()) { - DPRINTF(IEW, "[tid:%i]: Issue: Nonspeculative instruction " - "encountered, skipping.\n", tid); - - // Same as non-speculative stores. - inst->setCanCommit(); - - // Specifically insert it as nonspeculative. - instQueue.insertNonSpec(inst); - - ++iewDispNonSpecInsts; - - add_to_iq = false; - } else if (inst->isNop()) { - DPRINTF(IEW, "[tid:%i]: Issue: Nop instruction encountered, " - "skipping.\n", tid); - - inst->setIssued(); - inst->setExecuted(); - inst->setCanCommit(); - - instQueue.recordProducer(inst); - - exeNop[tid]++; - - add_to_iq = false; - } else if (inst->isExecuted()) { - assert(0 && "Instruction shouldn't be executed.\n"); - DPRINTF(IEW, "Issue: Executed branch encountered, " - "skipping.\n"); - - inst->setIssued(); - inst->setCanCommit(); - - instQueue.recordProducer(inst); - - add_to_iq = false; - } else { - add_to_iq = true; - } - - // If the instruction queue is not full, then add the - // instruction. - if (add_to_iq) { - instQueue.insert(inst); - } - - insts_to_dispatch.pop(); - - toRename->iewInfo[tid].dispatched++; - - ++iewDispatchedInsts; - } - - if (!insts_to_dispatch.empty()) { - DPRINTF(IEW,"[tid:%i]: Issue: Bandwidth Full. Blocking.\n"); - block(tid); - toRename->iewUnblock[tid] = false; - } - - if (dispatchStatus[tid] == Idle && dis_num_inst) { - dispatchStatus[tid] = Running; - - updatedQueues = true; - } - - dis_num_inst = 0; -} - -template <class Impl> -void -DefaultIEW<Impl>::printAvailableInsts() -{ - int inst = 0; - - cout << "Available Instructions: "; - - while (fromIssue->insts[inst]) { - - if (inst%3==0) cout << "\n\t"; - - cout << "PC: " << fromIssue->insts[inst]->readPC() - << " TN: " << fromIssue->insts[inst]->threadNumber - << " SN: " << fromIssue->insts[inst]->seqNum << " | "; - - inst++; - - } - - cout << "\n"; -} - -template <class Impl> -void -DefaultIEW<Impl>::executeInsts() -{ - wbNumInst = 0; - wbCycle = 0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - fetchRedirect[tid] = false; - } - -#if 0 - printAvailableInsts(); -#endif - - // Execute/writeback any instructions that are available. - int insts_to_execute = fromIssue->size; - int inst_num = 0; - for (; inst_num < insts_to_execute; - ++inst_num) { - - DPRINTF(IEW, "Execute: Executing instructions from IQ.\n"); - - DynInstPtr inst = instQueue.getInstToExecute(); - - DPRINTF(IEW, "Execute: Processing PC %#x, [tid:%i] [sn:%i].\n", - inst->readPC(), inst->threadNumber,inst->seqNum); - - // Check if the instruction is squashed; if so then skip it - if (inst->isSquashed()) { - DPRINTF(IEW, "Execute: Instruction was squashed.\n"); - - // Consider this instruction executed so that commit can go - // ahead and retire the instruction. - inst->setExecuted(); - - // Not sure if I should set this here or just let commit try to - // commit any squashed instructions. I like the latter a bit more. - inst->setCanCommit(); - - ++iewExecSquashedInsts; - - continue; - } - - Fault fault = NoFault; - - // Execute instruction. - // Note that if the instruction faults, it will be handled - // at the commit stage. - if (inst->isMemRef() && - (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { - DPRINTF(IEW, "Execute: Calculating address for memory " - "reference.\n"); - - // Tell the LDSTQ to execute this instruction (if it is a load). - if (inst->isLoad()) { - // Loads will mark themselves as executed, and their writeback - // event adds the instruction to the queue to commit - fault = ldstQueue.executeLoad(inst); - } else if (inst->isStore()) { - ldstQueue.executeStore(inst); - - // If the store had a fault then it may not have a mem req - if (inst->req && !(inst->req->flags & LOCKED)) { - inst->setExecuted(); - - instToCommit(inst); - } - - // Store conditionals will mark themselves as - // executed, and their writeback event will add the - // instruction to the queue to commit. - } else { - panic("Unexpected memory type!\n"); - } - - } else { - inst->execute(); - - inst->setExecuted(); - - instToCommit(inst); - } - - updateExeInstStats(inst); - - // Check if branch prediction was correct, if not then we need - // to tell commit to squash in flight instructions. Only - // handle this if there hasn't already been something that - // redirects fetch in this group of instructions. - - // This probably needs to prioritize the redirects if a different - // scheduler is used. Currently the scheduler schedules the oldest - // instruction first, so the branch resolution order will be correct. - unsigned tid = inst->threadNumber; - - if (!fetchRedirect[tid]) { - - if (inst->mispredicted()) { - fetchRedirect[tid] = true; - - DPRINTF(IEW, "Execute: Branch mispredict detected.\n"); - DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x.\n", - inst->nextPC); - - // If incorrect, then signal the ROB that it must be squashed. - squashDueToBranch(inst, tid); - - if (inst->predTaken()) { - predictedTakenIncorrect++; - } else { - predictedNotTakenIncorrect++; - } - } else if (ldstQueue.violation(tid)) { - fetchRedirect[tid] = true; - - // If there was an ordering violation, then get the - // DynInst that caused the violation. Note that this - // clears the violation signal. - DynInstPtr violator; - violator = ldstQueue.getMemDepViolator(tid); - - DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: " - "%#x, inst PC: %#x. Addr is: %#x.\n", - violator->readPC(), inst->readPC(), inst->physEffAddr); - - // Tell the instruction queue that a violation has occured. - instQueue.violation(inst, violator); - - // Squash. - squashDueToMemOrder(inst,tid); - - ++memOrderViolationEvents; - } else if (ldstQueue.loadBlocked(tid) && - !ldstQueue.isLoadBlockedHandled(tid)) { - fetchRedirect[tid] = true; - - DPRINTF(IEW, "Load operation couldn't execute because the " - "memory system is blocked. PC: %#x [sn:%lli]\n", - inst->readPC(), inst->seqNum); - - squashDueToMemBlocked(inst, tid); - } - } - } - - if (inst_num) { - if (exeStatus == Idle) { - exeStatus = Running; - } - - updatedQueues = true; - - cpu->activityThisCycle(); - } - - // Need to reset this in case a writeback event needs to write into the - // iew queue. That way the writeback event will write into the correct - // spot in the queue. - wbNumInst = 0; -} - -template <class Impl> -void -DefaultIEW<Impl>::writebackInsts() -{ - // Loop through the head of the time buffer and wake any - // dependents. These instructions are about to write back. Also - // mark scoreboard that this instruction is finally complete. - // Either have IEW have direct access to scoreboard, or have this - // as part of backwards communication. - for (int inst_num = 0; inst_num < issueWidth && - toCommit->insts[inst_num]; inst_num++) { - DynInstPtr inst = toCommit->insts[inst_num]; - int tid = inst->threadNumber; - - DPRINTF(IEW, "Sending instructions to commit, PC %#x.\n", - inst->readPC()); - - iewInstsToCommit[tid]++; - - // Some instructions will be sent to commit without having - // executed because they need commit to handle them. - // E.g. Uncached loads have not actually executed when they - // are first sent to commit. Instead commit must tell the LSQ - // when it's ready to execute the uncached load. - if (!inst->isSquashed() && inst->isExecuted()) { - int dependents = instQueue.wakeDependents(inst); - - for (int i = 0; i < inst->numDestRegs(); i++) { - //mark as Ready - DPRINTF(IEW,"Setting Destination Register %i\n", - inst->renamedDestRegIdx(i)); - scoreboard->setReg(inst->renamedDestRegIdx(i)); - } - - producerInst[tid]++; - consumerInst[tid]+= dependents; - writebackCount[tid]++; - } - } -} - -template<class Impl> -void -DefaultIEW<Impl>::tick() -{ - wbNumInst = 0; - wbCycle = 0; - - wroteToTimeBuffer = false; - updatedQueues = false; - - sortInsts(); - - // Free function units marked as being freed this cycle. - fuPool->processFreeUnits(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - // Check stall and squash signals, dispatch any instructions. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - DPRINTF(IEW,"Issue: Processing [tid:%i]\n",tid); - - checkSignalsAndUpdate(tid); - dispatch(tid); - } - - if (exeStatus != Squashing) { - executeInsts(); - - writebackInsts(); - - // Have the instruction queue try to schedule any ready instructions. - // (In actuality, this scheduling is for instructions that will - // be executed next cycle.) - instQueue.scheduleReadyInsts(); - - // Also should advance its own time buffers if the stage ran. - // Not the best place for it, but this works (hopefully). - issueToExecQueue.advance(); - } - - bool broadcast_free_entries = false; - - if (updatedQueues || exeStatus == Running || updateLSQNextCycle) { - exeStatus = Idle; - updateLSQNextCycle = false; - - broadcast_free_entries = true; - } - - // Writeback any stores using any leftover bandwidth. - ldstQueue.writebackStores(); - - // Check the committed load/store signals to see if there's a load - // or store to commit. Also check if it's being told to execute a - // nonspeculative instruction. - // This is pretty inefficient... - - threads = (*activeThreads).begin(); - while (threads != (*activeThreads).end()) { - unsigned tid = (*threads++); - - DPRINTF(IEW,"Processing [tid:%i]\n",tid); - - if (fromCommit->commitInfo[tid].doneSeqNum != 0 && - !fromCommit->commitInfo[tid].squash && - !fromCommit->commitInfo[tid].robSquashing) { - - ldstQueue.commitStores(fromCommit->commitInfo[tid].doneSeqNum,tid); - - ldstQueue.commitLoads(fromCommit->commitInfo[tid].doneSeqNum,tid); - - updateLSQNextCycle = true; - instQueue.commit(fromCommit->commitInfo[tid].doneSeqNum,tid); - } - - if (fromCommit->commitInfo[tid].nonSpecSeqNum != 0) { - - //DPRINTF(IEW,"NonspecInst from thread %i",tid); - if (fromCommit->commitInfo[tid].uncached) { - instQueue.replayMemInst(fromCommit->commitInfo[tid].uncachedLoad); - } else { - instQueue.scheduleNonSpec( - fromCommit->commitInfo[tid].nonSpecSeqNum); - } - } - - if (broadcast_free_entries) { - toFetch->iewInfo[tid].iqCount = - instQueue.getCount(tid); - toFetch->iewInfo[tid].ldstqCount = - ldstQueue.getCount(tid); - - toRename->iewInfo[tid].usedIQ = true; - toRename->iewInfo[tid].freeIQEntries = - instQueue.numFreeEntries(); - toRename->iewInfo[tid].usedLSQ = true; - toRename->iewInfo[tid].freeLSQEntries = - ldstQueue.numFreeEntries(tid); - - wroteToTimeBuffer = true; - } - - DPRINTF(IEW, "[tid:%i], Dispatch dispatched %i instructions.\n", - tid, toRename->iewInfo[tid].dispatched); - } - - DPRINTF(IEW, "IQ has %i free entries (Can schedule: %i). " - "LSQ has %i free entries.\n", - instQueue.numFreeEntries(), instQueue.hasReadyInsts(), - ldstQueue.numFreeEntries()); - - updateStatus(); - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::updateExeInstStats(DynInstPtr &inst) -{ - int thread_number = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) - exeSwp[thread_number]++; - else - iewExecutedInsts++; -#else - iewExecutedInsts[thread_number]++; -#endif - - // - // Control operations - // - if (inst->isControl()) - exeBranches[thread_number]++; - - // - // Memory operations - // - if (inst->isMemRef()) { - exeRefs[thread_number]++; - - if (inst->isLoad()) { - iewExecLoadInsts[thread_number]++; - } - } -} diff --git a/cpu/o3/inst_queue.cc b/cpu/o3/inst_queue.cc deleted file mode 100644 index 95ae2b699..000000000 --- a/cpu/o3/inst_queue.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/inst_queue_impl.hh" - -// Force instantiation of InstructionQueue. -template class InstructionQueue<AlphaSimpleImpl>; diff --git a/cpu/o3/inst_queue.hh b/cpu/o3/inst_queue.hh deleted file mode 100644 index 518de73d9..000000000 --- a/cpu/o3/inst_queue.hh +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_INST_QUEUE_HH__ -#define __CPU_O3_INST_QUEUE_HH__ - -#include <list> -#include <map> -#include <queue> -#include <vector> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/dep_graph.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "sim/host.hh" - -class FUPool; -class MemInterface; - -/** - * A standard instruction queue class. It holds ready instructions, in - * order, in seperate priority queues to facilitate the scheduling of - * instructions. The IQ uses a separate linked list to track dependencies. - * Similar to the rename map and the free list, it expects that - * floating point registers have their indices start after the integer - * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer - * and 96-191 are fp). This remains true even for both logical and - * physical register indices. The IQ depends on the memory dependence unit to - * track when memory operations are ready in terms of ordering; register - * dependencies are tracked normally. Right now the IQ also handles the - * execution timing; this is mainly to allow back-to-back scheduling without - * requiring IEW to be able to peek into the IQ. At the end of the execution - * latency, the instruction is put into the queue to execute, where it will - * have the execute() function called on it. - * @todo: Make IQ able to handle multiple FU pools. - */ -template <class Impl> -class InstructionQueue -{ - public: - //Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - - typedef typename Impl::CPUPol::IEW IEW; - typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; - typedef typename Impl::CPUPol::IssueStruct IssueStruct; - typedef typename Impl::CPUPol::TimeStruct TimeStruct; - - // Typedef of iterator through the list of instructions. - typedef typename std::list<DynInstPtr>::iterator ListIt; - - friend class Impl::FullCPU; - - /** FU completion event class. */ - class FUCompletion : public Event { - private: - /** Executing instruction. */ - DynInstPtr inst; - - /** Index of the FU used for executing. */ - int fuIdx; - - /** Pointer back to the instruction queue. */ - InstructionQueue<Impl> *iqPtr; - - bool freeFU; - - public: - /** Construct a FU completion event. */ - FUCompletion(DynInstPtr &_inst, int fu_idx, - InstructionQueue<Impl> *iq_ptr); - - virtual void process(); - virtual const char *description(); - void setFreeFU() { freeFU = true; } - }; - - /** Constructs an IQ. */ - InstructionQueue(Params *params); - - /** Destructs the IQ. */ - ~InstructionQueue(); - - /** Returns the name of the IQ. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - void resetState(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *_cpu) { cpu = _cpu; } - - /** Sets active threads list. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets the IEW pointer. */ - void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; } - - /** Sets the timer buffer between issue and execute. */ - void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue); - - /** Sets the global time buffer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - void switchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - /** Number of entries needed for given amount of threads. */ - int entryAmount(int num_threads); - - /** Resets max entries for all threads. */ - void resetEntries(); - - /** Returns total number of free entries. */ - unsigned numFreeEntries(); - - /** Returns number of free entries for a thread. */ - unsigned numFreeEntries(unsigned tid); - - /** Returns whether or not the IQ is full. */ - bool isFull(); - - /** Returns whether or not the IQ is full for a specific thread. */ - bool isFull(unsigned tid); - - /** Returns if there are any ready instructions in the IQ. */ - bool hasReadyInsts(); - - /** Inserts a new instruction into the IQ. */ - void insert(DynInstPtr &new_inst); - - /** Inserts a new, non-speculative instruction into the IQ. */ - void insertNonSpec(DynInstPtr &new_inst); - - /** Inserts a memory or write barrier into the IQ to make sure - * loads and stores are ordered properly. - */ - void insertBarrier(DynInstPtr &barr_inst); - - DynInstPtr getInstToExecute(); - - /** - * Records the instruction as the producer of a register without - * adding it to the rest of the IQ. - */ - void recordProducer(DynInstPtr &inst) - { addToProducers(inst); } - - /** Process FU completion event. */ - void processFUCompletion(DynInstPtr &inst, int fu_idx); - - /** - * Schedules ready instructions, adding the ready ones (oldest first) to - * the queue to execute. - */ - void scheduleReadyInsts(); - - /** Schedules a single specific non-speculative instruction. */ - void scheduleNonSpec(const InstSeqNum &inst); - - /** - * Commits all instructions up to and including the given sequence number, - * for a specific thread. - */ - void commit(const InstSeqNum &inst, unsigned tid = 0); - - /** Wakes all dependents of a completed instruction. */ - int wakeDependents(DynInstPtr &completed_inst); - - /** Adds a ready memory instruction to the ready list. */ - void addReadyMemInst(DynInstPtr &ready_inst); - - /** - * Reschedules a memory instruction. It will be ready to issue once - * replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &resched_inst); - - /** Replays a memory instruction. It must be rescheduled first. */ - void replayMemInst(DynInstPtr &replay_inst); - - /** Completes a memory operation. */ - void completeMemInst(DynInstPtr &completed_inst); - - /** Indicates an ordering violation between a store and a load. */ - void violation(DynInstPtr &store, DynInstPtr &faulting_load); - - /** - * Squashes instructions for a thread. Squashing information is obtained - * from the time buffer. - */ - void squash(unsigned tid); - - /** Returns the number of used entries for a thread. */ - unsigned getCount(unsigned tid) { return count[tid]; }; - - /** Debug function to print all instructions. */ - void printInsts(); - - private: - /** Does the actual squashing. */ - void doSquash(unsigned tid); - - ///////////////////////// - // Various pointers - ///////////////////////// - - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Cache interface. */ - MemInterface *dcacheInterface; - - /** Pointer to IEW stage. */ - IEW *iewStage; - - /** The memory dependence unit, which tracks/predicts memory dependences - * between instructions. - */ - MemDepUnit memDepUnit[Impl::MaxThreads]; - - /** The queue to the execute stage. Issued instructions will be written - * into it. - */ - TimeBuffer<IssueStruct> *issueToExecuteQueue; - - /** The backwards time buffer. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to read information from timebuffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Function unit pool. */ - FUPool *fuPool; - - ////////////////////////////////////// - // Instruction lists, ready queues, and ordering - ////////////////////////////////////// - - /** List of all the instructions in the IQ (some of which may be issued). */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - std::list<DynInstPtr> instsToExecute; - - /** - * Struct for comparing entries to be added to the priority queue. This - * gives reverse ordering to the instructions in terms of sequence - * numbers: the instructions with smaller sequence numbers (and hence - * are older) will be at the top of the priority queue. - */ - struct pqCompare { - bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const - { - return lhs->seqNum > rhs->seqNum; - } - }; - - typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> - ReadyInstQueue; - - /** List of ready instructions, per op class. They are separated by op - * class to allow for easy mapping to FUs. - */ - ReadyInstQueue readyInsts[Num_OpClasses]; - - /** List of non-speculative instructions that will be scheduled - * once the IQ gets a signal from commit. While it's redundant to - * have the key be a part of the value (the sequence number is stored - * inside of DynInst), when these instructions are woken up only - * the sequence number will be available. Thus it is most efficient to be - * able to search by the sequence number alone. - */ - std::map<InstSeqNum, DynInstPtr> nonSpecInsts; - - typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt; - - /** Entry for the list age ordering by op class. */ - struct ListOrderEntry { - OpClass queueType; - InstSeqNum oldestInst; - }; - - /** List that contains the age order of the oldest instruction of each - * ready queue. Used to select the oldest instruction available - * among op classes. - * @todo: Might be better to just move these entries around instead - * of creating new ones every time the position changes due to an - * instruction issuing. Not sure std::list supports this. - */ - std::list<ListOrderEntry> listOrder; - - typedef typename std::list<ListOrderEntry>::iterator ListOrderIt; - - /** Tracks if each ready queue is on the age order list. */ - bool queueOnList[Num_OpClasses]; - - /** Iterators of each ready queue. Points to their spot in the age order - * list. - */ - ListOrderIt readyIt[Num_OpClasses]; - - /** Add an op class to the age order list. */ - void addToOrderList(OpClass op_class); - - /** - * Called when the oldest instruction has been removed from a ready queue; - * this places that ready queue into the proper spot in the age order list. - */ - void moveToYoungerInst(ListOrderIt age_order_it); - - DependencyGraph<DynInstPtr> dependGraph; - - ////////////////////////////////////// - // Various parameters - ////////////////////////////////////// - - /** IQ Resource Sharing Policy */ - enum IQPolicy { - Dynamic, - Partitioned, - Threshold - }; - - /** IQ sharing policy for SMT. */ - IQPolicy iqPolicy; - - /** Number of Total Threads*/ - unsigned numThreads; - - /** Pointer to list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Per Thread IQ count */ - unsigned count[Impl::MaxThreads]; - - /** Max IQ Entries Per Thread */ - unsigned maxEntries[Impl::MaxThreads]; - - /** Number of free IQ entries left. */ - unsigned freeEntries; - - /** The number of entries in the instruction queue. */ - unsigned numEntries; - - /** The total number of instructions that can be issued in one cycle. */ - unsigned totalWidth; - - /** The number of physical registers in the CPU. */ - unsigned numPhysRegs; - - /** The number of physical integer registers in the CPU. */ - unsigned numPhysIntRegs; - - /** The number of floating point registers in the CPU. */ - unsigned numPhysFloatRegs; - - /** Delay between commit stage and the IQ. - * @todo: Make there be a distinction between the delays within IEW. - */ - unsigned commitToIEWDelay; - - bool switchedOut; - - /** The sequence number of the squashed instruction. */ - InstSeqNum squashedSeqNum[Impl::MaxThreads]; - - /** A cache of the recently woken registers. It is 1 if the register - * has been woken up recently, and 0 if the register has been added - * to the dependency graph and has not yet received its value. It - * is basically a secondary scoreboard, and should pretty much mirror - * the scoreboard that exists in the rename map. - */ - std::vector<bool> regScoreboard; - - /** Adds an instruction to the dependency graph, as a consumer. */ - bool addToDependents(DynInstPtr &new_inst); - - /** Adds an instruction to the dependency graph, as a producer. */ - void addToProducers(DynInstPtr &new_inst); - - /** Moves an instruction to the ready queue if it is ready. */ - void addIfReady(DynInstPtr &inst); - - /** Debugging function to count how many entries are in the IQ. It does - * a linear walk through the instructions, so do not call this function - * during normal execution. - */ - int countInsts(); - - /** Debugging function to dump all the list sizes, as well as print - * out the list of nonspeculative instructions. Should not be used - * in any other capacity, but it has no harmful sideaffects. - */ - void dumpLists(); - - /** Debugging function to dump out all instructions that are in the - * IQ. - */ - void dumpInsts(); - - /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; - /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; - - Stats::Scalar<> iqInstsIssued; - /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; - /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; - /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; - /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; - /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; - /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; - /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; - /** Stat for number of squashed instruction operands examined when - * squashing. - */ - Stats::Scalar<> iqSquashedOperandsExamined; - /** Stat for number of non-speculative instructions removed due to a squash. - */ - Stats::Scalar<> iqSquashedNonSpecRemoved; - - Stats::VectorDistribution<> queueResDist; - Stats::Distribution<> numIssuedDist; - Stats::VectorDistribution<> issueDelayDist; - - Stats::Vector<> statFuBusy; -// Stats::Vector<> dist_unissued; - Stats::Vector2d<> statIssuedInstType; - - Stats::Formula issueRate; -// Stats::Formula issue_stores; -// Stats::Formula issue_op_rate; - Stats::Vector<> fuBusy; //cumulative fu busy - - Stats::Formula fuBusyRate; -}; - -#endif //__CPU_O3_INST_QUEUE_HH__ diff --git a/cpu/o3/inst_queue_impl.hh b/cpu/o3/inst_queue_impl.hh deleted file mode 100644 index f1dc4e01f..000000000 --- a/cpu/o3/inst_queue_impl.hh +++ /dev/null @@ -1,1367 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <limits> -#include <vector> - -#include "sim/root.hh" - -#include "cpu/o3/fu_pool.hh" -#include "cpu/o3/inst_queue.hh" - -using namespace std; - -template <class Impl> -InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, - int fu_idx, - InstructionQueue<Impl> *iq_ptr) - : Event(&mainEventQueue, Stat_Event_Pri), - inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -InstructionQueue<Impl>::FUCompletion::process() -{ - iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1); - inst = NULL; -} - - -template <class Impl> -const char * -InstructionQueue<Impl>::FUCompletion::description() -{ - return "Functional unit completion event"; -} - -template <class Impl> -InstructionQueue<Impl>::InstructionQueue(Params *params) - : dcacheInterface(params->dcacheInterface), - fuPool(params->fuPool), - numEntries(params->numIQEntries), - totalWidth(params->issueWidth), - numPhysIntRegs(params->numPhysIntRegs), - numPhysFloatRegs(params->numPhysFloatRegs), - commitToIEWDelay(params->commitToIEWDelay) -{ - assert(fuPool); - - switchedOut = false; - - numThreads = params->numberOfThreads; - - // Set the number of physical registers as the number of int + float - numPhysRegs = numPhysIntRegs + numPhysFloatRegs; - - DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs); - - //Create an entry for each physical register within the - //dependency graph. - dependGraph.resize(numPhysRegs); - - // Resize the register scoreboard. - regScoreboard.resize(numPhysRegs); - - //Initialize Mem Dependence Units - for (int i = 0; i < numThreads; i++) { - memDepUnit[i].init(params,i); - memDepUnit[i].setIQ(this); - } - - resetState(); - - string policy = params->smtIQPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Figure out resource sharing policy - if (policy == "dynamic") { - iqPolicy = Dynamic; - - //Set Max Entries to Total ROB Capacity - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = numEntries; - } - - } else if (policy == "partitioned") { - iqPolicy = Partitioned; - - //@todo:make work if part_amt doesnt divide evenly. - int part_amt = numEntries / numThreads; - - //Divide ROB up evenly - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = part_amt; - } - - DPRINTF(Fetch, "IQ sharing policy set to Partitioned:" - "%i entries per thread.\n",part_amt); - - } else if (policy == "threshold") { - iqPolicy = Threshold; - - double threshold = (double)params->smtIQThreshold / 100; - - int thresholdIQ = (int)((double)threshold * numEntries); - - //Divide up by threshold amount - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = thresholdIQ; - } - - DPRINTF(Fetch, "IQ sharing policy set to Threshold:" - "%i entries per thread.\n",thresholdIQ); - } else { - assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," - "Partitioned, Threshold}"); - } -} - -template <class Impl> -InstructionQueue<Impl>::~InstructionQueue() -{ - dependGraph.reset(); - cprintf("Nodes traversed: %i, removed: %i\n", - dependGraph.nodesTraversed, dependGraph.nodesRemoved); -} - -template <class Impl> -std::string -InstructionQueue<Impl>::name() const -{ - return cpu->name() + ".iq"; -} - -template <class Impl> -void -InstructionQueue<Impl>::regStats() -{ - using namespace Stats; - iqInstsAdded - .name(name() + ".iqInstsAdded") - .desc("Number of instructions added to the IQ (excludes non-spec)") - .prereq(iqInstsAdded); - - iqNonSpecInstsAdded - .name(name() + ".iqNonSpecInstsAdded") - .desc("Number of non-speculative instructions added to the IQ") - .prereq(iqNonSpecInstsAdded); - - iqInstsIssued - .name(name() + ".iqInstsIssued") - .desc("Number of instructions issued") - .prereq(iqInstsIssued); - - iqIntInstsIssued - .name(name() + ".iqIntInstsIssued") - .desc("Number of integer instructions issued") - .prereq(iqIntInstsIssued); - - iqFloatInstsIssued - .name(name() + ".iqFloatInstsIssued") - .desc("Number of float instructions issued") - .prereq(iqFloatInstsIssued); - - iqBranchInstsIssued - .name(name() + ".iqBranchInstsIssued") - .desc("Number of branch instructions issued") - .prereq(iqBranchInstsIssued); - - iqMemInstsIssued - .name(name() + ".iqMemInstsIssued") - .desc("Number of memory instructions issued") - .prereq(iqMemInstsIssued); - - iqMiscInstsIssued - .name(name() + ".iqMiscInstsIssued") - .desc("Number of miscellaneous instructions issued") - .prereq(iqMiscInstsIssued); - - iqSquashedInstsIssued - .name(name() + ".iqSquashedInstsIssued") - .desc("Number of squashed instructions issued") - .prereq(iqSquashedInstsIssued); - - iqSquashedInstsExamined - .name(name() + ".iqSquashedInstsExamined") - .desc("Number of squashed instructions iterated over during squash;" - " mainly for profiling") - .prereq(iqSquashedInstsExamined); - - iqSquashedOperandsExamined - .name(name() + ".iqSquashedOperandsExamined") - .desc("Number of squashed operands that are examined and possibly " - "removed from graph") - .prereq(iqSquashedOperandsExamined); - - iqSquashedNonSpecRemoved - .name(name() + ".iqSquashedNonSpecRemoved") - .desc("Number of squashed non-spec instructions that were removed") - .prereq(iqSquashedNonSpecRemoved); - - queueResDist - .init(Num_OpClasses, 0, 99, 2) - .name(name() + ".IQ:residence:") - .desc("cycles from dispatch to issue") - .flags(total | pdf | cdf ) - ; - for (int i = 0; i < Num_OpClasses; ++i) { - queueResDist.subname(i, opClassStrings[i]); - } - numIssuedDist - .init(0,totalWidth,1) - .name(name() + ".ISSUE:issued_per_cycle") - .desc("Number of insts issued each cycle") - .flags(pdf) - ; -/* - dist_unissued - .init(Num_OpClasses+2) - .name(name() + ".ISSUE:unissued_cause") - .desc("Reason ready instruction not issued") - .flags(pdf | dist) - ; - for (int i=0; i < (Num_OpClasses + 2); ++i) { - dist_unissued.subname(i, unissued_names[i]); - } -*/ - statIssuedInstType - .init(numThreads,Num_OpClasses) - .name(name() + ".ISSUE:FU_type") - .desc("Type of FU issued") - .flags(total | pdf | dist) - ; - statIssuedInstType.ysubnames(opClassStrings); - - // - // How long did instructions for a particular FU type wait prior to issue - // - - issueDelayDist - .init(Num_OpClasses,0,99,2) - .name(name() + ".ISSUE:") - .desc("cycles from operands ready to issue") - .flags(pdf | cdf) - ; - - for (int i=0; i<Num_OpClasses; ++i) { - stringstream subname; - subname << opClassStrings[i] << "_delay"; - issueDelayDist.subname(i, subname.str()); - } - - issueRate - .name(name() + ".ISSUE:rate") - .desc("Inst issue rate") - .flags(total) - ; - issueRate = iqInstsIssued / cpu->numCycles; -/* - issue_stores - .name(name() + ".ISSUE:stores") - .desc("Number of stores issued") - .flags(total) - ; - issue_stores = exe_refs - exe_loads; -*/ -/* - issue_op_rate - .name(name() + ".ISSUE:op_rate") - .desc("Operation issue rate") - .flags(total) - ; - issue_op_rate = issued_ops / numCycles; -*/ - statFuBusy - .init(Num_OpClasses) - .name(name() + ".ISSUE:fu_full") - .desc("attempts to use FU when none available") - .flags(pdf | dist) - ; - for (int i=0; i < Num_OpClasses; ++i) { - statFuBusy.subname(i, opClassStrings[i]); - } - - fuBusy - .init(numThreads) - .name(name() + ".ISSUE:fu_busy_cnt") - .desc("FU busy when requested") - .flags(total) - ; - - fuBusyRate - .name(name() + ".ISSUE:fu_busy_rate") - .desc("FU busy rate (busy events/executed inst)") - .flags(total) - ; - fuBusyRate = fuBusy / iqInstsIssued; - - for ( int i=0; i < numThreads; i++) { - // Tell mem dependence unit to reg stats as well. - memDepUnit[i].regStats(); - } -} - -template <class Impl> -void -InstructionQueue<Impl>::resetState() -{ - //Initialize thread IQ counts - for (int i = 0; i <numThreads; i++) { - count[i] = 0; - instList[i].clear(); - } - - // Initialize the number of free IQ entries. - freeEntries = numEntries; - - // Note that in actuality, the registers corresponding to the logical - // registers start off as ready. However this doesn't matter for the - // IQ as the instruction should have been correctly told if those - // registers are ready in rename. Thus it can all be initialized as - // unready. - for (int i = 0; i < numPhysRegs; ++i) { - regScoreboard[i] = false; - } - - for (int i = 0; i < numThreads; ++i) { - squashedSeqNum[i] = 0; - } - - for (int i = 0; i < Num_OpClasses; ++i) { - while (!readyInsts[i].empty()) - readyInsts[i].pop(); - queueOnList[i] = false; - readyIt[i] = listOrder.end(); - } - nonSpecInsts.clear(); - listOrder.clear(); -} - -template <class Impl> -void -InstructionQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(IQ, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -InstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) -{ - DPRINTF(IQ, "Set the issue to execute queue.\n"); - issueToExecuteQueue = i2e_ptr; -} - -template <class Impl> -void -InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(IQ, "Set the time buffer.\n"); - timeBuffer = tb_ptr; - - fromCommit = timeBuffer->getWire(-commitToIEWDelay); -} - -template <class Impl> -void -InstructionQueue<Impl>::switchOut() -{ - resetState(); - dependGraph.reset(); - switchedOut = true; - for (int i = 0; i < numThreads; ++i) { - memDepUnit[i].switchOut(); - } -} - -template <class Impl> -void -InstructionQueue<Impl>::takeOverFrom() -{ - switchedOut = false; -} - -template <class Impl> -int -InstructionQueue<Impl>::entryAmount(int num_threads) -{ - if (iqPolicy == Partitioned) { - return numEntries / num_threads; - } else { - return 0; - } -} - - -template <class Impl> -void -InstructionQueue<Impl>::resetEntries() -{ - if (iqPolicy != Dynamic || numThreads > 1) { - int active_threads = (*activeThreads).size(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - list<unsigned>::iterator list_end = (*activeThreads).end(); - - while (threads != list_end) { - if (iqPolicy == Partitioned) { - maxEntries[*threads++] = numEntries / active_threads; - } else if(iqPolicy == Threshold && active_threads == 1) { - maxEntries[*threads++] = numEntries; - } - } - } -} - -template <class Impl> -unsigned -InstructionQueue<Impl>::numFreeEntries() -{ - return freeEntries; -} - -template <class Impl> -unsigned -InstructionQueue<Impl>::numFreeEntries(unsigned tid) -{ - return maxEntries[tid] - count[tid]; -} - -// Might want to do something more complex if it knows how many instructions -// will be issued this cycle. -template <class Impl> -bool -InstructionQueue<Impl>::isFull() -{ - if (freeEntries == 0) { - return(true); - } else { - return(false); - } -} - -template <class Impl> -bool -InstructionQueue<Impl>::isFull(unsigned tid) -{ - if (numFreeEntries(tid) == 0) { - return(true); - } else { - return(false); - } -} - -template <class Impl> -bool -InstructionQueue<Impl>::hasReadyInsts() -{ - if (!listOrder.empty()) { - return true; - } - - for (int i = 0; i < Num_OpClasses; ++i) { - if (!readyInsts[i].empty()) { - return true; - } - } - - return false; -} - -template <class Impl> -void -InstructionQueue<Impl>::insert(DynInstPtr &new_inst) -{ - // Make sure the instruction is valid - assert(new_inst); - - DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n", - new_inst->seqNum, new_inst->readPC()); - - assert(freeEntries != 0); - - instList[new_inst->threadNumber].push_back(new_inst); - - --freeEntries; - - new_inst->setInIQ(); - - // Look through its source registers (physical regs), and mark any - // dependencies. - addToDependents(new_inst); - - // Have this instruction set itself as the producer of its destination - // register(s). - addToProducers(new_inst); - - if (new_inst->isMemRef()) { - memDepUnit[new_inst->threadNumber].insert(new_inst); - } else { - addIfReady(new_inst); - } - - ++iqInstsAdded; - - count[new_inst->threadNumber]++; - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -void -InstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) -{ - // @todo: Clean up this code; can do it by setting inst as unable - // to issue, then calling normal insert on the inst. - - assert(new_inst); - - nonSpecInsts[new_inst->seqNum] = new_inst; - - DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x " - "to the IQ.\n", - new_inst->seqNum, new_inst->readPC()); - - assert(freeEntries != 0); - - instList[new_inst->threadNumber].push_back(new_inst); - - --freeEntries; - - new_inst->setInIQ(); - - // Have this instruction set itself as the producer of its destination - // register(s). - addToProducers(new_inst); - - // If it's a memory instruction, add it to the memory dependency - // unit. - if (new_inst->isMemRef()) { - memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); - } - - ++iqNonSpecInstsAdded; - - count[new_inst->threadNumber]++; - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -void -InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst) -{ - memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst); - - insertNonSpec(barr_inst); -} - -template <class Impl> -typename Impl::DynInstPtr -InstructionQueue<Impl>::getInstToExecute() -{ - assert(!instsToExecute.empty()); - DynInstPtr inst = instsToExecute.front(); - instsToExecute.pop_front(); - return inst; -} - -template <class Impl> -void -InstructionQueue<Impl>::addToOrderList(OpClass op_class) -{ - assert(!readyInsts[op_class].empty()); - - ListOrderEntry queue_entry; - - queue_entry.queueType = op_class; - - queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; - - ListOrderIt list_it = listOrder.begin(); - ListOrderIt list_end_it = listOrder.end(); - - while (list_it != list_end_it) { - if ((*list_it).oldestInst > queue_entry.oldestInst) { - break; - } - - list_it++; - } - - readyIt[op_class] = listOrder.insert(list_it, queue_entry); - queueOnList[op_class] = true; -} - -template <class Impl> -void -InstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) -{ - // Get iterator of next item on the list - // Delete the original iterator - // Determine if the next item is either the end of the list or younger - // than the new instruction. If so, then add in a new iterator right here. - // If not, then move along. - ListOrderEntry queue_entry; - OpClass op_class = (*list_order_it).queueType; - ListOrderIt next_it = list_order_it; - - ++next_it; - - queue_entry.queueType = op_class; - queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; - - while (next_it != listOrder.end() && - (*next_it).oldestInst < queue_entry.oldestInst) { - ++next_it; - } - - readyIt[op_class] = listOrder.insert(next_it, queue_entry); -} - -template <class Impl> -void -InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) -{ - // The CPU could have been sleeping until this op completed (*extremely* - // long latency op). Wake it if it was. This may be overkill. - if (isSwitchedOut()) { - return; - } - - iewStage->wakeCPU(); - - if (fu_idx > -1) - fuPool->freeUnitNextCycle(fu_idx); - - // @todo: Ensure that these FU Completions happen at the beginning - // of a cycle, otherwise they could add too many instructions to - // the queue. - // @todo: This could break if there's multiple multi-cycle ops - // finishing on this cycle. Maybe implement something like - // instToCommit in iew_impl.hh. - issueToExecuteQueue->access(0)->size++; - instsToExecute.push_back(inst); -// int &size = issueToExecuteQueue->access(0)->size; - -// issueToExecuteQueue->access(0)->insts[size++] = inst; -} - -// @todo: Figure out a better way to remove the squashed items from the -// lists. Checking the top item of each list to see if it's squashed -// wastes time and forces jumps. -template <class Impl> -void -InstructionQueue<Impl>::scheduleReadyInsts() -{ - DPRINTF(IQ, "Attempting to schedule ready instructions from " - "the IQ.\n"); - - IssueStruct *i2e_info = issueToExecuteQueue->access(0); - - // Have iterator to head of the list - // While I haven't exceeded bandwidth or reached the end of the list, - // Try to get a FU that can do what this op needs. - // If successful, change the oldestInst to the new top of the list, put - // the queue in the proper place in the list. - // Increment the iterator. - // This will avoid trying to schedule a certain op class if there are no - // FUs that handle it. - ListOrderIt order_it = listOrder.begin(); - ListOrderIt order_end_it = listOrder.end(); - int total_issued = 0; - - while (total_issued < totalWidth && - order_it != order_end_it) { - OpClass op_class = (*order_it).queueType; - - assert(!readyInsts[op_class].empty()); - - DynInstPtr issuing_inst = readyInsts[op_class].top(); - - assert(issuing_inst->seqNum == (*order_it).oldestInst); - - if (issuing_inst->isSquashed()) { - readyInsts[op_class].pop(); - - if (!readyInsts[op_class].empty()) { - moveToYoungerInst(order_it); - } else { - readyIt[op_class] = listOrder.end(); - queueOnList[op_class] = false; - } - - listOrder.erase(order_it++); - - ++iqSquashedInstsIssued; - - continue; - } - - int idx = -2; - int op_latency = 1; - int tid = issuing_inst->threadNumber; - - if (op_class != No_OpClass) { - idx = fuPool->getUnit(op_class); - - if (idx > -1) { - op_latency = fuPool->getOpLatency(op_class); - } - } - - if (idx == -2 || idx != -1) { - if (op_latency == 1) { -// i2e_info->insts[exec_queue_slot++] = issuing_inst; - i2e_info->size++; - instsToExecute.push_back(issuing_inst); - - // Add the FU onto the list of FU's to be freed next - // cycle if we used one. - if (idx >= 0) - fuPool->freeUnitNextCycle(idx); - } else { - int issue_latency = fuPool->getIssueLatency(op_class); - // Generate completion event for the FU - FUCompletion *execution = new FUCompletion(issuing_inst, - idx, this); - - execution->schedule(curTick + cpu->cycles(issue_latency - 1)); - - // @todo: Enforce that issue_latency == 1 or op_latency - if (issue_latency > 1) { - execution->setFreeFU(); - } else { - // @todo: Not sure I'm accounting for the - // multi-cycle op in a pipelined FU properly, or - // the number of instructions issued in one cycle. -// i2e_info->insts[exec_queue_slot++] = issuing_inst; -// i2e_info->size++; - - // Add the FU onto the list of FU's to be freed next cycle. - fuPool->freeUnitNextCycle(idx); - } - } - - DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x " - "[sn:%lli]\n", - tid, issuing_inst->readPC(), - issuing_inst->seqNum); - - readyInsts[op_class].pop(); - - if (!readyInsts[op_class].empty()) { - moveToYoungerInst(order_it); - } else { - readyIt[op_class] = listOrder.end(); - queueOnList[op_class] = false; - } - - issuing_inst->setIssued(); - ++total_issued; - - if (!issuing_inst->isMemRef()) { - // Memory instructions can not be freed from the IQ until they - // complete. - ++freeEntries; - count[tid]--; - issuing_inst->removeInIQ(); - } else { - memDepUnit[tid].issue(issuing_inst); - } - - listOrder.erase(order_it++); - statIssuedInstType[tid][op_class]++; - } else { - statFuBusy[op_class]++; - fuBusy[tid]++; - ++order_it; - } - } - - numIssuedDist.sample(total_issued); - iqInstsIssued+= total_issued; - - if (total_issued) { - cpu->activityThisCycle(); - } else { - DPRINTF(IQ, "Not able to schedule any instructions.\n"); - } -} - -template <class Impl> -void -InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) -{ - DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready " - "to execute.\n", inst); - - NonSpecMapIt inst_it = nonSpecInsts.find(inst); - - assert(inst_it != nonSpecInsts.end()); - - unsigned tid = (*inst_it).second->threadNumber; - - (*inst_it).second->setCanIssue(); - - if (!(*inst_it).second->isMemRef()) { - addIfReady((*inst_it).second); - } else { - memDepUnit[tid].nonSpecInstReady((*inst_it).second); - } - - (*inst_it).second = NULL; - - nonSpecInsts.erase(inst_it); -} - -template <class Impl> -void -InstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid) -{ - DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", - tid,inst); - - ListIt iq_it = instList[tid].begin(); - - while (iq_it != instList[tid].end() && - (*iq_it)->seqNum <= inst) { - ++iq_it; - instList[tid].pop_front(); - } - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -int -InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) -{ - int dependents = 0; - - DPRINTF(IQ, "Waking dependents of completed instruction.\n"); - - assert(!completed_inst->isSquashed()); - - // Tell the memory dependence unit to wake any dependents on this - // instruction if it is a memory instruction. Also complete the memory - // instruction at this point since we know it executed without issues. - // @todo: Might want to rename "completeMemInst" to something that - // indicates that it won't need to be replayed, and call this - // earlier. Might not be a big deal. - if (completed_inst->isMemRef()) { - memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); - completeMemInst(completed_inst); - } else if (completed_inst->isMemBarrier() || - completed_inst->isWriteBarrier()) { - memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst); - } - - for (int dest_reg_idx = 0; - dest_reg_idx < completed_inst->numDestRegs(); - dest_reg_idx++) - { - PhysRegIndex dest_reg = - completed_inst->renamedDestRegIdx(dest_reg_idx); - - // Special case of uniq or control registers. They are not - // handled by the IQ and thus have no dependency graph entry. - // @todo Figure out a cleaner way to handle this. - if (dest_reg >= numPhysRegs) { - continue; - } - - DPRINTF(IQ, "Waking any dependents on register %i.\n", - (int) dest_reg); - - //Go through the dependency chain, marking the registers as - //ready within the waiting instructions. - DynInstPtr dep_inst = dependGraph.pop(dest_reg); - - while (dep_inst) { - DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n", - dep_inst->readPC()); - - // Might want to give more information to the instruction - // so that it knows which of its source registers is - // ready. However that would mean that the dependency - // graph entries would need to hold the src_reg_idx. - dep_inst->markSrcRegReady(); - - addIfReady(dep_inst); - - dep_inst = dependGraph.pop(dest_reg); - - ++dependents; - } - - // Reset the head node now that all of its dependents have - // been woken up. - assert(dependGraph.empty(dest_reg)); - dependGraph.clearInst(dest_reg); - - // Mark the scoreboard as having that register ready. - regScoreboard[dest_reg] = true; - } - return dependents; -} - -template <class Impl> -void -InstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) -{ - OpClass op_class = ready_inst->opClass(); - - readyInsts[op_class].push(ready_inst); - - // Will need to reorder the list if either a queue is not on the list, - // or it has an older instruction than last time. - if (!queueOnList[op_class]) { - addToOrderList(op_class); - } else if (readyInsts[op_class].top()->seqNum < - (*readyIt[op_class]).oldestInst) { - listOrder.erase(readyIt[op_class]); - addToOrderList(op_class); - } - - DPRINTF(IQ, "Instruction is ready to issue, putting it onto " - "the ready list, PC %#x opclass:%i [sn:%lli].\n", - ready_inst->readPC(), op_class, ready_inst->seqNum); -} - -template <class Impl> -void -InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) -{ - memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); -} - -template <class Impl> -void -InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) -{ - memDepUnit[replay_inst->threadNumber].replay(replay_inst); -} - -template <class Impl> -void -InstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) -{ - int tid = completed_inst->threadNumber; - - DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", - completed_inst->readPC(), completed_inst->seqNum); - - ++freeEntries; - - completed_inst->memOpDone = true; - - memDepUnit[tid].completed(completed_inst); - - count[tid]--; -} - -template <class Impl> -void -InstructionQueue<Impl>::violation(DynInstPtr &store, - DynInstPtr &faulting_load) -{ - memDepUnit[store->threadNumber].violation(store, faulting_load); -} - -template <class Impl> -void -InstructionQueue<Impl>::squash(unsigned tid) -{ - DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " - "the IQ.\n", tid); - - // Read instruction sequence number of last instruction out of the - // time buffer. - squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; - - // Call doSquash if there are insts in the IQ - if (count[tid] > 0) { - doSquash(tid); - } - - // Also tell the memory dependence unit to squash. - memDepUnit[tid].squash(squashedSeqNum[tid], tid); -} - -template <class Impl> -void -InstructionQueue<Impl>::doSquash(unsigned tid) -{ - // Start at the tail. - ListIt squash_it = instList[tid].end(); - --squash_it; - - DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", - tid, squashedSeqNum[tid]); - - // Squash any instructions younger than the squashed sequence number - // given. - while (squash_it != instList[tid].end() && - (*squash_it)->seqNum > squashedSeqNum[tid]) { - - DynInstPtr squashed_inst = (*squash_it); - - // Only handle the instruction if it actually is in the IQ and - // hasn't already been squashed in the IQ. - if (squashed_inst->threadNumber != tid || - squashed_inst->isSquashedInIQ()) { - --squash_it; - continue; - } - - if (!squashed_inst->isIssued() || - (squashed_inst->isMemRef() && - !squashed_inst->memOpDone)) { - - // Remove the instruction from the dependency list. - if (!squashed_inst->isNonSpeculative() && - !squashed_inst->isStoreConditional() && - !squashed_inst->isMemBarrier() && - !squashed_inst->isWriteBarrier()) { - - for (int src_reg_idx = 0; - src_reg_idx < squashed_inst->numSrcRegs(); - src_reg_idx++) - { - PhysRegIndex src_reg = - squashed_inst->renamedSrcRegIdx(src_reg_idx); - - // Only remove it from the dependency graph if it - // was placed there in the first place. - - // Instead of doing a linked list traversal, we - // can just remove these squashed instructions - // either at issue time, or when the register is - // overwritten. The only downside to this is it - // leaves more room for error. - - if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && - src_reg < numPhysRegs) { - dependGraph.remove(src_reg, squashed_inst); - } - - - ++iqSquashedOperandsExamined; - } - } else { - NonSpecMapIt ns_inst_it = - nonSpecInsts.find(squashed_inst->seqNum); - assert(ns_inst_it != nonSpecInsts.end()); - - (*ns_inst_it).second = NULL; - - nonSpecInsts.erase(ns_inst_it); - - ++iqSquashedNonSpecRemoved; - } - - // Might want to also clear out the head of the dependency graph. - - // Mark it as squashed within the IQ. - squashed_inst->setSquashedInIQ(); - - // @todo: Remove this hack where several statuses are set so the - // inst will flow through the rest of the pipeline. - squashed_inst->setIssued(); - squashed_inst->setCanCommit(); - squashed_inst->removeInIQ(); - - //Update Thread IQ Count - count[squashed_inst->threadNumber]--; - - ++freeEntries; - - DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x " - "squashed.\n", - tid, squashed_inst->seqNum, squashed_inst->readPC()); - } - - instList[tid].erase(squash_it--); - ++iqSquashedInstsExamined; - } -} - -template <class Impl> -bool -InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst) -{ - // Loop through the instruction's source registers, adding - // them to the dependency list if they are not ready. - int8_t total_src_regs = new_inst->numSrcRegs(); - bool return_val = false; - - for (int src_reg_idx = 0; - src_reg_idx < total_src_regs; - src_reg_idx++) - { - // Only add it to the dependency graph if it's not ready. - if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { - PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); - - // Check the IQ's scoreboard to make sure the register - // hasn't become ready while the instruction was in flight - // between stages. Only if it really isn't ready should - // it be added to the dependency graph. - if (src_reg >= numPhysRegs) { - continue; - } else if (regScoreboard[src_reg] == false) { - DPRINTF(IQ, "Instruction PC %#x has src reg %i that " - "is being added to the dependency chain.\n", - new_inst->readPC(), src_reg); - - dependGraph.insert(src_reg, new_inst); - - // Change the return value to indicate that something - // was added to the dependency graph. - return_val = true; - } else { - DPRINTF(IQ, "Instruction PC %#x has src reg %i that " - "became ready before it reached the IQ.\n", - new_inst->readPC(), src_reg); - // Mark a register ready within the instruction. - new_inst->markSrcRegReady(src_reg_idx); - } - } - } - - return return_val; -} - -template <class Impl> -void -InstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst) -{ - // Nothing really needs to be marked when an instruction becomes - // the producer of a register's value, but for convenience a ptr - // to the producing instruction will be placed in the head node of - // the dependency links. - int8_t total_dest_regs = new_inst->numDestRegs(); - - for (int dest_reg_idx = 0; - dest_reg_idx < total_dest_regs; - dest_reg_idx++) - { - PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); - - // Instructions that use the misc regs will have a reg number - // higher than the normal physical registers. In this case these - // registers are not renamed, and there is no need to track - // dependencies as these instructions must be executed at commit. - if (dest_reg >= numPhysRegs) { - continue; - } - - if (!dependGraph.empty(dest_reg)) { - dependGraph.dump(); - panic("Dependency graph %i not empty!", dest_reg); - } - - dependGraph.setInst(dest_reg, new_inst); - - // Mark the scoreboard to say it's not yet ready. - regScoreboard[dest_reg] = false; - } -} - -template <class Impl> -void -InstructionQueue<Impl>::addIfReady(DynInstPtr &inst) -{ - // If the instruction now has all of its source registers - // available, then add it to the list of ready instructions. - if (inst->readyToIssue()) { - - //Add the instruction to the proper ready list. - if (inst->isMemRef()) { - - DPRINTF(IQ, "Checking if memory instruction can issue.\n"); - - // Message to the mem dependence unit that this instruction has - // its registers ready. - memDepUnit[inst->threadNumber].regsReady(inst); - - return; - } - - OpClass op_class = inst->opClass(); - - DPRINTF(IQ, "Instruction is ready to issue, putting it onto " - "the ready list, PC %#x opclass:%i [sn:%lli].\n", - inst->readPC(), op_class, inst->seqNum); - - readyInsts[op_class].push(inst); - - // Will need to reorder the list if either a queue is not on the list, - // or it has an older instruction than last time. - if (!queueOnList[op_class]) { - addToOrderList(op_class); - } else if (readyInsts[op_class].top()->seqNum < - (*readyIt[op_class]).oldestInst) { - listOrder.erase(readyIt[op_class]); - addToOrderList(op_class); - } - } -} - -template <class Impl> -int -InstructionQueue<Impl>::countInsts() -{ - //ksewell:This works but definitely could use a cleaner write - //with a more intuitive way of counting. Right now it's - //just brute force .... - -#if 0 - int total_insts = 0; - - for (int i = 0; i < numThreads; ++i) { - ListIt count_it = instList[i].begin(); - - while (count_it != instList[i].end()) { - if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { - if (!(*count_it)->isIssued()) { - ++total_insts; - } else if ((*count_it)->isMemRef() && - !(*count_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++total_insts; - } - } - - ++count_it; - } - } - - return total_insts; -#else - return numEntries - freeEntries; -#endif -} - -template <class Impl> -void -InstructionQueue<Impl>::dumpLists() -{ - for (int i = 0; i < Num_OpClasses; ++i) { - cprintf("Ready list %i size: %i\n", i, readyInsts[i].size()); - - cprintf("\n"); - } - - cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); - - NonSpecMapIt non_spec_it = nonSpecInsts.begin(); - NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); - - cprintf("Non speculative list: "); - - while (non_spec_it != non_spec_end_it) { - cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), - (*non_spec_it).second->seqNum); - ++non_spec_it; - } - - cprintf("\n"); - - ListOrderIt list_order_it = listOrder.begin(); - ListOrderIt list_order_end_it = listOrder.end(); - int i = 1; - - cprintf("List order: "); - - while (list_order_it != list_order_end_it) { - cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, - (*list_order_it).oldestInst); - - ++list_order_it; - ++i; - } - - cprintf("\n"); -} - - -template <class Impl> -void -InstructionQueue<Impl>::dumpInsts() -{ - for (int i = 0; i < numThreads; ++i) { - int num = 0; - int valid_num = 0; - ListIt inst_list_it = instList[i].begin(); - - while (inst_list_it != instList[i].end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed - // still count towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } - } -} diff --git a/cpu/o3/mem_dep_unit.cc b/cpu/o3/mem_dep_unit.cc deleted file mode 100644 index ccdd1a515..000000000 --- a/cpu/o3/mem_dep_unit.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/store_set.hh" -#include "cpu/o3/mem_dep_unit_impl.hh" - -// Force instantation of memory dependency unit using store sets and -// AlphaSimpleImpl. -template class MemDepUnit<StoreSet, AlphaSimpleImpl>; - -template <> -int -MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_count = 0; -template <> -int -MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_insert = 0; -template <> -int -MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_erase = 0; diff --git a/cpu/o3/mem_dep_unit.hh b/cpu/o3/mem_dep_unit.hh deleted file mode 100644 index acbe08ec2..000000000 --- a/cpu/o3/mem_dep_unit.hh +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_MEM_DEP_UNIT_HH__ -#define __CPU_O3_MEM_DEP_UNIT_HH__ - -#include <list> -#include <set> - -#include "base/hashmap.hh" -#include "base/refcnt.hh" -#include "base/statistics.hh" -#include "cpu/inst_seq.hh" - -struct SNHash { - size_t operator() (const InstSeqNum &seq_num) const { - unsigned a = (unsigned)seq_num; - unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; - - return hash; - } -}; - -template <class Impl> -class InstructionQueue; - -/** - * Memory dependency unit class. This holds the memory dependence predictor. - * As memory operations are issued to the IQ, they are also issued to this - * unit, which then looks up the prediction as to what they are dependent - * upon. This unit must be checked prior to a memory operation being able - * to issue. Although this is templated, it's somewhat hard to make a generic - * memory dependence unit. This one is mostly for store sets; it will be - * quite limited in what other memory dependence predictions it can also - * utilize. Thus this class should be most likely be rewritten for other - * dependence prediction schemes. - */ -template <class MemDepPred, class Impl> -class MemDepUnit { - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - /** Empty constructor. Must call init() prior to using in this case. */ - MemDepUnit() {} - - /** Constructs a MemDepUnit with given parameters. */ - MemDepUnit(Params *params); - - /** Frees up any memory allocated. */ - ~MemDepUnit(); - - /** Returns the name of the memory dependence unit. */ - std::string name() const; - - /** Initializes the unit with parameters and a thread id. */ - void init(Params *params, int tid); - - /** Registers statistics. */ - void regStats(); - - void switchOut(); - - void takeOverFrom(); - - /** Sets the pointer to the IQ. */ - void setIQ(InstructionQueue<Impl> *iq_ptr); - - /** Inserts a memory instruction. */ - void insert(DynInstPtr &inst); - - /** Inserts a non-speculative memory instruction. */ - void insertNonSpec(DynInstPtr &inst); - - /** Inserts a barrier instruction. */ - void insertBarrier(DynInstPtr &barr_inst); - - /** Indicate that an instruction has its registers ready. */ - void regsReady(DynInstPtr &inst); - - /** Indicate that a non-speculative instruction is ready. */ - void nonSpecInstReady(DynInstPtr &inst); - - /** Reschedules an instruction to be re-executed. */ - void reschedule(DynInstPtr &inst); - - /** Replays all instructions that have been rescheduled by moving them to - * the ready list. - */ - void replay(DynInstPtr &inst); - - /** Completes a memory instruction. */ - void completed(DynInstPtr &inst); - - /** Completes a barrier instruction. */ - void completeBarrier(DynInstPtr &inst); - - /** Wakes any dependents of a memory instruction. */ - void wakeDependents(DynInstPtr &inst); - - /** Squashes all instructions up until a given sequence number for a - * specific thread. - */ - void squash(const InstSeqNum &squashed_num, unsigned tid); - - /** Indicates an ordering violation between a store and a younger load. */ - void violation(DynInstPtr &store_inst, DynInstPtr &violating_load); - - /** Issues the given instruction */ - void issue(DynInstPtr &inst); - - /** Debugging function to dump the lists of instructions. */ - void dumpLists(); - - private: - typedef typename std::list<DynInstPtr>::iterator ListIt; - - class MemDepEntry; - - typedef RefCountingPtr<MemDepEntry> MemDepEntryPtr; - - /** Memory dependence entries that track memory operations, marking - * when the instruction is ready to execute and what instructions depend - * upon it. - */ - class MemDepEntry : public RefCounted { - public: - /** Constructs a memory dependence entry. */ - MemDepEntry(DynInstPtr &new_inst) - : inst(new_inst), regsReady(false), memDepReady(false), - completed(false), squashed(false) - { - ++memdep_count; - - DPRINTF(MemDepUnit, "Memory dependency entry created. " - "memdep_count=%i\n", memdep_count); - } - - /** Frees any pointers. */ - ~MemDepEntry() - { - for (int i = 0; i < dependInsts.size(); ++i) { - dependInsts[i] = NULL; - } - - --memdep_count; - - DPRINTF(MemDepUnit, "Memory dependency entry deleted. " - "memdep_count=%i\n", memdep_count); - } - - /** Returns the name of the memory dependence entry. */ - std::string name() const { return "memdepentry"; } - - /** The instruction being tracked. */ - DynInstPtr inst; - - /** The iterator to the instruction's location inside the list. */ - ListIt listIt; - - /** A vector of any dependent instructions. */ - std::vector<MemDepEntryPtr> dependInsts; - - /** If the registers are ready or not. */ - bool regsReady; - /** If all memory dependencies have been satisfied. */ - bool memDepReady; - /** If the instruction is completed. */ - bool completed; - /** If the instruction is squashed. */ - bool squashed; - - /** For debugging. */ - static int memdep_count; - static int memdep_insert; - static int memdep_erase; - }; - - /** Finds the memory dependence entry in the hash map. */ - inline MemDepEntryPtr &findInHash(const DynInstPtr &inst); - - /** Moves an entry to the ready list. */ - inline void moveToReady(MemDepEntryPtr &ready_inst_entry); - - typedef m5::hash_map<InstSeqNum, MemDepEntryPtr, SNHash> MemDepHash; - - typedef typename MemDepHash::iterator MemDepHashIt; - - /** A hash map of all memory dependence entries. */ - MemDepHash memDepHash; - - /** A list of all instructions in the memory dependence unit. */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - /** A list of all instructions that are going to be replayed. */ - std::list<DynInstPtr> instsToReplay; - - /** The memory dependence predictor. It is accessed upon new - * instructions being added to the IQ, and responds by telling - * this unit what instruction the newly added instruction is dependent - * upon. - */ - MemDepPred depPred; - - bool loadBarrier; - InstSeqNum loadBarrierSN; - bool storeBarrier; - InstSeqNum storeBarrierSN; - - /** Pointer to the IQ. */ - InstructionQueue<Impl> *iqPtr; - - /** The thread id of this memory dependence unit. */ - int id; - - /** Stat for number of inserted loads. */ - Stats::Scalar<> insertedLoads; - /** Stat for number of inserted stores. */ - Stats::Scalar<> insertedStores; - /** Stat for number of conflicting loads that had to wait for a store. */ - Stats::Scalar<> conflictingLoads; - /** Stat for number of conflicting stores that had to wait for a store. */ - Stats::Scalar<> conflictingStores; -}; - -#endif // __CPU_O3_MEM_DEP_UNIT_HH__ diff --git a/cpu/o3/mem_dep_unit_impl.hh b/cpu/o3/mem_dep_unit_impl.hh deleted file mode 100644 index 8b195baab..000000000 --- a/cpu/o3/mem_dep_unit_impl.hh +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <map> - -#include "cpu/o3/inst_queue.hh" -#include "cpu/o3/mem_dep_unit.hh" - -template <class MemDepPred, class Impl> -MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params) - : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), - loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) -{ - DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n"); -} - -template <class MemDepPred, class Impl> -MemDepUnit<MemDepPred, Impl>::~MemDepUnit() -{ - for (int tid=0; tid < Impl::MaxThreads; tid++) { - - ListIt inst_list_it = instList[tid].begin(); - - MemDepHashIt hash_it; - - while (!instList[tid].empty()) { - hash_it = memDepHash.find((*inst_list_it)->seqNum); - - assert(hash_it != memDepHash.end()); - - memDepHash.erase(hash_it); - - instList[tid].erase(inst_list_it++); - } - } - - assert(MemDepEntry::memdep_count == 0); -} - -template <class MemDepPred, class Impl> -std::string -MemDepUnit<MemDepPred, Impl>::name() const -{ - return "memdepunit"; -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid) -{ - DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); - - id = tid; - - depPred.init(params->SSITSize, params->LFSTSize); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::regStats() -{ - insertedLoads - .name(name() + ".memDep.insertedLoads") - .desc("Number of loads inserted to the mem dependence unit."); - - insertedStores - .name(name() + ".memDep.insertedStores") - .desc("Number of stores inserted to the mem dependence unit."); - - conflictingLoads - .name(name() + ".memDep.conflictingLoads") - .desc("Number of conflicting loads."); - - conflictingStores - .name(name() + ".memDep.conflictingStores") - .desc("Number of conflicting stores."); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::switchOut() -{ - for (int i = 0; i < Impl::MaxThreads; ++i) { - instList[i].clear(); - } - instsToReplay.clear(); - memDepHash.clear(); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::takeOverFrom() -{ - loadBarrier = storeBarrier = false; - loadBarrierSN = storeBarrierSN = 0; - depPred.clear(); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::setIQ(InstructionQueue<Impl> *iq_ptr) -{ - iqPtr = iq_ptr; -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::insert(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - MemDepEntryPtr inst_entry = new MemDepEntry(inst); - - // Add the MemDepEntry to the hash. - memDepHash.insert( - std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry)); - MemDepEntry::memdep_insert++; - - instList[tid].push_back(inst); - - inst_entry->listIt = --(instList[tid].end()); - - // Check any barriers and the dependence predictor for any - // producing stores. - InstSeqNum producing_store; - if (inst->isLoad() && loadBarrier) { - producing_store = loadBarrierSN; - } else if (inst->isStore() && storeBarrier) { - producing_store = storeBarrierSN; - } else { - producing_store = depPred.checkInst(inst->readPC()); - } - - MemDepEntryPtr store_entry = NULL; - - // If there is a producing store, try to find the entry. - if (producing_store != 0) { - MemDepHashIt hash_it = memDepHash.find(producing_store); - - if (hash_it != memDepHash.end()) { - store_entry = (*hash_it).second; - } - } - - // If no store entry, then instruction can issue as soon as the registers - // are ready. - if (!store_entry) { - DPRINTF(MemDepUnit, "No dependency for inst PC " - "%#x [sn:%lli].\n", inst->readPC(), inst->seqNum); - - inst_entry->memDepReady = true; - - if (inst->readyToIssue()) { - inst_entry->regsReady = true; - - moveToReady(inst_entry); - } - } else { - // Otherwise make the instruction dependent on the store/barrier. - DPRINTF(MemDepUnit, "Adding to dependency list; " - "inst PC %#x is dependent on [sn:%lli].\n", - inst->readPC(), producing_store); - - if (inst->readyToIssue()) { - inst_entry->regsReady = true; - } - - // Add this instruction to the list of dependents. - store_entry->dependInsts.push_back(inst_entry); - - if (inst->isLoad()) { - ++conflictingLoads; - } else { - ++conflictingStores; - } - } - - if (inst->isStore()) { - DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber); - - ++insertedStores; - } else if (inst->isLoad()) { - ++insertedLoads; - } else { - panic("Unknown type! (most likely a barrier)."); - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::insertNonSpec(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - MemDepEntryPtr inst_entry = new MemDepEntry(inst); - - // Insert the MemDepEntry into the hash. - memDepHash.insert( - std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry)); - MemDepEntry::memdep_insert++; - - // Add the instruction to the list. - instList[tid].push_back(inst); - - inst_entry->listIt = --(instList[tid].end()); - - // Might want to turn this part into an inline function or something. - // It's shared between both insert functions. - if (inst->isStore()) { - DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber); - - ++insertedStores; - } else if (inst->isLoad()) { - ++insertedLoads; - } else { - panic("Unknown type! (most likely a barrier)."); - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::insertBarrier(DynInstPtr &barr_inst) -{ - InstSeqNum barr_sn = barr_inst->seqNum; - if (barr_inst->isMemBarrier()) { - loadBarrier = true; - loadBarrierSN = barr_sn; - storeBarrier = true; - storeBarrierSN = barr_sn; - DPRINTF(MemDepUnit, "Inserted a memory barrier\n"); - } else if (barr_inst->isWriteBarrier()) { - storeBarrier = true; - storeBarrierSN = barr_sn; - DPRINTF(MemDepUnit, "Inserted a write barrier\n"); - } - - unsigned tid = barr_inst->threadNumber; - - MemDepEntryPtr inst_entry = new MemDepEntry(barr_inst); - - // Add the MemDepEntry to the hash. - memDepHash.insert( - std::pair<InstSeqNum, MemDepEntryPtr>(barr_sn, inst_entry)); - MemDepEntry::memdep_insert++; - - // Add the instruction to the instruction list. - instList[tid].push_back(barr_inst); - - inst_entry->listIt = --(instList[tid].end()); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Marking registers as ready for " - "instruction PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - MemDepEntryPtr inst_entry = findInHash(inst); - - inst_entry->regsReady = true; - - if (inst_entry->memDepReady) { - DPRINTF(MemDepUnit, "Instruction has its memory " - "dependencies resolved, adding it to the ready list.\n"); - - moveToReady(inst_entry); - } else { - DPRINTF(MemDepUnit, "Instruction still waiting on " - "memory dependency.\n"); - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Marking non speculative " - "instruction PC %#x as ready [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - MemDepEntryPtr inst_entry = findInHash(inst); - - moveToReady(inst_entry); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::reschedule(DynInstPtr &inst) -{ - instsToReplay.push_back(inst); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::replay(DynInstPtr &inst) -{ - DynInstPtr temp_inst; - bool found_inst = false; - - while (!instsToReplay.empty()) { - temp_inst = instsToReplay.front(); - - MemDepEntryPtr inst_entry = findInHash(temp_inst); - - DPRINTF(MemDepUnit, "Replaying mem instruction PC %#x " - "[sn:%lli].\n", - temp_inst->readPC(), temp_inst->seqNum); - - moveToReady(inst_entry); - - if (temp_inst == inst) { - found_inst = true; - } - - instsToReplay.pop_front(); - } - - assert(found_inst); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::completed(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Completed mem instruction PC %#x " - "[sn:%lli].\n", - inst->readPC(), inst->seqNum); - - unsigned tid = inst->threadNumber; - - // Remove the instruction from the hash and the list. - MemDepHashIt hash_it = memDepHash.find(inst->seqNum); - - assert(hash_it != memDepHash.end()); - - instList[tid].erase((*hash_it).second->listIt); - - (*hash_it).second = NULL; - - memDepHash.erase(hash_it); - MemDepEntry::memdep_erase++; -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::completeBarrier(DynInstPtr &inst) -{ - wakeDependents(inst); - completed(inst); - - InstSeqNum barr_sn = inst->seqNum; - - if (inst->isMemBarrier()) { - assert(loadBarrier && storeBarrier); - if (loadBarrierSN == barr_sn) - loadBarrier = false; - if (storeBarrierSN == barr_sn) - storeBarrier = false; - } else if (inst->isWriteBarrier()) { - assert(storeBarrier); - if (storeBarrierSN == barr_sn) - storeBarrier = false; - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::wakeDependents(DynInstPtr &inst) -{ - // Only stores and barriers have dependents. - if (!inst->isStore() && !inst->isMemBarrier() && !inst->isWriteBarrier()) { - return; - } - - MemDepEntryPtr inst_entry = findInHash(inst); - - for (int i = 0; i < inst_entry->dependInsts.size(); ++i ) { - MemDepEntryPtr woken_inst = inst_entry->dependInsts[i]; - - if (!woken_inst->inst) { - // Potentially removed mem dep entries could be on this list - continue; - } - - DPRINTF(MemDepUnit, "Waking up a dependent inst, " - "[sn:%lli].\n", - woken_inst->inst->seqNum); - - if (woken_inst->regsReady && !woken_inst->squashed) { - moveToReady(woken_inst); - } else { - woken_inst->memDepReady = true; - } - } - - inst_entry->dependInsts.clear(); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::squash(const InstSeqNum &squashed_num, - unsigned tid) -{ - if (!instsToReplay.empty()) { - ListIt replay_it = instsToReplay.begin(); - while (replay_it != instsToReplay.end()) { - if ((*replay_it)->threadNumber == tid && - (*replay_it)->seqNum > squashed_num) { - instsToReplay.erase(replay_it++); - } else { - ++replay_it; - } - } - } - - ListIt squash_it = instList[tid].end(); - --squash_it; - - MemDepHashIt hash_it; - - while (!instList[tid].empty() && - (*squash_it)->seqNum > squashed_num) { - - DPRINTF(MemDepUnit, "Squashing inst [sn:%lli]\n", - (*squash_it)->seqNum); - - hash_it = memDepHash.find((*squash_it)->seqNum); - - assert(hash_it != memDepHash.end()); - - (*hash_it).second->squashed = true; - - (*hash_it).second = NULL; - - memDepHash.erase(hash_it); - MemDepEntry::memdep_erase++; - - instList[tid].erase(squash_it--); - } - - // Tell the dependency predictor to squash as well. - depPred.squash(squashed_num, tid); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::violation(DynInstPtr &store_inst, - DynInstPtr &violating_load) -{ - DPRINTF(MemDepUnit, "Passing violating PCs to store sets," - " load: %#x, store: %#x\n", violating_load->readPC(), - store_inst->readPC()); - // Tell the memory dependence unit of the violation. - depPred.violation(violating_load->readPC(), store_inst->readPC()); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Issuing instruction PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - depPred.issued(inst->readPC(), inst->seqNum, inst->isStore()); -} - -template <class MemDepPred, class Impl> -inline typename MemDepUnit<MemDepPred,Impl>::MemDepEntryPtr & -MemDepUnit<MemDepPred, Impl>::findInHash(const DynInstPtr &inst) -{ - MemDepHashIt hash_it = memDepHash.find(inst->seqNum); - - assert(hash_it != memDepHash.end()); - - return (*hash_it).second; -} - -template <class MemDepPred, class Impl> -inline void -MemDepUnit<MemDepPred, Impl>::moveToReady(MemDepEntryPtr &woken_inst_entry) -{ - DPRINTF(MemDepUnit, "Adding instruction [sn:%lli] " - "to the ready list.\n", woken_inst_entry->inst->seqNum); - - assert(!woken_inst_entry->squashed); - - iqPtr->addReadyMemInst(woken_inst_entry->inst); -} - - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::dumpLists() -{ - for (unsigned tid=0; tid < Impl::MaxThreads; tid++) { - cprintf("Instruction list %i size: %i\n", - tid, instList[tid].size()); - - ListIt inst_list_it = instList[tid].begin(); - int num = 0; - - while (inst_list_it != instList[tid].end()) { - cprintf("Instruction:%i\nPC:%#x\n[sn:%i]\n[tid:%i]\nIssued:%i\n" - "Squashed:%i\n\n", - num, (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - inst_list_it++; - ++num; - } - } - - cprintf("Memory dependence hash size: %i\n", memDepHash.size()); - - cprintf("Memory dependence entries: %i\n", MemDepEntry::memdep_count); -} diff --git a/cpu/o3/ras.cc b/cpu/o3/ras.cc deleted file mode 100644 index 0b3ea4918..000000000 --- a/cpu/o3/ras.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/ras.hh" - -void -ReturnAddrStack::init(unsigned _numEntries) -{ - numEntries = _numEntries; - usedEntries = 0; - tos = 0; - - addrStack.resize(numEntries); - - for (int i = 0; i < numEntries; ++i) - addrStack[i] = 0; -} - -void -ReturnAddrStack::reset() -{ - usedEntries = 0; - tos = 0; - for (int i = 0; i < numEntries; ++i) - addrStack[i] = 0; -} - -void -ReturnAddrStack::push(const Addr &return_addr) -{ - incrTos(); - - addrStack[tos] = return_addr; - - if (usedEntries != numEntries) { - ++usedEntries; - } -} - -void -ReturnAddrStack::pop() -{ - if (usedEntries > 0) { - --usedEntries; - } - - decrTos(); -} - -void -ReturnAddrStack::restore(unsigned top_entry_idx, - const Addr &restored_target) -{ - tos = top_entry_idx; - - addrStack[tos] = restored_target; -} diff --git a/cpu/o3/ras.hh b/cpu/o3/ras.hh deleted file mode 100644 index 27e7c2df4..000000000 --- a/cpu/o3/ras.hh +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_RAS_HH__ -#define __CPU_O3_RAS_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include <vector> - -/** Return address stack class, implements a simple RAS. */ -class ReturnAddrStack -{ - public: - /** Creates a return address stack, but init() must be called prior to - * use. - */ - ReturnAddrStack() {} - - /** Initializes RAS with a specified number of entries. - * @param numEntries Number of entries in the RAS. - */ - void init(unsigned numEntries); - - void reset(); - - /** Returns the top address on the RAS. */ - Addr top() - { return addrStack[tos]; } - - /** Returns the index of the top of the RAS. */ - unsigned topIdx() - { return tos; } - - /** Pushes an address onto the RAS. */ - void push(const Addr &return_addr); - - /** Pops the top address from the RAS. */ - void pop(); - - /** Changes index to the top of the RAS, and replaces the top address with - * a new target. - * @param top_entry_idx The index of the RAS that will now be the top. - * @param restored_target The new target address of the new top of the RAS. - */ - void restore(unsigned top_entry_idx, const Addr &restored_target); - - private: - /** Increments the top of stack index. */ - inline void incrTos() - { if (++tos == numEntries) tos = 0; } - - /** Decrements the top of stack index. */ - inline void decrTos() - { tos = (tos == 0 ? numEntries - 1 : tos - 1); } - - /** The RAS itself. */ - std::vector<Addr> addrStack; - - /** The number of entries in the RAS. */ - unsigned numEntries; - - /** The number of used entries in the RAS. */ - unsigned usedEntries; - - /** The top of stack index. */ - unsigned tos; -}; - -#endif // __CPU_O3_RAS_HH__ diff --git a/cpu/o3/regfile.hh b/cpu/o3/regfile.hh deleted file mode 100644 index ed1238d36..000000000 --- a/cpu/o3/regfile.hh +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_REGFILE_HH__ -#define __CPU_O3_REGFILE_HH__ - -#include "arch/isa_traits.hh" -#include "arch/faults.hh" -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/o3/comm.hh" - -#if FULL_SYSTEM -#include "kern/kernel_stats.hh" - -#endif - -#include <vector> - -/** - * Simple physical register file class. - * This really only depends on the ISA, and not the Impl. Things that are - * in the ifdef FULL_SYSTEM are pretty dependent on the ISA, and probably - * should go in the AlphaFullCPU. - */ -template <class Impl> -class PhysRegFile -{ - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - // Note that most of the definitions of the IntReg, FloatReg, etc. exist - // within the Impl/ISA class and not within this PhysRegFile class. - - // Will make these registers public for now, but they probably should - // be private eventually with some accessor functions. - public: - typedef typename Impl::FullCPU FullCPU; - - /** - * Constructs a physical register file with the specified amount of - * integer and floating point registers. - */ - PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs); - - //Everything below should be pretty well identical to the normal - //register file that exists within AlphaISA class. - //The duplication is unfortunate but it's better than having - //different ways to access certain registers. - - //Add these in later when everything else is in place -// void serialize(std::ostream &os); -// void unserialize(Checkpoint *cp, const std::string §ion); - - /** Reads an integer register. */ - uint64_t readIntReg(PhysRegIndex reg_idx) - { - assert(reg_idx < numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to int register %i, has data " - "%i\n", int(reg_idx), intRegFile[reg_idx]); - return intRegFile[reg_idx]; - } - - /** Reads a floating point register (single precision). */ - float readFloatRegSingle(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as single, has " - "data %8.8f\n", int(reg_idx), (float)floatRegFile[reg_idx].d); - - return (float)floatRegFile[reg_idx].d; - } - - /** Reads a floating point register (double precision). */ - double readFloatRegDouble(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as double, has " - " data %8.8f\n", int(reg_idx), floatRegFile[reg_idx].d); - - return floatRegFile[reg_idx].d; - } - - /** Reads a floating point register as an integer. */ - uint64_t readFloatRegInt(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as int, has data " - "%lli\n", int(reg_idx), floatRegFile[reg_idx].q); - - return floatRegFile[reg_idx].q; - } - - /** Sets an integer register to the given value. */ - void setIntReg(PhysRegIndex reg_idx, uint64_t val) - { - assert(reg_idx < numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - intRegFile[reg_idx] = val; - } - - /** Sets a single precision floating point register to the given value. */ - void setFloatRegSingle(PhysRegIndex reg_idx, float val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].d = (double)val; - } - - /** Sets a double precision floating point register to the given value. */ - void setFloatRegDouble(PhysRegIndex reg_idx, double val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].d = val; - } - - /** Sets a floating point register to the given integer value. */ - void setFloatRegInt(PhysRegIndex reg_idx, uint64_t val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].q = val; - } - - //Consider leaving this stuff and below in some implementation specific - //file as opposed to the general register file. Or have a derived class. - MiscReg readMiscReg(int misc_reg, unsigned thread_id) - { - return miscRegs[thread_id].readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, - unsigned thread_id) - { - return miscRegs[thread_id].readRegWithEffect(misc_reg, fault, - cpu->xcBase(thread_id)); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned thread_id) - { - return miscRegs[thread_id].setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned thread_id) - { - return miscRegs[thread_id].setRegWithEffect(misc_reg, val, - cpu->xcBase(thread_id)); - } - -#if FULL_SYSTEM - int readIntrFlag() { return intrflag; } - /** Sets an interrupt flag. */ - void setIntrFlag(int val) { intrflag = val; } -#endif - - public: - /** (signed) integer register file. */ - std::vector<IntReg> intRegFile; - - /** Floating point register file. */ - std::vector<FloatReg> floatRegFile; - - /** Miscellaneous register file. */ - MiscRegFile miscRegs[Impl::MaxThreads]; - -#if FULL_SYSTEM - private: - int intrflag; // interrupt flag -#endif - - private: - /** CPU pointer. */ - FullCPU *cpu; - - public: - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } - - /** Number of physical integer registers. */ - unsigned numPhysicalIntRegs; - /** Number of physical floating point registers. */ - unsigned numPhysicalFloatRegs; -}; - -template <class Impl> -PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs) - : numPhysicalIntRegs(_numPhysicalIntRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs) -{ - intRegFile.resize(numPhysicalIntRegs); - floatRegFile.resize(numPhysicalFloatRegs); - - //memset(intRegFile, 0, sizeof(*intRegFile)); - //memset(floatRegFile, 0, sizeof(*floatRegFile)); -} - -#endif diff --git a/cpu/o3/rename.cc b/cpu/o3/rename.cc deleted file mode 100644 index 4dc3bf6b2..000000000 --- a/cpu/o3/rename.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/rename_impl.hh" - -template class DefaultRename<AlphaSimpleImpl>; diff --git a/cpu/o3/rename.hh b/cpu/o3/rename.hh deleted file mode 100644 index 3f1a27bb5..000000000 --- a/cpu/o3/rename.hh +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_RENAME_HH__ -#define __CPU_O3_RENAME_HH__ - -#include <list> - -#include "base/statistics.hh" -#include "base/timebuf.hh" - -/** - * DefaultRename handles both single threaded and SMT rename. Its - * width is specified by the parameters; each cycle it tries to rename - * that many instructions. It holds onto the rename history of all - * instructions with destination registers, storing the - * arch. register, the new physical register, and the old physical - * register, to allow for undoing of mappings if squashing happens, or - * freeing up registers upon commit. Rename handles blocking if the - * ROB, IQ, or LSQ is going to be full. Rename also handles barriers, - * and does so by stalling on the instruction until the ROB is empty - * and there are no instructions in flight to the ROB. - */ -template<class Impl> -class DefaultRename -{ - public: - // Typedefs from the Impl. - typedef typename Impl::CPUPol CPUPol; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::Params Params; - - // Typedefs from the CPUPol - typedef typename CPUPol::DecodeStruct DecodeStruct; - typedef typename CPUPol::RenameStruct RenameStruct; - typedef typename CPUPol::TimeStruct TimeStruct; - typedef typename CPUPol::FreeList FreeList; - typedef typename CPUPol::RenameMap RenameMap; - // These are used only for initialization. - typedef typename CPUPol::IEW IEW; - typedef typename CPUPol::Commit Commit; - - // Typedefs from the ISA. - typedef TheISA::RegIndex RegIndex; - - // A list is used to queue the instructions. Barrier insts must - // be added to the front of the list, which is the only reason for - // using a list instead of a queue. (Most other stages use a - // queue) - typedef std::list<DynInstPtr> InstQueue; - - public: - /** Overall rename status. Used to determine if the CPU can - * deschedule itself due to a lack of activity. - */ - enum RenameStatus { - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - StartSquash, - Squashing, - Blocked, - Unblocking, - SerializeStall - }; - - private: - /** Rename status. */ - RenameStatus _status; - - /** Per-thread status. */ - ThreadStatus renameStatus[Impl::MaxThreads]; - - public: - /** DefaultRename constructor. */ - DefaultRename(Params *params); - - /** Returns the name of rename. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the main backwards communication time buffer pointer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Sets pointer to time buffer used to communicate to the next stage. */ - void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); - - /** Sets pointer to time buffer coming from decode. */ - void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr); - - /** Sets pointer to IEW stage. Used only for initialization. */ - void setIEWStage(IEW *iew_stage) - { iew_ptr = iew_stage; } - - /** Sets pointer to commit stage. Used only for initialization. */ - void setCommitStage(Commit *commit_stage) - { commit_ptr = commit_stage; } - - private: - /** Pointer to IEW stage. Used only for initialization. */ - IEW *iew_ptr; - - /** Pointer to commit stage. Used only for initialization. */ - Commit *commit_ptr; - - public: - /** Initializes variables for the stage. */ - void initStage(); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to rename maps (per-thread structures). */ - void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]); - - /** Sets pointer to the free list. */ - void setFreeList(FreeList *fl_ptr); - - /** Sets pointer to the scoreboard. */ - void setScoreboard(Scoreboard *_scoreboard); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - /** Squashes all instructions in a thread. */ - void squash(unsigned tid); - - /** Ticks rename, which processes all input signals and attempts to rename - * as many instructions as possible. - */ - void tick(); - - /** Debugging function used to dump history buffer of renamings. */ - void dumpHistory(); - - private: - /** Determines what to do based on rename's current status. - * @param status_change rename() sets this variable if there was a status - * change (ie switching from blocking to unblocking). - * @param tid Thread id to rename instructions from. - */ - void rename(bool &status_change, unsigned tid); - - /** Renames instructions for the given thread. Also handles serializing - * instructions. - */ - void renameInsts(unsigned tid); - - /** Inserts unused instructions from a given thread into the skid buffer, - * to be renamed once rename unblocks. - */ - void skidInsert(unsigned tid); - - /** Separates instructions from decode into individual lists of instructions - * sorted by thread. - */ - void sortInsts(); - - /** Returns if all of the skid buffers are empty. */ - bool skidsEmpty(); - - /** Updates overall rename status based on all of the threads' statuses. */ - void updateStatus(); - - /** Switches rename to blocking, and signals back that rename has become - * blocked. - * @return Returns true if there is a status change. - */ - bool block(unsigned tid); - - /** Switches rename to unblocking if the skid buffer is empty, and signals - * back that rename has unblocked. - * @return Returns true if there is a status change. - */ - bool unblock(unsigned tid); - - /** Executes actual squash, removing squashed instructions. */ - void doSquash(unsigned tid); - - /** Removes a committed instruction's rename history. */ - void removeFromHistory(InstSeqNum inst_seq_num, unsigned tid); - - /** Renames the source registers of an instruction. */ - inline void renameSrcRegs(DynInstPtr &inst, unsigned tid); - - /** Renames the destination registers of an instruction. */ - inline void renameDestRegs(DynInstPtr &inst, unsigned tid); - - /** Calculates the number of free ROB entries for a specific thread. */ - inline int calcFreeROBEntries(unsigned tid); - - /** Calculates the number of free IQ entries for a specific thread. */ - inline int calcFreeIQEntries(unsigned tid); - - /** Calculates the number of free LSQ entries for a specific thread. */ - inline int calcFreeLSQEntries(unsigned tid); - - /** Returns the number of valid instructions coming from decode. */ - unsigned validInsts(); - - /** Reads signals telling rename to block/unblock. */ - void readStallSignals(unsigned tid); - - /** Checks if any stages are telling rename to block. */ - bool checkStall(unsigned tid); - - void readFreeEntries(unsigned tid); - - bool checkSignalsAndUpdate(unsigned tid); - - /** Either serializes on the next instruction available in the InstQueue, - * or records that it must serialize on the next instruction to enter - * rename. - * @param inst_list The list of younger, unprocessed instructions for the - * thread that has the serializeAfter instruction. - * @param tid The thread id. - */ - void serializeAfter(InstQueue &inst_list, unsigned tid); - - /** Holds the information for each destination register rename. It holds - * the instruction's sequence number, the arch register, the old physical - * register for that arch. register, and the new physical register. - */ - struct RenameHistory { - RenameHistory(InstSeqNum _instSeqNum, RegIndex _archReg, - PhysRegIndex _newPhysReg, PhysRegIndex _prevPhysReg) - : instSeqNum(_instSeqNum), archReg(_archReg), - newPhysReg(_newPhysReg), prevPhysReg(_prevPhysReg) - { - } - - /** The sequence number of the instruction that renamed. */ - InstSeqNum instSeqNum; - /** The architectural register index that was renamed. */ - RegIndex archReg; - /** The new physical register that the arch. register is renamed to. */ - PhysRegIndex newPhysReg; - /** The old physical register that the arch. register was renamed to. */ - PhysRegIndex prevPhysReg; - }; - - /** A per-thread list of all destination register renames, used to either - * undo rename mappings or free old physical registers. - */ - std::list<RenameHistory> historyBuffer[Impl::MaxThreads]; - - /** Pointer to CPU. */ - FullCPU *cpu; - - /** Pointer to main time buffer used for backwards communication. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to get IEW's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromIEW; - - /** Wire to get commit's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Wire to write infromation heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toDecode; - - /** Rename instruction queue. */ - TimeBuffer<RenameStruct> *renameQueue; - - /** Wire to write any information heading to IEW. */ - typename TimeBuffer<RenameStruct>::wire toIEW; - - /** Decode instruction queue interface. */ - TimeBuffer<DecodeStruct> *decodeQueue; - - /** Wire to get decode's output from decode queue. */ - typename TimeBuffer<DecodeStruct>::wire fromDecode; - - /** Queue of all instructions coming from decode this cycle. */ - InstQueue insts[Impl::MaxThreads]; - - /** Skid buffer between rename and decode. */ - InstQueue skidBuffer[Impl::MaxThreads]; - - /** Rename map interface. */ - RenameMap *renameMap[Impl::MaxThreads]; - - /** Free list interface. */ - FreeList *freeList; - - /** Pointer to the list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Pointer to the scoreboard. */ - Scoreboard *scoreboard; - - /** Count of instructions in progress that have been sent off to the IQ - * and ROB, but are not yet included in their occupancy counts. - */ - int instsInProgress[Impl::MaxThreads]; - - /** Variable that tracks if decode has written to the time buffer this - * cycle. Used to tell CPU if there is activity this cycle. - */ - bool wroteToTimeBuffer; - - /** Structures whose free entries impact the amount of instructions that - * can be renamed. - */ - struct FreeEntries { - unsigned iqEntries; - unsigned lsqEntries; - unsigned robEntries; - }; - - /** Per-thread tracking of the number of free entries of back-end - * structures. - */ - FreeEntries freeEntries[Impl::MaxThreads]; - - /** Records if the ROB is empty. In SMT mode the ROB may be dynamically - * partitioned between threads, so the ROB must tell rename when it is - * empty. - */ - bool emptyROB[Impl::MaxThreads]; - - /** Source of possible stalls. */ - struct Stalls { - bool iew; - bool commit; - }; - - /** Tracks which stages are telling decode to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** The serialize instruction that rename has stalled on. */ - DynInstPtr serializeInst[Impl::MaxThreads]; - - /** Records if rename needs to serialize on the next instruction for any - * thread. - */ - bool serializeOnNextInst[Impl::MaxThreads]; - - /** Delay between iew and rename, in ticks. */ - int iewToRenameDelay; - - /** Delay between decode and rename, in ticks. */ - int decodeToRenameDelay; - - /** Delay between commit and rename, in ticks. */ - unsigned commitToRenameDelay; - - /** Rename width, in instructions. */ - unsigned renameWidth; - - /** Commit width, in instructions. Used so rename knows how many - * instructions might have freed registers in the previous cycle. - */ - unsigned commitWidth; - - /** The index of the instruction in the time buffer to IEW that rename is - * currently using. - */ - unsigned toIEWIndex; - - /** Whether or not rename needs to block this cycle. */ - bool blockThisCycle; - - /** The number of threads active in rename. */ - unsigned numThreads; - - /** The maximum skid buffer size. */ - unsigned skidBufferMax; - - /** Enum to record the source of a structure full stall. Can come from - * either ROB, IQ, LSQ, and it is priortized in that order. - */ - enum FullSource { - ROB, - IQ, - LSQ, - NONE - }; - - /** Function used to increment the stat that corresponds to the source of - * the stall. - */ - inline void incrFullStat(const FullSource &source); - - /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> renameSquashCycles; - /** Stat for total number of cycles spent idle. */ - Stats::Scalar<> renameIdleCycles; - /** Stat for total number of cycles spent blocking. */ - Stats::Scalar<> renameBlockCycles; - /** Stat for total number of cycles spent stalling for a serializing inst. */ - Stats::Scalar<> renameSerializeStallCycles; - /** Stat for total number of cycles spent running normally. */ - Stats::Scalar<> renameRunCycles; - /** Stat for total number of cycles spent unblocking. */ - Stats::Scalar<> renameUnblockCycles; - /** Stat for total number of renamed instructions. */ - Stats::Scalar<> renameRenamedInsts; - /** Stat for total number of squashed instructions that rename discards. */ - Stats::Scalar<> renameSquashedInsts; - /** Stat for total number of times that the ROB starts a stall in rename. */ - Stats::Scalar<> renameROBFullEvents; - /** Stat for total number of times that the IQ starts a stall in rename. */ - Stats::Scalar<> renameIQFullEvents; - /** Stat for total number of times that the LSQ starts a stall in rename. */ - Stats::Scalar<> renameLSQFullEvents; - /** Stat for total number of times that rename runs out of free registers - * to use to rename. */ - Stats::Scalar<> renameFullRegistersEvents; - /** Stat for total number of renamed destination registers. */ - Stats::Scalar<> renameRenamedOperands; - /** Stat for total number of source register rename lookups. */ - Stats::Scalar<> renameRenameLookups; - /** Stat for total number of committed renaming mappings. */ - Stats::Scalar<> renameCommittedMaps; - /** Stat for total number of mappings that were undone due to a squash. */ - Stats::Scalar<> renameUndoneMaps; - Stats::Scalar<> renamedSerializing; - Stats::Scalar<> renamedTempSerializing; - Stats::Scalar<> renameSkidInsts; -}; - -#endif // __CPU_O3_RENAME_HH__ diff --git a/cpu/o3/rename_impl.hh b/cpu/o3/rename_impl.hh deleted file mode 100644 index b4f1077d1..000000000 --- a/cpu/o3/rename_impl.hh +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> - -#include "config/full_system.hh" -#include "cpu/o3/rename.hh" - -using namespace std; - -template <class Impl> -DefaultRename<Impl>::DefaultRename(Params *params) - : iewToRenameDelay(params->iewToRenameDelay), - decodeToRenameDelay(params->decodeToRenameDelay), - commitToRenameDelay(params->commitToRenameDelay), - renameWidth(params->renameWidth), - commitWidth(params->commitWidth), - numThreads(params->numberOfThreads) -{ - _status = Inactive; - - for (int i=0; i< numThreads; i++) { - renameStatus[i] = Idle; - - freeEntries[i].iqEntries = 0; - freeEntries[i].lsqEntries = 0; - freeEntries[i].robEntries = 0; - - stalls[i].iew = false; - stalls[i].commit = false; - serializeInst[i] = NULL; - - instsInProgress[i] = 0; - - emptyROB[i] = true; - - serializeOnNextInst[i] = false; - } - - // @todo: Make into a parameter. - skidBufferMax = (2 * (iewToRenameDelay * params->decodeWidth)) + renameWidth; -} - -template <class Impl> -std::string -DefaultRename<Impl>::name() const -{ - return cpu->name() + ".rename"; -} - -template <class Impl> -void -DefaultRename<Impl>::regStats() -{ - renameSquashCycles - .name(name() + ".RENAME:SquashCycles") - .desc("Number of cycles rename is squashing") - .prereq(renameSquashCycles); - renameIdleCycles - .name(name() + ".RENAME:IdleCycles") - .desc("Number of cycles rename is idle") - .prereq(renameIdleCycles); - renameBlockCycles - .name(name() + ".RENAME:BlockCycles") - .desc("Number of cycles rename is blocking") - .prereq(renameBlockCycles); - renameSerializeStallCycles - .name(name() + ".RENAME:serializeStallCycles") - .desc("count of cycles rename stalled for serializing inst") - .flags(Stats::total); - renameRunCycles - .name(name() + ".RENAME:RunCycles") - .desc("Number of cycles rename is running") - .prereq(renameIdleCycles); - renameUnblockCycles - .name(name() + ".RENAME:UnblockCycles") - .desc("Number of cycles rename is unblocking") - .prereq(renameUnblockCycles); - renameRenamedInsts - .name(name() + ".RENAME:RenamedInsts") - .desc("Number of instructions processed by rename") - .prereq(renameRenamedInsts); - renameSquashedInsts - .name(name() + ".RENAME:SquashedInsts") - .desc("Number of squashed instructions processed by rename") - .prereq(renameSquashedInsts); - renameROBFullEvents - .name(name() + ".RENAME:ROBFullEvents") - .desc("Number of times rename has blocked due to ROB full") - .prereq(renameROBFullEvents); - renameIQFullEvents - .name(name() + ".RENAME:IQFullEvents") - .desc("Number of times rename has blocked due to IQ full") - .prereq(renameIQFullEvents); - renameLSQFullEvents - .name(name() + ".RENAME:LSQFullEvents") - .desc("Number of times rename has blocked due to LSQ full") - .prereq(renameLSQFullEvents); - renameFullRegistersEvents - .name(name() + ".RENAME:FullRegisterEvents") - .desc("Number of times there has been no free registers") - .prereq(renameFullRegistersEvents); - renameRenamedOperands - .name(name() + ".RENAME:RenamedOperands") - .desc("Number of destination operands rename has renamed") - .prereq(renameRenamedOperands); - renameRenameLookups - .name(name() + ".RENAME:RenameLookups") - .desc("Number of register rename lookups that rename has made") - .prereq(renameRenameLookups); - renameCommittedMaps - .name(name() + ".RENAME:CommittedMaps") - .desc("Number of HB maps that are committed") - .prereq(renameCommittedMaps); - renameUndoneMaps - .name(name() + ".RENAME:UndoneMaps") - .desc("Number of HB maps that are undone due to squashing") - .prereq(renameUndoneMaps); - renamedSerializing - .name(name() + ".RENAME:serializingInsts") - .desc("count of serializing insts renamed") - .flags(Stats::total) - ; - renamedTempSerializing - .name(name() + ".RENAME:tempSerializingInsts") - .desc("count of temporary serializing insts renamed") - .flags(Stats::total) - ; - renameSkidInsts - .name(name() + ".RENAME:skidInsts") - .desc("count of insts added to the skid buffer") - .flags(Stats::total) - ; -} - -template <class Impl> -void -DefaultRename<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Rename, "Setting CPU pointer.\n"); - cpu = cpu_ptr; -} - -template <class Impl> -void -DefaultRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(Rename, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to read information from time buffer, from IEW stage. - fromIEW = timeBuffer->getWire(-iewToRenameDelay); - - // Setup wire to read infromation from time buffer, from commit stage. - fromCommit = timeBuffer->getWire(-commitToRenameDelay); - - // Setup wire to write information to previous stages. - toDecode = timeBuffer->getWire(0); -} - -template <class Impl> -void -DefaultRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) -{ - DPRINTF(Rename, "Setting rename queue pointer.\n"); - renameQueue = rq_ptr; - - // Setup wire to write information to future stages. - toIEW = renameQueue->getWire(0); -} - -template <class Impl> -void -DefaultRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) -{ - DPRINTF(Rename, "Setting decode queue pointer.\n"); - decodeQueue = dq_ptr; - - // Setup wire to get information from decode. - fromDecode = decodeQueue->getWire(-decodeToRenameDelay); -} - -template <class Impl> -void -DefaultRename<Impl>::initStage() -{ - // Grab the number of free entries directly from the stages. - for (int tid=0; tid < numThreads; tid++) { - freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid); - freeEntries[tid].lsqEntries = iew_ptr->ldstQueue.numFreeEntries(tid); - freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid); - emptyROB[tid] = true; - } -} - -template<class Impl> -void -DefaultRename<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Rename, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - - -template <class Impl> -void -DefaultRename<Impl>::setRenameMap(RenameMap rm_ptr[]) -{ - DPRINTF(Rename, "Setting rename map pointers.\n"); - - for (int i=0; i<numThreads; i++) { - renameMap[i] = &rm_ptr[i]; - } -} - -template <class Impl> -void -DefaultRename<Impl>::setFreeList(FreeList *fl_ptr) -{ - DPRINTF(Rename, "Setting free list pointer.\n"); - freeList = fl_ptr; -} - -template<class Impl> -void -DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard) -{ - DPRINTF(Rename, "Setting scoreboard pointer.\n"); - scoreboard = _scoreboard; -} - -template <class Impl> -void -DefaultRename<Impl>::switchOut() -{ - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultRename<Impl>::doSwitchOut() -{ - for (int i = 0; i < numThreads; i++) { - typename list<RenameHistory>::iterator hb_it = historyBuffer[i].begin(); - - while (!historyBuffer[i].empty()) { - assert(hb_it != historyBuffer[i].end()); - - DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " - "number %i.\n", i, (*hb_it).instSeqNum); - - // Tell the rename map to set the architected register to the - // previous physical register that it was renamed to. - renameMap[i]->setEntry(hb_it->archReg, hb_it->prevPhysReg); - - // Put the renamed physical register back on the free list. - freeList->addReg(hb_it->newPhysReg); - - historyBuffer[i].erase(hb_it++); - } - insts[i].clear(); - skidBuffer[i].clear(); - } -} - -template <class Impl> -void -DefaultRename<Impl>::takeOverFrom() -{ - _status = Inactive; - initStage(); - - // Reset all state prior to taking over from the other CPU. - for (int i=0; i< numThreads; i++) { - renameStatus[i] = Idle; - - stalls[i].iew = false; - stalls[i].commit = false; - serializeInst[i] = NULL; - - instsInProgress[i] = 0; - - emptyROB[i] = true; - - serializeOnNextInst[i] = false; - } -} - -template <class Impl> -void -DefaultRename<Impl>::squash(unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Squashing instructions.\n",tid); - - // Clear the stall signal if rename was blocked or unblocking before. - // If it still needs to block, the blocking should happen the next - // cycle and there should be space to hold everything due to the squash. - if (renameStatus[tid] == Blocked || - renameStatus[tid] == Unblocking || - renameStatus[tid] == SerializeStall) { -#if 0 - // In syscall emulation, we can have both a block and a squash due - // to a syscall in the same cycle. This would cause both signals to - // be high. This shouldn't happen in full system. - if (toDecode->renameBlock[tid]) { - toDecode->renameBlock[tid] = 0; - } else { - toDecode->renameUnblock[tid] = 1; - } -#else - toDecode->renameUnblock[tid] = 1; -#endif - serializeInst[tid] = NULL; - } - - // Set the status to Squashing. - renameStatus[tid] = Squashing; - - // Squash any instructions from decode. - unsigned squashCount = 0; - - for (int i=0; i<fromDecode->size; i++) { - if (fromDecode->insts[i]->threadNumber == tid) { - fromDecode->insts[i]->squashed = true; - wroteToTimeBuffer = true; - squashCount++; - } - } - - insts[tid].clear(); - - // Clear the skid buffer in case it has any data in it. - skidBuffer[tid].clear(); - - doSquash(tid); -} - -template <class Impl> -void -DefaultRename<Impl>::tick() -{ - wroteToTimeBuffer = false; - - blockThisCycle = false; - - bool status_change = false; - - toIEWIndex = 0; - - sortInsts(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - // Check stall and squash signals. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - DPRINTF(Rename, "Processing [tid:%i]\n", tid); - - status_change = checkSignalsAndUpdate(tid) || status_change; - - rename(status_change, tid); - } - - if (status_change) { - updateStatus(); - } - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); - } - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - // If we committed this cycle then doneSeqNum will be > 0 - if (fromCommit->commitInfo[tid].doneSeqNum != 0 && - !fromCommit->commitInfo[tid].squash && - renameStatus[tid] != Squashing) { - - removeFromHistory(fromCommit->commitInfo[tid].doneSeqNum, - tid); - } - } - - // @todo: make into updateProgress function - for (int tid=0; tid < numThreads; tid++) { - instsInProgress[tid] -= fromIEW->iewInfo[tid].dispatched; - - assert(instsInProgress[tid] >=0); - } - -} - -template<class Impl> -void -DefaultRename<Impl>::rename(bool &status_change, unsigned tid) -{ - // If status is Running or idle, - // call renameInsts() - // If status is Unblocking, - // buffer any instructions coming from decode - // continue trying to empty skid buffer - // check if stall conditions have passed - - if (renameStatus[tid] == Blocked) { - ++renameBlockCycles; - } else if (renameStatus[tid] == Squashing) { - ++renameSquashCycles; - } else if (renameStatus[tid] == SerializeStall) { - ++renameSerializeStallCycles; - } - - if (renameStatus[tid] == Running || - renameStatus[tid] == Idle) { - DPRINTF(Rename, "[tid:%u]: Not blocked, so attempting to run " - "stage.\n", tid); - - renameInsts(tid); - } else if (renameStatus[tid] == Unblocking) { - renameInsts(tid); - - if (validInsts()) { - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - } - - // If we switched over to blocking, then there's a potential for - // an overall status change. - status_change = unblock(tid) || status_change || blockThisCycle; - } -} - -template <class Impl> -void -DefaultRename<Impl>::renameInsts(unsigned tid) -{ - // Instructions can be either in the skid buffer or the queue of - // instructions coming from decode, depending on the status. - int insts_available = renameStatus[tid] == Unblocking ? - skidBuffer[tid].size() : insts[tid].size(); - - // Check the decode queue to see if instructions are available. - // If there are no available instructions to rename, then do nothing. - if (insts_available == 0) { - DPRINTF(Rename, "[tid:%u]: Nothing to do, breaking out early.\n", - tid); - // Should I change status to idle? - ++renameIdleCycles; - return; - } else if (renameStatus[tid] == Unblocking) { - ++renameUnblockCycles; - } else if (renameStatus[tid] == Running) { - ++renameRunCycles; - } - - DynInstPtr inst; - - // Will have to do a different calculation for the number of free - // entries. - int free_rob_entries = calcFreeROBEntries(tid); - int free_iq_entries = calcFreeIQEntries(tid); - int free_lsq_entries = calcFreeLSQEntries(tid); - int min_free_entries = free_rob_entries; - - FullSource source = ROB; - - if (free_iq_entries < min_free_entries) { - min_free_entries = free_iq_entries; - source = IQ; - } - - if (free_lsq_entries < min_free_entries) { - min_free_entries = free_lsq_entries; - source = LSQ; - } - - // Check if there's any space left. - if (min_free_entries <= 0) { - DPRINTF(Rename, "[tid:%u]: Blocking due to no free ROB/IQ/LSQ " - "entries.\n" - "ROB has %i free entries.\n" - "IQ has %i free entries.\n" - "LSQ has %i free entries.\n", - tid, - free_rob_entries, - free_iq_entries, - free_lsq_entries); - - blockThisCycle = true; - - block(tid); - - incrFullStat(source); - - return; - } else if (min_free_entries < insts_available) { - DPRINTF(Rename, "[tid:%u]: Will have to block this cycle." - "%i insts available, but only %i insts can be " - "renamed due to ROB/IQ/LSQ limits.\n", - tid, insts_available, min_free_entries); - - insts_available = min_free_entries; - - blockThisCycle = true; - - incrFullStat(source); - } - - InstQueue &insts_to_rename = renameStatus[tid] == Unblocking ? - skidBuffer[tid] : insts[tid]; - - DPRINTF(Rename, "[tid:%u]: %i available instructions to " - "send iew.\n", tid, insts_available); - - DPRINTF(Rename, "[tid:%u]: %i insts pipelining from Rename | %i insts " - "dispatched to IQ last cycle.\n", - tid, instsInProgress[tid], fromIEW->iewInfo[tid].dispatched); - - // Handle serializing the next instruction if necessary. - if (serializeOnNextInst[tid]) { - if (emptyROB[tid] && instsInProgress[tid] == 0) { - // ROB already empty; no need to serialize. - serializeOnNextInst[tid] = false; - } else if (!insts_to_rename.empty()) { - insts_to_rename.front()->setSerializeBefore(); - } - } - - int renamed_insts = 0; - - while (insts_available > 0 && toIEWIndex < renameWidth) { - DPRINTF(Rename, "[tid:%u]: Sending instructions to IEW.\n", tid); - - assert(!insts_to_rename.empty()); - - inst = insts_to_rename.front(); - - insts_to_rename.pop_front(); - - if (renameStatus[tid] == Unblocking) { - DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%#x from rename " - "skidBuffer\n", - tid, inst->seqNum, inst->readPC()); - } - - if (inst->isSquashed()) { - DPRINTF(Rename, "[tid:%u]: instruction %i with PC %#x is " - "squashed, skipping.\n", - tid, inst->seqNum, inst->threadNumber,inst->readPC()); - - ++renameSquashedInsts; - - // Decrement how many instructions are available. - --insts_available; - - continue; - } - - DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with " - "PC %#x.\n", - tid, inst->seqNum, inst->readPC()); - - // Handle serializeAfter/serializeBefore instructions. - // serializeAfter marks the next instruction as serializeBefore. - // serializeBefore makes the instruction wait in rename until the ROB - // is empty. - - // In this model, IPR accesses are serialize before - // instructions, and store conditionals are serialize after - // instructions. This is mainly due to lack of support for - // out-of-order operations of either of those classes of - // instructions. - if ((inst->isIprAccess() || inst->isSerializeBefore()) && - !inst->isSerializeHandled()) { - DPRINTF(Rename, "Serialize before instruction encountered.\n"); - - if (!inst->isTempSerializeBefore()) { - renamedSerializing++; - inst->setSerializeHandled(); - } else { - renamedTempSerializing++; - } - - // Change status over to SerializeStall so that other stages know - // what this is blocked on. - renameStatus[tid] = SerializeStall; - - serializeInst[tid] = inst; - - blockThisCycle = true; - - break; - } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) && - !inst->isSerializeHandled()) { - DPRINTF(Rename, "Serialize after instruction encountered.\n"); - - renamedSerializing++; - - inst->setSerializeHandled(); - - serializeAfter(insts_to_rename, tid); - } - - // Check here to make sure there are enough destination registers - // to rename to. Otherwise block. - if (renameMap[tid]->numFreeEntries() < inst->numDestRegs()) { - DPRINTF(Rename, "Blocking due to lack of free " - "physical registers to rename to.\n"); - blockThisCycle = true; - - ++renameFullRegistersEvents; - - break; - } - - renameSrcRegs(inst, inst->threadNumber); - - renameDestRegs(inst, inst->threadNumber); - - ++renamed_insts; - - // Put instruction in rename queue. - toIEW->insts[toIEWIndex] = inst; - ++(toIEW->size); - - // Increment which instruction we're on. - ++toIEWIndex; - - // Decrement how many instructions are available. - --insts_available; - } - - instsInProgress[tid] += renamed_insts; - renameRenamedInsts += renamed_insts; - - // If we wrote to the time buffer, record this. - if (toIEWIndex) { - wroteToTimeBuffer = true; - } - - // Check if there's any instructions left that haven't yet been renamed. - // If so then block. - if (insts_available) { - blockThisCycle = true; - } - - if (blockThisCycle) { - block(tid); - toDecode->renameUnblock[tid] = false; - } -} - -template<class Impl> -void -DefaultRename<Impl>::skidInsert(unsigned tid) -{ - DynInstPtr inst = NULL; - - while (!insts[tid].empty()) { - inst = insts[tid].front(); - - insts[tid].pop_front(); - - assert(tid == inst->threadNumber); - - DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC:%#x into Rename " - "skidBuffer\n", tid, inst->seqNum, inst->readPC()); - - ++renameSkidInsts; - - skidBuffer[tid].push_back(inst); - } - - if (skidBuffer[tid].size() > skidBufferMax) - panic("Skidbuffer Exceeded Max Size"); -} - -template <class Impl> -void -DefaultRename<Impl>::sortInsts() -{ - int insts_from_decode = fromDecode->size; -#ifdef DEBUG - for (int i=0; i < numThreads; i++) - assert(insts[i].empty()); -#endif - for (int i = 0; i < insts_from_decode; ++i) { - DynInstPtr inst = fromDecode->insts[i]; - insts[inst->threadNumber].push_back(inst); - } -} - -template<class Impl> -bool -DefaultRename<Impl>::skidsEmpty() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - -template<class Impl> -void -DefaultRename<Impl>::updateStatus() -{ - bool any_unblocking = false; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (renameStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // Rename will have activity if it's unblocking. - if (any_unblocking) { - if (_status == Inactive) { - _status = Active; - - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(FullCPU::RenameIdx); - } - } else { - // If it's not unblocking, then rename will not have any internal - // activity. Switch it to inactive. - if (_status == Active) { - _status = Inactive; - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::RenameIdx); - } - } -} - -template <class Impl> -bool -DefaultRename<Impl>::block(unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Blocking.\n", tid); - - // Add the current inputs onto the skid buffer, so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - - // Only signal backwards to block if the previous stages do not think - // rename is already blocked. - if (renameStatus[tid] != Blocked) { - if (renameStatus[tid] != Unblocking) { - toDecode->renameBlock[tid] = true; - toDecode->renameUnblock[tid] = false; - wroteToTimeBuffer = true; - } - - // Rename can not go from SerializeStall to Blocked, otherwise - // it would not know to complete the serialize stall. - if (renameStatus[tid] != SerializeStall) { - // Set status to Blocked. - renameStatus[tid] = Blocked; - return true; - } - } - - return false; -} - -template <class Impl> -bool -DefaultRename<Impl>::unblock(unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Trying to unblock.\n", tid); - - // Rename is done unblocking if the skid buffer is empty. - if (skidBuffer[tid].empty() && renameStatus[tid] != SerializeStall) { - - DPRINTF(Rename, "[tid:%u]: Done unblocking.\n", tid); - - toDecode->renameUnblock[tid] = true; - wroteToTimeBuffer = true; - - renameStatus[tid] = Running; - return true; - } - - return false; -} - -template <class Impl> -void -DefaultRename<Impl>::doSquash(unsigned tid) -{ - typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].begin(); - - InstSeqNum squashed_seq_num = fromCommit->commitInfo[tid].doneSeqNum; - - // After a syscall squashes everything, the history buffer may be empty - // but the ROB may still be squashing instructions. - if (historyBuffer[tid].empty()) { - return; - } - - // Go through the most recent instructions, undoing the mappings - // they did and freeing up the registers. - while (!historyBuffer[tid].empty() && - (*hb_it).instSeqNum > squashed_seq_num) { - assert(hb_it != historyBuffer[tid].end()); - - DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " - "number %i.\n", tid, (*hb_it).instSeqNum); - - // Tell the rename map to set the architected register to the - // previous physical register that it was renamed to. - renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg); - - // Put the renamed physical register back on the free list. - freeList->addReg(hb_it->newPhysReg); - - historyBuffer[tid].erase(hb_it++); - - ++renameUndoneMaps; - } -} - -template<class Impl> -void -DefaultRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num, unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Removing a committed instruction from the " - "history buffer %u (size=%i), until [sn:%lli].\n", - tid, tid, historyBuffer[tid].size(), inst_seq_num); - - typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].end(); - - --hb_it; - - if (historyBuffer[tid].empty()) { - DPRINTF(Rename, "[tid:%u]: History buffer is empty.\n", tid); - return; - } else if (hb_it->instSeqNum > inst_seq_num) { - DPRINTF(Rename, "[tid:%u]: Old sequence number encountered. Ensure " - "that a syscall happened recently.\n", tid); - return; - } - - // Commit all the renames up until (and including) the committed sequence - // number. Some or even all of the committed instructions may not have - // rename histories if they did not have destination registers that were - // renamed. - while (!historyBuffer[tid].empty() && - hb_it != historyBuffer[tid].end() && - (*hb_it).instSeqNum <= inst_seq_num) { - - DPRINTF(Rename, "[tid:%u]: Freeing up older rename of reg %i, " - "[sn:%lli].\n", - tid, (*hb_it).prevPhysReg, (*hb_it).instSeqNum); - - freeList->addReg((*hb_it).prevPhysReg); - ++renameCommittedMaps; - - historyBuffer[tid].erase(hb_it--); - } -} - -template <class Impl> -inline void -DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid) -{ - assert(renameMap[tid] != 0); - - unsigned num_src_regs = inst->numSrcRegs(); - - // Get the architectual register numbers from the source and - // destination operands, and redirect them to the right register. - // Will need to mark dependencies though. - for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { - RegIndex src_reg = inst->srcRegIdx(src_idx); - - // Look up the source registers to get the phys. register they've - // been renamed to, and set the sources to those registers. - PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg); - - DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got " - "physical reg %i.\n", tid, (int)src_reg, - (int)renamed_reg); - - inst->renameSrcReg(src_idx, renamed_reg); - - // See if the register is ready or not. - if (scoreboard->getReg(renamed_reg) == true) { - DPRINTF(Rename, "[tid:%u]: Register is ready.\n", tid); - - inst->markSrcRegReady(src_idx); - } - - ++renameRenameLookups; - } -} - -template <class Impl> -inline void -DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid) -{ - typename RenameMap::RenameInfo rename_result; - - unsigned num_dest_regs = inst->numDestRegs(); - - // Rename the destination registers. - for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { - RegIndex dest_reg = inst->destRegIdx(dest_idx); - - // Get the physical register that the destination will be - // renamed to. - rename_result = renameMap[tid]->rename(dest_reg); - - //Mark Scoreboard entry as not ready - scoreboard->unsetReg(rename_result.first); - - DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " - "reg %i.\n", tid, (int)dest_reg, - (int)rename_result.first); - - // Record the rename information so that a history can be kept. - RenameHistory hb_entry(inst->seqNum, dest_reg, - rename_result.first, - rename_result.second); - - historyBuffer[tid].push_front(hb_entry); - - DPRINTF(Rename, "[tid:%u]: Adding instruction to history buffer, " - "[sn:%lli].\n",tid, - (*historyBuffer[tid].begin()).instSeqNum); - - // Tell the instruction to rename the appropriate destination - // register (dest_idx) to the new physical register - // (rename_result.first), and record the previous physical - // register that the same logical register was renamed to - // (rename_result.second). - inst->renameDestReg(dest_idx, - rename_result.first, - rename_result.second); - - ++renameRenamedOperands; - } -} - -template <class Impl> -inline int -DefaultRename<Impl>::calcFreeROBEntries(unsigned tid) -{ - int num_free = freeEntries[tid].robEntries - - (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); - - //DPRINTF(Rename,"[tid:%i]: %i rob free\n",tid,num_free); - - return num_free; -} - -template <class Impl> -inline int -DefaultRename<Impl>::calcFreeIQEntries(unsigned tid) -{ - int num_free = freeEntries[tid].iqEntries - - (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); - - //DPRINTF(Rename,"[tid:%i]: %i iq free\n",tid,num_free); - - return num_free; -} - -template <class Impl> -inline int -DefaultRename<Impl>::calcFreeLSQEntries(unsigned tid) -{ - int num_free = freeEntries[tid].lsqEntries - - (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToLSQ); - - //DPRINTF(Rename,"[tid:%i]: %i lsq free\n",tid,num_free); - - return num_free; -} - -template <class Impl> -unsigned -DefaultRename<Impl>::validInsts() -{ - unsigned inst_count = 0; - - for (int i=0; i<fromDecode->size; i++) { - if (!fromDecode->insts[i]->squashed) - inst_count++; - } - - return inst_count; -} - -template <class Impl> -void -DefaultRename<Impl>::readStallSignals(unsigned tid) -{ - if (fromIEW->iewBlock[tid]) { - stalls[tid].iew = true; - } - - if (fromIEW->iewUnblock[tid]) { - assert(stalls[tid].iew); - stalls[tid].iew = false; - } - - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - stalls[tid].commit = false; - } -} - -template <class Impl> -bool -DefaultRename<Impl>::checkStall(unsigned tid) -{ - bool ret_val = false; - - if (stalls[tid].iew) { - DPRINTF(Rename,"[tid:%i]: Stall from IEW stage detected.\n", tid); - ret_val = true; - } else if (stalls[tid].commit) { - DPRINTF(Rename,"[tid:%i]: Stall from Commit stage detected.\n", tid); - ret_val = true; - } else if (calcFreeROBEntries(tid) <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: ROB has 0 free entries.\n", tid); - ret_val = true; - } else if (calcFreeIQEntries(tid) <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: IQ has 0 free entries.\n", tid); - ret_val = true; - } else if (calcFreeLSQEntries(tid) <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: LSQ has 0 free entries.\n", tid); - ret_val = true; - } else if (renameMap[tid]->numFreeEntries() <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: RenameMap has 0 free entries.\n", tid); - ret_val = true; - } else if (renameStatus[tid] == SerializeStall && - (!emptyROB[tid] || instsInProgress[tid])) { - DPRINTF(Rename,"[tid:%i]: Stall: Serialize stall and ROB is not " - "empty.\n", - tid); - ret_val = true; - } - - return ret_val; -} - -template <class Impl> -void -DefaultRename<Impl>::readFreeEntries(unsigned tid) -{ - bool updated = false; - if (fromIEW->iewInfo[tid].usedIQ) { - freeEntries[tid].iqEntries = - fromIEW->iewInfo[tid].freeIQEntries; - updated = true; - } - - if (fromIEW->iewInfo[tid].usedLSQ) { - freeEntries[tid].lsqEntries = - fromIEW->iewInfo[tid].freeLSQEntries; - updated = true; - } - - if (fromCommit->commitInfo[tid].usedROB) { - freeEntries[tid].robEntries = - fromCommit->commitInfo[tid].freeROBEntries; - emptyROB[tid] = fromCommit->commitInfo[tid].emptyROB; - updated = true; - } - - DPRINTF(Rename, "[tid:%i]: Free IQ: %i, Free ROB: %i, Free LSQ: %i\n", - tid, - freeEntries[tid].iqEntries, - freeEntries[tid].robEntries, - freeEntries[tid].lsqEntries); - - DPRINTF(Rename, "[tid:%i]: %i instructions not yet in ROB\n", - tid, instsInProgress[tid]); -} - -template <class Impl> -bool -DefaultRename<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Check if there's a squash signal, squash if there is - // Check stall signals, block if necessary. - // If status was blocked - // check if stall conditions have passed - // if so then go to unblocking - // If status was Squashing - // check if squashing is not high. Switch to running this cycle. - // If status was serialize stall - // check if ROB is empty and no insts are in flight to the ROB - - readFreeEntries(tid); - readStallSignals(tid); - - if (fromCommit->commitInfo[tid].squash) { - DPRINTF(Rename, "[tid:%u]: Squashing instructions due to squash from " - "commit.\n", tid); - - squash(tid); - - return true; - } - - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(Rename, "[tid:%u]: ROB is still squashing.\n", tid); - - renameStatus[tid] = Squashing; - - return true; - } - - if (checkStall(tid)) { - return block(tid); - } - - if (renameStatus[tid] == Blocked) { - DPRINTF(Rename, "[tid:%u]: Done blocking, switching to unblocking.\n", - tid); - - renameStatus[tid] = Unblocking; - - unblock(tid); - - return true; - } - - if (renameStatus[tid] == Squashing) { - // Switch status to running if rename isn't being told to block or - // squash this cycle. - DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", - tid); - - renameStatus[tid] = Running; - - return false; - } - - if (renameStatus[tid] == SerializeStall) { - // Stall ends once the ROB is free. - DPRINTF(Rename, "[tid:%u]: Done with serialize stall, switching to " - "unblocking.\n", tid); - - DynInstPtr serial_inst = serializeInst[tid]; - - renameStatus[tid] = Unblocking; - - unblock(tid); - - DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with " - "PC %#x.\n", - tid, serial_inst->seqNum, serial_inst->readPC()); - - // Put instruction into queue here. - serial_inst->clearSerializeBefore(); - - if (!skidBuffer[tid].empty()) { - skidBuffer[tid].push_front(serial_inst); - } else { - insts[tid].push_front(serial_inst); - } - - DPRINTF(Rename, "[tid:%u]: Instruction must be processed by rename." - " Adding to front of list.", tid); - - serializeInst[tid] = NULL; - - return true; - } - - // If we've reached this point, we have not gotten any signals that - // cause rename to change its status. Rename remains the same as before. - return false; -} - -template<class Impl> -void -DefaultRename<Impl>::serializeAfter(InstQueue &inst_list, - unsigned tid) -{ - if (inst_list.empty()) { - // Mark a bit to say that I must serialize on the next instruction. - serializeOnNextInst[tid] = true; - return; - } - - // Set the next instruction as serializing. - inst_list.front()->setSerializeBefore(); -} - -template <class Impl> -inline void -DefaultRename<Impl>::incrFullStat(const FullSource &source) -{ - switch (source) { - case ROB: - ++renameROBFullEvents; - break; - case IQ: - ++renameIQFullEvents; - break; - case LSQ: - ++renameLSQFullEvents; - break; - default: - panic("Rename full stall stat should be incremented for a reason!"); - break; - } -} - -template <class Impl> -void -DefaultRename<Impl>::dumpHistory() -{ - typename list<RenameHistory>::iterator buf_it; - - for (int i = 0; i < numThreads; i++) { - - buf_it = historyBuffer[i].begin(); - - while (buf_it != historyBuffer[i].end()) { - cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys " - "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg, - (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg); - - buf_it++; - } - } -} diff --git a/cpu/o3/rename_map.cc b/cpu/o3/rename_map.cc deleted file mode 100644 index fc59058a1..000000000 --- a/cpu/o3/rename_map.cc +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <vector> - -#include "cpu/o3/rename_map.hh" - -using namespace std; - -// @todo: Consider making inline bool functions that determine if the -// register is a logical int, logical fp, physical int, physical fp, -// etc. - -SimpleRenameMap::~SimpleRenameMap() -{ -} - -void -SimpleRenameMap::init(unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - PhysRegIndex &ireg_idx, - - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - PhysRegIndex &freg_idx, - - unsigned _numMiscRegs, - - RegIndex _intZeroReg, - RegIndex _floatZeroReg, - - int map_id, - bool bindRegs) -{ - id = map_id; - - numLogicalIntRegs = _numLogicalIntRegs; - - numLogicalFloatRegs = _numLogicalFloatRegs; - - numPhysicalIntRegs = _numPhysicalIntRegs; - - numPhysicalFloatRegs = _numPhysicalFloatRegs; - - numMiscRegs = _numMiscRegs; - - intZeroReg = _intZeroReg; - floatZeroReg = _floatZeroReg; - - DPRINTF(Rename, "Creating rename map %i. Phys: %i / %i, Float: " - "%i / %i.\n", id, numLogicalIntRegs, numPhysicalIntRegs, - numLogicalFloatRegs, numPhysicalFloatRegs); - - numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs; - - numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs; - - //Create the rename maps - intRenameMap.resize(numLogicalIntRegs); - floatRenameMap.resize(numLogicalRegs); - - if (bindRegs) { - DPRINTF(Rename, "Binding registers into rename map %i",id); - - // Initialize the entries in the integer rename map to point to the - // physical registers of the same index - for (RegIndex index = 0; index < numLogicalIntRegs; ++index) - { - intRenameMap[index].physical_reg = ireg_idx++; - } - - // Initialize the entries in the floating point rename map to point to - // the physical registers of the same index - // Although the index refers purely to architected registers, because - // the floating reg indices come after the integer reg indices, they - // may exceed the size of a normal RegIndex (short). - for (PhysRegIndex index = numLogicalIntRegs; - index < numLogicalRegs; ++index) - { - floatRenameMap[index].physical_reg = freg_idx++; - } - } else { - DPRINTF(Rename, "Binding registers into rename map %i",id); - - PhysRegIndex temp_ireg = ireg_idx; - - for (RegIndex index = 0; index < numLogicalIntRegs; ++index) - { - intRenameMap[index].physical_reg = temp_ireg++; - } - - PhysRegIndex temp_freg = freg_idx; - - for (PhysRegIndex index = numLogicalIntRegs; - index < numLogicalRegs; ++index) - { - floatRenameMap[index].physical_reg = temp_freg++; - } - } -} - -void -SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr) -{ - freeList = fl_ptr; -} - - -SimpleRenameMap::RenameInfo -SimpleRenameMap::rename(RegIndex arch_reg) -{ - PhysRegIndex renamed_reg; - PhysRegIndex prev_reg; - - if (arch_reg < numLogicalIntRegs) { - - // Record the current physical register that is renamed to the - // requested architected register. - prev_reg = intRenameMap[arch_reg].physical_reg; - - // If it's not referencing the zero register, then rename the - // register. - if (arch_reg != intZeroReg) { - renamed_reg = freeList->getIntReg(); - - intRenameMap[arch_reg].physical_reg = renamed_reg; - - assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs); - - } else { - // Otherwise return the zero register so nothing bad happens. - renamed_reg = intZeroReg; - } - } else if (arch_reg < numLogicalRegs) { - // Record the current physical register that is renamed to the - // requested architected register. - prev_reg = floatRenameMap[arch_reg].physical_reg; - - // If it's not referencing the zero register, then rename the - // register. - if (arch_reg != floatZeroReg) { - renamed_reg = freeList->getFloatReg(); - - floatRenameMap[arch_reg].physical_reg = renamed_reg; - - assert(renamed_reg < numPhysicalRegs && - renamed_reg >= numPhysicalIntRegs); - } else { - // Otherwise return the zero register so nothing bad happens. - renamed_reg = floatZeroReg; - } - } else { - // Subtract off the base offset for miscellaneous registers. - arch_reg = arch_reg - numLogicalRegs; - - // No renaming happens to the misc. registers. They are - // simply the registers that come after all the physical - // registers; thus take the base architected register and add - // the physical registers to it. - renamed_reg = arch_reg + numPhysicalRegs; - - // Set the previous register to the same register; mainly it must be - // known that the prev reg was outside the range of normal registers - // so the free list can avoid adding it. - prev_reg = renamed_reg; - - assert(renamed_reg < numPhysicalRegs + numMiscRegs); - } - - return RenameInfo(renamed_reg, prev_reg); -} - -PhysRegIndex -SimpleRenameMap::lookup(RegIndex arch_reg) -{ - if (arch_reg < numLogicalIntRegs) { - return intRenameMap[arch_reg].physical_reg; - } else if (arch_reg < numLogicalRegs) { - return floatRenameMap[arch_reg].physical_reg; - } else { - // Subtract off the misc registers offset. - arch_reg = arch_reg - numLogicalRegs; - - // Misc. regs don't rename, so simply add the base arch reg to - // the number of physical registers. - return numPhysicalRegs + arch_reg; - } -} - -void -SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg) -{ - // In this implementation the miscellaneous registers do not - // actually rename, so this function does not allow you to try to - // change their mappings. - if (arch_reg < numLogicalIntRegs) { - DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n", - (int)arch_reg, renamed_reg); - - intRenameMap[arch_reg].physical_reg = renamed_reg; - } else if (arch_reg < numLogicalIntRegs + numLogicalFloatRegs) { - DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n", - (int)arch_reg - numLogicalIntRegs, renamed_reg); - - floatRenameMap[arch_reg].physical_reg = renamed_reg; - } -} - -int -SimpleRenameMap::numFreeEntries() -{ - int free_int_regs = freeList->numFreeIntRegs(); - int free_float_regs = freeList->numFreeFloatRegs(); - - if (free_int_regs < free_float_regs) { - return free_int_regs; - } else { - return free_float_regs; - } -} diff --git a/cpu/o3/rename_map.hh b/cpu/o3/rename_map.hh deleted file mode 100644 index d7e49ae83..000000000 --- a/cpu/o3/rename_map.hh +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Todo: Create destructor. -// Have it so that there's a more meaningful name given to the variable -// that marks the beginning of the FP registers. - -#ifndef __CPU_O3_RENAME_MAP_HH__ -#define __CPU_O3_RENAME_MAP_HH__ - -#include <iostream> -#include <utility> -#include <vector> - -#include "cpu/o3/free_list.hh" -//For RegIndex -#include "arch/isa_traits.hh" - -class SimpleRenameMap -{ - protected: - typedef TheISA::RegIndex RegIndex; - public: - /** - * Pair of a logical register and a physical register. Tells the - * previous mapping of a logical register to a physical register. - * Used to roll back the rename map to a previous state. - */ - typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo; - - /** - * Pair of a physical register and a physical register. Used to - * return the physical register that a logical register has been - * renamed to, and the previous physical register that the same - * logical register was previously mapped to. - */ - typedef std::pair<PhysRegIndex, PhysRegIndex> RenameInfo; - - public: - //Constructor - SimpleRenameMap() {}; - - /** Destructor. */ - ~SimpleRenameMap(); - - void init(unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - PhysRegIndex &_int_reg_start, - - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - PhysRegIndex &_float_reg_start, - - unsigned _numMiscRegs, - - RegIndex _intZeroReg, - RegIndex _floatZeroReg, - - int id, - bool bindRegs); - - void setFreeList(SimpleFreeList *fl_ptr); - - //Tell rename map to get a free physical register for a given - //architected register. Not sure it should have a return value, - //but perhaps it should have some sort of fault in case there are - //no free registers. - RenameInfo rename(RegIndex arch_reg); - - PhysRegIndex lookup(RegIndex phys_reg); - - /** - * Marks the given register as ready, meaning that its value has been - * calculated and written to the register file. - * @param ready_reg The index of the physical register that is now ready. - */ - void setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg); - - int numFreeEntries(); - - private: - /** Rename Map ID */ - int id; - - /** Number of logical integer registers. */ - int numLogicalIntRegs; - - /** Number of physical integer registers. */ - int numPhysicalIntRegs; - - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; - - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; - - /** Number of miscellaneous registers. */ - int numMiscRegs; - - /** Number of logical integer + float registers. */ - int numLogicalRegs; - - /** Number of physical integer + float registers. */ - int numPhysicalRegs; - - /** The integer zero register. This implementation assumes it is always - * zero and never can be anything else. - */ - RegIndex intZeroReg; - - /** The floating point zero register. This implementation assumes it is - * always zero and never can be anything else. - */ - RegIndex floatZeroReg; - - class RenameEntry - { - public: - PhysRegIndex physical_reg; - bool valid; - - RenameEntry() - : physical_reg(0), valid(false) - { } - }; - - //Change this to private - private: - /** Integer rename map. */ - std::vector<RenameEntry> intRenameMap; - - /** Floating point rename map. */ - std::vector<RenameEntry> floatRenameMap; - - private: - /** Free list interface. */ - SimpleFreeList *freeList; -}; - -#endif //__CPU_O3_RENAME_MAP_HH__ diff --git a/cpu/o3/rob.cc b/cpu/o3/rob.cc deleted file mode 100644 index c10f782fd..000000000 --- a/cpu/o3/rob.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/rob_impl.hh" - -// Force instantiation of InstructionQueue. -template class ROB<AlphaSimpleImpl>; diff --git a/cpu/o3/rob.hh b/cpu/o3/rob.hh deleted file mode 100644 index e05eebe5a..000000000 --- a/cpu/o3/rob.hh +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ROB_HH__ -#define __CPU_O3_ROB_HH__ - -#include <string> -#include <utility> -#include <vector> - -/** - * ROB class. The ROB is largely what drives squashing. - */ -template <class Impl> -class ROB -{ - protected: - typedef TheISA::RegIndex RegIndex; - public: - //Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo; - typedef typename std::list<DynInstPtr>::iterator InstIt; - - /** Possible ROB statuses. */ - enum Status { - Running, - Idle, - ROBSquashing - }; - - /** SMT ROB Sharing Policy */ - enum ROBPolicy{ - Dynamic, - Partitioned, - Threshold - }; - - private: - /** Per-thread ROB status. */ - Status robStatus[Impl::MaxThreads]; - - /** ROB resource sharing policy for SMT mode. */ - ROBPolicy robPolicy; - - public: - /** ROB constructor. - * @param _numEntries Number of entries in ROB. - * @param _squashWidth Number of instructions that can be squashed in a - * single cycle. - * @param _smtROBPolicy ROB Partitioning Scheme for SMT. - * @param _smtROBThreshold Max Resources(by %) a thread can have in the ROB. - * @param _numThreads The number of active threads. - */ - ROB(unsigned _numEntries, unsigned _squashWidth, std::string smtROBPolicy, - unsigned _smtROBThreshold, unsigned _numThreads); - - std::string name() const; - - /** Function to set the CPU pointer, necessary due to which object the ROB - * is created within. - * @param cpu_ptr Pointer to the implementation specific full CPU object. - */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets pointer to the list of active threads. - * @param at_ptr Pointer to the list of active threads. - */ - void setActiveThreads(std::list<unsigned>* at_ptr); - - void switchOut(); - - void takeOverFrom(); - - /** Function to insert an instruction into the ROB. Note that whatever - * calls this function must ensure that there is enough space within the - * ROB for the new instruction. - * @param inst The instruction being inserted into the ROB. - */ - void insertInst(DynInstPtr &inst); - - /** Returns pointer to the head instruction within the ROB. There is - * no guarantee as to the return value if the ROB is empty. - * @retval Pointer to the DynInst that is at the head of the ROB. - */ -// DynInstPtr readHeadInst(); - - /** Returns a pointer to the head instruction of a specific thread within - * the ROB. - * @return Pointer to the DynInst that is at the head of the ROB. - */ - DynInstPtr readHeadInst(unsigned tid); - - /** Returns pointer to the tail instruction within the ROB. There is - * no guarantee as to the return value if the ROB is empty. - * @retval Pointer to the DynInst that is at the tail of the ROB. - */ -// DynInstPtr readTailInst(); - - /** Returns a pointer to the tail instruction of a specific thread within - * the ROB. - * @return Pointer to the DynInst that is at the tail of the ROB. - */ - DynInstPtr readTailInst(unsigned tid); - - /** Retires the head instruction, removing it from the ROB. */ -// void retireHead(); - - /** Retires the head instruction of a specific thread, removing it from the - * ROB. - */ - void retireHead(unsigned tid); - - /** Is the oldest instruction across all threads ready. */ -// bool isHeadReady(); - - /** Is the oldest instruction across a particular thread ready. */ - bool isHeadReady(unsigned tid); - - /** Is there any commitable head instruction across all threads ready. */ - bool canCommit(); - - /** Re-adjust ROB partitioning. */ - void resetEntries(); - - /** Number of entries needed For 'num_threads' amount of threads. */ - int entryAmount(int num_threads); - - /** Returns the number of total free entries in the ROB. */ - unsigned numFreeEntries(); - - /** Returns the number of free entries in a specific ROB paritition. */ - unsigned numFreeEntries(unsigned tid); - - /** Returns the maximum number of entries for a specific thread. */ - unsigned getMaxEntries(unsigned tid) - { return maxEntries[tid]; } - - /** Returns the number of entries being used by a specific thread. */ - unsigned getThreadEntries(unsigned tid) - { return threadEntries[tid]; } - - /** Returns if the ROB is full. */ - bool isFull() - { return numInstsInROB == numEntries; } - - /** Returns if a specific thread's partition is full. */ - bool isFull(unsigned tid) - { return threadEntries[tid] == numEntries; } - - /** Returns if the ROB is empty. */ - bool isEmpty() - { return numInstsInROB == 0; } - - /** Returns if a specific thread's partition is empty. */ - bool isEmpty(unsigned tid) - { return threadEntries[tid] == 0; } - - /** Executes the squash, marking squashed instructions. */ - void doSquash(unsigned tid); - - /** Squashes all instructions younger than the given sequence number for - * the specific thread. - */ - void squash(InstSeqNum squash_num, unsigned tid); - - /** Updates the head instruction with the new oldest instruction. */ - void updateHead(); - - /** Updates the tail instruction with the new youngest instruction. */ - void updateTail(); - - /** Reads the PC of the oldest head instruction. */ -// uint64_t readHeadPC(); - - /** Reads the PC of the head instruction of a specific thread. */ -// uint64_t readHeadPC(unsigned tid); - - /** Reads the next PC of the oldest head instruction. */ -// uint64_t readHeadNextPC(); - - /** Reads the next PC of the head instruction of a specific thread. */ -// uint64_t readHeadNextPC(unsigned tid); - - /** Reads the sequence number of the oldest head instruction. */ -// InstSeqNum readHeadSeqNum(); - - /** Reads the sequence number of the head instruction of a specific thread. - */ -// InstSeqNum readHeadSeqNum(unsigned tid); - - /** Reads the PC of the youngest tail instruction. */ -// uint64_t readTailPC(); - - /** Reads the PC of the tail instruction of a specific thread. */ -// uint64_t readTailPC(unsigned tid); - - /** Reads the sequence number of the youngest tail instruction. */ -// InstSeqNum readTailSeqNum(); - - /** Reads the sequence number of tail instruction of a specific thread. */ -// InstSeqNum readTailSeqNum(unsigned tid); - - /** Checks if the ROB is still in the process of squashing instructions. - * @retval Whether or not the ROB is done squashing. - */ - bool isDoneSquashing(unsigned tid) const - { return doneSquashing[tid]; } - - /** Checks if the ROB is still in the process of squashing instructions for - * any thread. - */ - bool isDoneSquashing(); - - /** This is more of a debugging function than anything. Use - * numInstsInROB to get the instructions in the ROB unless you are - * double checking that variable. - */ - int countInsts(); - - /** This is more of a debugging function than anything. Use - * threadEntries to get the instructions in the ROB unless you are - * double checking that variable. - */ - int countInsts(unsigned tid); - - private: - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Active Threads in CPU */ - std::list<unsigned>* activeThreads; - - /** Number of instructions in the ROB. */ - unsigned numEntries; - - /** Entries Per Thread */ - unsigned threadEntries[Impl::MaxThreads]; - - /** Max Insts a Thread Can Have in the ROB */ - unsigned maxEntries[Impl::MaxThreads]; - - /** ROB List of Instructions */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - /** Number of instructions that can be squashed in a single cycle. */ - unsigned squashWidth; - - public: - /** Iterator pointing to the instruction which is the last instruction - * in the ROB. This may at times be invalid (ie when the ROB is empty), - * however it should never be incorrect. - */ - InstIt tail; - - /** Iterator pointing to the instruction which is the first instruction in - * in the ROB*/ - InstIt head; - - private: - /** Iterator used for walking through the list of instructions when - * squashing. Used so that there is persistent state between cycles; - * when squashing, the instructions are marked as squashed but not - * immediately removed, meaning the tail iterator remains the same before - * and after a squash. - * This will always be set to cpu->instList.end() if it is invalid. - */ - InstIt squashIt[Impl::MaxThreads]; - - public: - /** Number of instructions in the ROB. */ - int numInstsInROB; - - DynInstPtr dummyInst; - - private: - /** The sequence number of the squashed instruction. */ - InstSeqNum squashedSeqNum; - - /** Is the ROB done squashing. */ - bool doneSquashing[Impl::MaxThreads]; - - /** Number of active threads. */ - unsigned numThreads; -}; - -#endif //__CPU_O3_ROB_HH__ diff --git a/cpu/o3/rob_impl.hh b/cpu/o3/rob_impl.hh deleted file mode 100644 index 25e0c80fd..000000000 --- a/cpu/o3/rob_impl.hh +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config/full_system.hh" -#include "cpu/o3/rob.hh" - -using namespace std; - -template <class Impl> -ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth, - string _smtROBPolicy, unsigned _smtROBThreshold, - unsigned _numThreads) - : numEntries(_numEntries), - squashWidth(_squashWidth), - numInstsInROB(0), - squashedSeqNum(0), - numThreads(_numThreads) -{ - for (int tid=0; tid < numThreads; tid++) { - doneSquashing[tid] = true; - threadEntries[tid] = 0; - } - - string policy = _smtROBPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Figure out rob policy - if (policy == "dynamic") { - robPolicy = Dynamic; - - //Set Max Entries to Total ROB Capacity - for (int i = 0; i < numThreads; i++) { - maxEntries[i]=numEntries; - } - - } else if (policy == "partitioned") { - robPolicy = Partitioned; - DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n"); - - //@todo:make work if part_amt doesnt divide evenly. - int part_amt = numEntries / numThreads; - - //Divide ROB up evenly - for (int i = 0; i < numThreads; i++) { - maxEntries[i]=part_amt; - } - - } else if (policy == "threshold") { - robPolicy = Threshold; - DPRINTF(Fetch, "ROB sharing policy set to Threshold\n"); - - int threshold = _smtROBThreshold;; - - //Divide up by threshold amount - for (int i = 0; i < numThreads; i++) { - maxEntries[i]=threshold; - } - } else { - assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic," - "Partitioned, Threshold}"); - } -} - -template <class Impl> -std::string -ROB<Impl>::name() const -{ - return cpu->name() + ".rob"; -} - -template <class Impl> -void -ROB<Impl>::setCPU(FullCPU *cpu_ptr) -{ - cpu = cpu_ptr; - - // Set the per-thread iterators to the end of the instruction list. - for (int i=0; i < numThreads;i++) { - squashIt[i] = instList[i].end(); - } - - // Initialize the "universal" ROB head & tail point to invalid - // pointers - head = instList[0].end(); - tail = instList[0].end(); -} - -template <class Impl> -void -ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(ROB, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -ROB<Impl>::switchOut() -{ - for (int tid = 0; tid < numThreads; tid++) { - instList[tid].clear(); - } -} - -template <class Impl> -void -ROB<Impl>::takeOverFrom() -{ - for (int tid=0; tid < numThreads; tid++) { - doneSquashing[tid] = true; - threadEntries[tid] = 0; - squashIt[tid] = instList[tid].end(); - } - numInstsInROB = 0; - - // Initialize the "universal" ROB head & tail point to invalid - // pointers - head = instList[0].end(); - tail = instList[0].end(); -} - -template <class Impl> -void -ROB<Impl>::resetEntries() -{ - if (robPolicy != Dynamic || numThreads > 1) { - int active_threads = (*activeThreads).size(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - list<unsigned>::iterator list_end = (*activeThreads).end(); - - while (threads != list_end) { - if (robPolicy == Partitioned) { - maxEntries[*threads++] = numEntries / active_threads; - } else if (robPolicy == Threshold && active_threads == 1) { - maxEntries[*threads++] = numEntries; - } - } - } -} - -template <class Impl> -int -ROB<Impl>::entryAmount(int num_threads) -{ - if (robPolicy == Partitioned) { - return numEntries / num_threads; - } else { - return 0; - } -} - -template <class Impl> -int -ROB<Impl>::countInsts() -{ - int total=0; - - for (int i=0;i < numThreads;i++) - total += countInsts(i); - - return total; -} - -template <class Impl> -int -ROB<Impl>::countInsts(unsigned tid) -{ - return instList[tid].size(); -} - -template <class Impl> -void -ROB<Impl>::insertInst(DynInstPtr &inst) -{ - //assert(numInstsInROB == countInsts()); - assert(inst); - - DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC()); - - assert(numInstsInROB != numEntries); - - int tid = inst->threadNumber; - - instList[tid].push_back(inst); - - //Set Up head iterator if this is the 1st instruction in the ROB - if (numInstsInROB == 0) { - head = instList[tid].begin(); - assert((*head) == inst); - } - - //Must Decrement for iterator to actually be valid since __.end() - //actually points to 1 after the last inst - tail = instList[tid].end(); - tail--; - - inst->setInROB(); - - ++numInstsInROB; - ++threadEntries[tid]; - - assert((*tail) == inst); - - DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]); -} - -// Whatever calls this function needs to ensure that it properly frees up -// registers prior to this function. -/* -template <class Impl> -void -ROB<Impl>::retireHead() -{ - //assert(numInstsInROB == countInsts()); - assert(numInstsInROB > 0); - - int tid = (*head)->threadNumber; - - retireHead(tid); - - if (numInstsInROB == 0) { - tail = instList[tid].end(); - } -} -*/ - -template <class Impl> -void -ROB<Impl>::retireHead(unsigned tid) -{ - //assert(numInstsInROB == countInsts()); - assert(numInstsInROB > 0); - - // Get the head ROB instruction. - InstIt head_it = instList[tid].begin(); - - DynInstPtr head_inst = (*head_it); - - assert(head_inst->readyToCommit()); - - DPRINTF(ROB, "[tid:%u]: Retiring head instruction, " - "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(), - head_inst->seqNum); - - --numInstsInROB; - --threadEntries[tid]; - - head_inst->removeInROB(); - head_inst->setCommitted(); - - instList[tid].erase(head_it); - - //Update "Global" Head of ROB - updateHead(); - - // @todo: A special case is needed if the instruction being - // retired is the only instruction in the ROB; otherwise the tail - // iterator will become invalidated. - cpu->removeFrontInst(head_inst); -} -/* -template <class Impl> -bool -ROB<Impl>::isHeadReady() -{ - if (numInstsInROB != 0) { - return (*head)->readyToCommit(); - } - - return false; -} -*/ -template <class Impl> -bool -ROB<Impl>::isHeadReady(unsigned tid) -{ - if (threadEntries[tid] != 0) { - return instList[tid].front()->readyToCommit(); - } - - return false; -} - -template <class Impl> -bool -ROB<Impl>::canCommit() -{ - //@todo: set ActiveThreads through ROB or CPU - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (isHeadReady(tid)) { - return true; - } - } - - return false; -} - -template <class Impl> -unsigned -ROB<Impl>::numFreeEntries() -{ - //assert(numInstsInROB == countInsts()); - - return numEntries - numInstsInROB; -} - -template <class Impl> -unsigned -ROB<Impl>::numFreeEntries(unsigned tid) -{ - return maxEntries[tid] - threadEntries[tid]; -} - -template <class Impl> -void -ROB<Impl>::doSquash(unsigned tid) -{ - DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n", - tid, squashedSeqNum); - - assert(squashIt[tid] != instList[tid].end()); - - if ((*squashIt[tid])->seqNum < squashedSeqNum) { - DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n", - tid); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - return; - } - - bool robTailUpdate = false; - - for (int numSquashed = 0; - numSquashed < squashWidth && - squashIt[tid] != instList[tid].end() && - (*squashIt[tid])->seqNum > squashedSeqNum; - ++numSquashed) - { - DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n", - (*squashIt[tid])->threadNumber, - (*squashIt[tid])->readPC(), - (*squashIt[tid])->seqNum); - - // Mark the instruction as squashed, and ready to commit so that - // it can drain out of the pipeline. - (*squashIt[tid])->setSquashed(); - - (*squashIt[tid])->setCanCommit(); - - - if (squashIt[tid] == instList[tid].begin()) { - DPRINTF(ROB, "Reached head of instruction list while " - "squashing.\n"); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - - return; - } - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - if ((*squashIt[tid]) == (*tail_thread)) - robTailUpdate = true; - - squashIt[tid]--; - } - - - // Check if ROB is done squashing. - if ((*squashIt[tid])->seqNum <= squashedSeqNum) { - DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n", - tid); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - } - - if (robTailUpdate) { - updateTail(); - } -} - - -template <class Impl> -void -ROB<Impl>::updateHead() -{ - DynInstPtr head_inst; - InstSeqNum lowest_num = 0; - bool first_valid = true; - - // @todo: set ActiveThreads through ROB or CPU - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned thread_num = *threads++; - - if (instList[thread_num].empty()) - continue; - - if (first_valid) { - head = instList[thread_num].begin(); - lowest_num = (*head)->seqNum; - first_valid = false; - continue; - } - - InstIt head_thread = instList[thread_num].begin(); - - DynInstPtr head_inst = (*head_thread); - - assert(head_inst != 0); - - if (head_inst->seqNum < lowest_num) { - head = head_thread; - lowest_num = head_inst->seqNum; - } - } - - if (first_valid) { - head = instList[0].end(); - } - -} - -template <class Impl> -void -ROB<Impl>::updateTail() -{ - tail = instList[0].end(); - bool first_valid = true; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (instList[tid].empty()) { - continue; - } - - // If this is the first valid then assign w/out - // comparison - if (first_valid) { - tail = instList[tid].end(); - tail--; - first_valid = false; - continue; - } - - // Assign new tail if this thread's tail is younger - // than our current "tail high" - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - if ((*tail_thread)->seqNum > (*tail)->seqNum) { - tail = tail_thread; - } - } -} - - -template <class Impl> -void -ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid) -{ - if (isEmpty()) { - DPRINTF(ROB, "Does not need to squash due to being empty " - "[sn:%i]\n", - squash_num); - - return; - } - - DPRINTF(ROB, "Starting to squash within the ROB.\n"); - - robStatus[tid] = ROBSquashing; - - doneSquashing[tid] = false; - - squashedSeqNum = squash_num; - - if (!instList[tid].empty()) { - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - squashIt[tid] = tail_thread; - - doSquash(tid); - } -} -/* -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readHeadInst() -{ - if (numInstsInROB != 0) { - assert((*head)->isInROB()==true); - return *head; - } else { - return dummyInst; - } -} -*/ -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readHeadInst(unsigned tid) -{ - if (threadEntries[tid] != 0) { - InstIt head_thread = instList[tid].begin(); - - assert((*head_thread)->isInROB()==true); - - return *head_thread; - } else { - return dummyInst; - } -} -/* -template <class Impl> -uint64_t -ROB<Impl>::readHeadPC() -{ - //assert(numInstsInROB == countInsts()); - - DynInstPtr head_inst = *head; - - return head_inst->readPC(); -} - -template <class Impl> -uint64_t -ROB<Impl>::readHeadPC(unsigned tid) -{ - //assert(numInstsInROB == countInsts()); - InstIt head_thread = instList[tid].begin(); - - return (*head_thread)->readPC(); -} - - -template <class Impl> -uint64_t -ROB<Impl>::readHeadNextPC() -{ - //assert(numInstsInROB == countInsts()); - - DynInstPtr head_inst = *head; - - return head_inst->readNextPC(); -} - -template <class Impl> -uint64_t -ROB<Impl>::readHeadNextPC(unsigned tid) -{ - //assert(numInstsInROB == countInsts()); - InstIt head_thread = instList[tid].begin(); - - return (*head_thread)->readNextPC(); -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readHeadSeqNum() -{ - //assert(numInstsInROB == countInsts()); - DynInstPtr head_inst = *head; - - return head_inst->seqNum; -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readHeadSeqNum(unsigned tid) -{ - InstIt head_thread = instList[tid].begin(); - - return ((*head_thread)->seqNum); -} - -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readTailInst() -{ - //assert(numInstsInROB == countInsts()); - //assert(tail != instList[0].end()); - - return (*tail); -} -*/ -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readTailInst(unsigned tid) -{ - //assert(tail_thread[tid] != instList[tid].end()); - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return *tail_thread; -} - -/* -template <class Impl> -uint64_t -ROB<Impl>::readTailPC() -{ - //assert(numInstsInROB == countInsts()); - - //assert(tail != instList[0].end()); - - return (*tail)->readPC(); -} - -template <class Impl> -uint64_t -ROB<Impl>::readTailPC(unsigned tid) -{ - //assert(tail_thread[tid] != instList[tid].end()); - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return (*tail_thread)->readPC(); -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readTailSeqNum() -{ - // Return the last sequence number that has not been squashed. Other - // stages can use it to squash any instructions younger than the current - // tail. - return (*tail)->seqNum; -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readTailSeqNum(unsigned tid) -{ - // Return the last sequence number that has not been squashed. Other - // stages can use it to squash any instructions younger than the current - // tail. - // assert(tail_thread[tid] != instList[tid].end()); - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return (*tail_thread)->seqNum; -} -*/ diff --git a/cpu/o3/sat_counter.hh b/cpu/o3/sat_counter.hh deleted file mode 100644 index d01fd93ce..000000000 --- a/cpu/o3/sat_counter.hh +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2005-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_SAT_COUNTER_HH__ -#define __CPU_O3_SAT_COUNTER_HH__ - -#include "sim/host.hh" - -/** - * Private counter class for the internal saturating counters. - * Implements an n bit saturating counter and provides methods to - * increment, decrement, and read it. - * @todo Consider making this something that more closely mimics a - * built in class so you can use ++ or --. - */ -class SatCounter -{ - public: - /** - * Constructor for the counter. - */ - SatCounter() - : initialVal(0), counter(0) - { } - - /** - * Constructor for the counter. - * @param bits How many bits the counter will have. - */ - SatCounter(unsigned bits) - : initialVal(0), maxVal((1 << bits) - 1), counter(0) - { } - - /** - * Constructor for the counter. - * @param bits How many bits the counter will have. - * @param initial_val Starting value for each counter. - */ - SatCounter(unsigned bits, uint8_t initial_val) - : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val) - { - // Check to make sure initial value doesn't exceed the max - // counter value. - if (initial_val > maxVal) { - fatal("BP: Initial counter value exceeds max size."); - } - } - - /** - * Sets the number of bits. - */ - void setBits(unsigned bits) { maxVal = (1 << bits) - 1; } - - void reset() { counter = initialVal; } - - /** - * Increments the counter's current value. - */ - void increment() - { - if (counter < maxVal) { - ++counter; - } - } - - /** - * Decrements the counter's current value. - */ - void decrement() - { - if (counter > 0) { - --counter; - } - } - - /** - * Read the counter's value. - */ - const uint8_t read() const - { return counter; } - - private: - uint8_t initialVal; - uint8_t maxVal; - uint8_t counter; -}; - -#endif // __CPU_O3_SAT_COUNTER_HH__ diff --git a/cpu/o3/store_set.cc b/cpu/o3/store_set.cc deleted file mode 100644 index 0c957c8c7..000000000 --- a/cpu/o3/store_set.cc +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/trace.hh" -#include "cpu/o3/store_set.hh" - -StoreSet::StoreSet(int _SSIT_size, int _LFST_size) - : SSITSize(_SSIT_size), LFSTSize(_LFST_size) -{ - DPRINTF(StoreSet, "StoreSet: Creating store set object.\n"); - DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n", - SSITSize, LFSTSize); - - SSIT.resize(SSITSize); - - validSSIT.resize(SSITSize); - - for (int i = 0; i < SSITSize; ++i) - validSSIT[i] = false; - - LFST.resize(LFSTSize); - - validLFST.resize(LFSTSize); - - for (int i = 0; i < LFSTSize; ++i) { - validLFST[i] = false; - LFST[i] = 0; - } - - indexMask = SSITSize - 1; - - offsetBits = 2; -} - -StoreSet::~StoreSet() -{ -} - -void -StoreSet::init(int _SSIT_size, int _LFST_size) -{ - SSITSize = _SSIT_size; - LFSTSize = _LFST_size; - - DPRINTF(StoreSet, "StoreSet: Creating store set object.\n"); - DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n", - SSITSize, LFSTSize); - - SSIT.resize(SSITSize); - - validSSIT.resize(SSITSize); - - for (int i = 0; i < SSITSize; ++i) - validSSIT[i] = false; - - LFST.resize(LFSTSize); - - validLFST.resize(LFSTSize); - - for (int i = 0; i < LFSTSize; ++i) { - validLFST[i] = false; - LFST[i] = 0; - } - - indexMask = SSITSize - 1; - - offsetBits = 2; -} - - -void -StoreSet::violation(Addr store_PC, Addr load_PC) -{ - int load_index = calcIndex(load_PC); - int store_index = calcIndex(store_PC); - - assert(load_index < SSITSize && store_index < SSITSize); - - bool valid_load_SSID = validSSIT[load_index]; - bool valid_store_SSID = validSSIT[store_index]; - - if (!valid_load_SSID && !valid_store_SSID) { - // Calculate a new SSID here. - SSID new_set = calcSSID(load_PC); - - validSSIT[load_index] = true; - - SSIT[load_index] = new_set; - - validSSIT[store_index] = true; - - SSIT[store_index] = new_set; - - assert(new_set < LFSTSize); - - DPRINTF(StoreSet, "StoreSet: Neither load nor store had a valid " - "storeset, creating a new one: %i for load %#x, store %#x\n", - new_set, load_PC, store_PC); - } else if (valid_load_SSID && !valid_store_SSID) { - SSID load_SSID = SSIT[load_index]; - - validSSIT[store_index] = true; - - SSIT[store_index] = load_SSID; - - assert(load_SSID < LFSTSize); - - DPRINTF(StoreSet, "StoreSet: Load had a valid store set. Adding " - "store to that set: %i for load %#x, store %#x\n", - load_SSID, load_PC, store_PC); - } else if (!valid_load_SSID && valid_store_SSID) { - SSID store_SSID = SSIT[store_index]; - - validSSIT[load_index] = true; - - SSIT[load_index] = store_SSID; - - DPRINTF(StoreSet, "StoreSet: Store had a valid store set: %i for " - "load %#x, store %#x\n", - store_SSID, load_PC, store_PC); - } else { - SSID load_SSID = SSIT[load_index]; - SSID store_SSID = SSIT[store_index]; - - assert(load_SSID < LFSTSize && store_SSID < LFSTSize); - - // The store set with the lower number wins - if (store_SSID > load_SSID) { - SSIT[store_index] = load_SSID; - - DPRINTF(StoreSet, "StoreSet: Load had smaller store set: %i; " - "for load %#x, store %#x\n", - load_SSID, load_PC, store_PC); - } else { - SSIT[load_index] = store_SSID; - - DPRINTF(StoreSet, "StoreSet: Store had smaller store set: %i; " - "for load %#x, store %#x\n", - store_SSID, load_PC, store_PC); - } - } -} - -void -StoreSet::insertLoad(Addr load_PC, InstSeqNum load_seq_num) -{ - // Does nothing. - return; -} - -void -StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num, - unsigned tid) -{ - int index = calcIndex(store_PC); - - int store_SSID; - - assert(index < SSITSize); - - if (!validSSIT[index]) { - // Do nothing if there's no valid entry. - return; - } else { - store_SSID = SSIT[index]; - - assert(store_SSID < LFSTSize); - - // Update the last store that was fetched with the current one. - LFST[store_SSID] = store_seq_num; - - validLFST[store_SSID] = 1; - - storeList[store_seq_num] = store_SSID; - - DPRINTF(StoreSet, "Store %#x updated the LFST, SSID: %i\n", - store_PC, store_SSID); - } -} - -InstSeqNum -StoreSet::checkInst(Addr PC) -{ - int index = calcIndex(PC); - - int inst_SSID; - - assert(index < SSITSize); - - if (!validSSIT[index]) { - DPRINTF(StoreSet, "Inst %#x with index %i had no SSID\n", - PC, index); - - // Return 0 if there's no valid entry. - return 0; - } else { - inst_SSID = SSIT[index]; - - assert(inst_SSID < LFSTSize); - - if (!validLFST[inst_SSID]) { - - DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had no " - "dependency\n", PC, index, inst_SSID); - - return 0; - } else { - DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had LFST " - "inum of %i\n", PC, index, inst_SSID, LFST[inst_SSID]); - - return LFST[inst_SSID]; - } - } -} - -void -StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store) -{ - // This only is updated upon a store being issued. - if (!is_store) { - return; - } - - int index = calcIndex(issued_PC); - - int store_SSID; - - assert(index < SSITSize); - - SeqNumMapIt store_list_it = storeList.find(issued_seq_num); - - if (store_list_it != storeList.end()) { - storeList.erase(store_list_it); - } - - // Make sure the SSIT still has a valid entry for the issued store. - if (!validSSIT[index]) { - return; - } - - store_SSID = SSIT[index]; - - assert(store_SSID < LFSTSize); - - // If the last fetched store in the store set refers to the store that - // was just issued, then invalidate the entry. - if (validLFST[store_SSID] && LFST[store_SSID] == issued_seq_num) { - DPRINTF(StoreSet, "StoreSet: store invalidated itself in LFST.\n"); - validLFST[store_SSID] = false; - } -} - -void -StoreSet::squash(InstSeqNum squashed_num, unsigned tid) -{ - DPRINTF(StoreSet, "StoreSet: Squashing until inum %i\n", - squashed_num); - - int idx; - SeqNumMapIt store_list_it = storeList.begin(); - - //@todo:Fix to only delete from correct thread - while (!storeList.empty()) { - idx = (*store_list_it).second; - - if ((*store_list_it).first <= squashed_num) { - break; - } - - bool younger = LFST[idx] > squashed_num; - - if (validLFST[idx] && younger) { - DPRINTF(StoreSet, "Squashed [sn:%lli]\n", LFST[idx]); - validLFST[idx] = false; - - storeList.erase(store_list_it++); - } else if (!validLFST[idx] && younger) { - storeList.erase(store_list_it++); - } - } -} - -void -StoreSet::clear() -{ - for (int i = 0; i < SSITSize; ++i) { - validSSIT[i] = false; - } - - for (int i = 0; i < LFSTSize; ++i) { - validLFST[i] = false; - } - - storeList.clear(); -} diff --git a/cpu/o3/store_set.hh b/cpu/o3/store_set.hh deleted file mode 100644 index 7189db3ab..000000000 --- a/cpu/o3/store_set.hh +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_STORE_SET_HH__ -#define __CPU_O3_STORE_SET_HH__ - -#include <list> -#include <map> -#include <utility> -#include <vector> - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" - -struct ltseqnum { - bool operator()(const InstSeqNum &lhs, const InstSeqNum &rhs) const - { - return lhs > rhs; - } -}; - -class StoreSet -{ - public: - typedef unsigned SSID; - - public: - StoreSet() { }; - - StoreSet(int SSIT_size, int LFST_size); - - ~StoreSet(); - - void init(int SSIT_size, int LFST_size); - - void violation(Addr store_PC, Addr load_PC); - - void insertLoad(Addr load_PC, InstSeqNum load_seq_num); - - void insertStore(Addr store_PC, InstSeqNum store_seq_num, - unsigned tid); - - InstSeqNum checkInst(Addr PC); - - void issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store); - - void squash(InstSeqNum squashed_num, unsigned tid); - - void clear(); - - private: - inline int calcIndex(Addr PC) - { return (PC >> offsetBits) & indexMask; } - - inline SSID calcSSID(Addr PC) - { return ((PC ^ (PC >> 10)) % LFSTSize); } - - std::vector<SSID> SSIT; - - std::vector<bool> validSSIT; - - std::vector<InstSeqNum> LFST; - - std::vector<bool> validLFST; - - std::map<InstSeqNum, int, ltseqnum> storeList; - - typedef std::map<InstSeqNum, int, ltseqnum>::iterator SeqNumMapIt; - - int SSITSize; - - int LFSTSize; - - int indexMask; - - // HACK: Hardcoded for now. - int offsetBits; -}; - -#endif // __CPU_O3_STORE_SET_HH__ diff --git a/cpu/o3/tournament_pred.cc b/cpu/o3/tournament_pred.cc deleted file mode 100644 index 89da7b9f5..000000000 --- a/cpu/o3/tournament_pred.cc +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/tournament_pred.hh" - -TournamentBP::TournamentBP(unsigned _localPredictorSize, - unsigned _localCtrBits, - unsigned _localHistoryTableSize, - unsigned _localHistoryBits, - unsigned _globalPredictorSize, - unsigned _globalCtrBits, - unsigned _globalHistoryBits, - unsigned _choicePredictorSize, - unsigned _choiceCtrBits, - unsigned _instShiftAmt) - : localPredictorSize(_localPredictorSize), - localCtrBits(_localCtrBits), - localHistoryTableSize(_localHistoryTableSize), - localHistoryBits(_localHistoryBits), - globalPredictorSize(_globalPredictorSize), - globalCtrBits(_globalCtrBits), - globalHistoryBits(_globalHistoryBits), - choicePredictorSize(_globalPredictorSize), - choiceCtrBits(_choiceCtrBits), - instShiftAmt(_instShiftAmt) -{ - //Should do checks here to make sure sizes are correct (powers of 2) - - //Setup the array of counters for the local predictor - localCtrs.resize(localPredictorSize); - - for (int i = 0; i < localPredictorSize; ++i) - localCtrs[i].setBits(localCtrBits); - - //Setup the history table for the local table - localHistoryTable.resize(localHistoryTableSize); - - for (int i = 0; i < localHistoryTableSize; ++i) - localHistoryTable[i] = 0; - - // Setup the local history mask - localHistoryMask = (1 << localHistoryBits) - 1; - - //Setup the array of counters for the global predictor - globalCtrs.resize(globalPredictorSize); - - for (int i = 0; i < globalPredictorSize; ++i) - globalCtrs[i].setBits(globalCtrBits); - - //Clear the global history - globalHistory = 0; - // Setup the global history mask - globalHistoryMask = (1 << globalHistoryBits) - 1; - - //Setup the array of counters for the choice predictor - choiceCtrs.resize(choicePredictorSize); - - for (int i = 0; i < choicePredictorSize; ++i) - choiceCtrs[i].setBits(choiceCtrBits); - - threshold = (1 << (localCtrBits - 1)) - 1; - threshold = threshold / 2; -} - -inline -unsigned -TournamentBP::calcLocHistIdx(Addr &branch_addr) -{ - return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1); -} - -inline -void -TournamentBP::updateHistoriesTaken(unsigned local_history_idx) -{ - globalHistory = (globalHistory << 1) | 1; - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] = - (localHistoryTable[local_history_idx] << 1) | 1; -} - -inline -void -TournamentBP::updateHistoriesNotTaken(unsigned local_history_idx) -{ - globalHistory = (globalHistory << 1); - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] = - (localHistoryTable[local_history_idx] << 1); -} - -bool -TournamentBP::lookup(Addr &branch_addr) -{ - uint8_t local_prediction; - unsigned local_history_idx; - unsigned local_predictor_idx; - - uint8_t global_prediction; - uint8_t choice_prediction; - - //Lookup in the local predictor to get its branch prediction - local_history_idx = calcLocHistIdx(branch_addr); - local_predictor_idx = localHistoryTable[local_history_idx] - & localHistoryMask; - local_prediction = localCtrs[local_predictor_idx].read(); - - //Lookup in the global predictor to get its branch prediction - global_prediction = globalCtrs[globalHistory].read(); - - //Lookup in the choice predictor to see which one to use - choice_prediction = choiceCtrs[globalHistory].read(); - - //@todo Put a threshold value in for the three predictors that can - // be set through the constructor (so this isn't hard coded). - //Also should put some of this code into functions. - if (choice_prediction > threshold) { - if (global_prediction > threshold) { - updateHistoriesTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].increment(); - localCtrs[local_history_idx].increment(); - - return true; - } else { - updateHistoriesNotTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].decrement(); - localCtrs[local_history_idx].decrement(); - - return false; - } - } else { - if (local_prediction > threshold) { - updateHistoriesTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].increment(); - localCtrs[local_history_idx].increment(); - - return true; - } else { - updateHistoriesNotTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].decrement(); - localCtrs[local_history_idx].decrement(); - - return false; - } - } -} - -// Update the branch predictor if it predicted a branch wrong. -void -TournamentBP::update(Addr &branch_addr, unsigned correct_gh, bool taken) -{ - - uint8_t local_prediction; - unsigned local_history_idx; - unsigned local_predictor_idx; - bool local_pred_taken; - - uint8_t global_prediction; - bool global_pred_taken; - - // Load the correct global history into the register. - globalHistory = correct_gh; - - // Get the local predictor's current prediction, remove the incorrect - // update, and update the local predictor - local_history_idx = calcLocHistIdx(branch_addr); - local_predictor_idx = localHistoryTable[local_history_idx]; - local_predictor_idx = (local_predictor_idx >> 1) & localHistoryMask; - - local_prediction = localCtrs[local_predictor_idx].read(); - local_pred_taken = local_prediction > threshold; - - //Get the global predictor's current prediction, and update the - //global predictor - global_prediction = globalCtrs[globalHistory].read(); - global_pred_taken = global_prediction > threshold; - - //Update the choice predictor to tell it which one was correct - if (local_pred_taken != global_pred_taken) { - //If the local prediction matches the actual outcome, decerement - //the counter. Otherwise increment the counter. - if (local_pred_taken == taken) { - choiceCtrs[globalHistory].decrement(); - } else { - choiceCtrs[globalHistory].increment(); - } - } - - if (taken) { - assert(globalHistory < globalPredictorSize && - local_predictor_idx < localPredictorSize); - - localCtrs[local_predictor_idx].increment(); - globalCtrs[globalHistory].increment(); - - globalHistory = (globalHistory << 1) | 1; - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] |= 1; - } else { - assert(globalHistory < globalPredictorSize && - local_predictor_idx < localPredictorSize); - - localCtrs[local_predictor_idx].decrement(); - globalCtrs[globalHistory].decrement(); - - globalHistory = (globalHistory << 1); - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] &= ~1; - } -} diff --git a/cpu/o3/tournament_pred.hh b/cpu/o3/tournament_pred.hh deleted file mode 100644 index 7b600aa53..000000000 --- a/cpu/o3/tournament_pred.hh +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_TOURNAMENT_PRED_HH__ -#define __CPU_O3_TOURNAMENT_PRED_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include "cpu/o3/sat_counter.hh" -#include <vector> - -class TournamentBP -{ - public: - /** - * Default branch predictor constructor. - */ - TournamentBP(unsigned localPredictorSize, - unsigned localCtrBits, - unsigned localHistoryTableSize, - unsigned localHistoryBits, - unsigned globalPredictorSize, - unsigned globalHistoryBits, - unsigned globalCtrBits, - unsigned choicePredictorSize, - unsigned choiceCtrBits, - unsigned instShiftAmt); - - /** - * Looks up the given address in the branch predictor and returns - * a true/false value as to whether it is taken. - * @param branch_addr The address of the branch to look up. - * @return Whether or not the branch is taken. - */ - bool lookup(Addr &branch_addr); - - /** - * Updates the branch predictor with the actual result of a branch. - * @param branch_addr The address of the branch to update. - * @param taken Whether or not the branch was taken. - */ - void update(Addr &branch_addr, unsigned global_history, bool taken); - - inline unsigned readGlobalHist() { return globalHistory; } - - private: - - inline bool getPrediction(uint8_t &count); - - inline unsigned calcLocHistIdx(Addr &branch_addr); - - inline void updateHistoriesTaken(unsigned local_history_idx); - - inline void updateHistoriesNotTaken(unsigned local_history_idx); - - /** Local counters. */ - std::vector<SatCounter> localCtrs; - - /** Size of the local predictor. */ - unsigned localPredictorSize; - - /** Number of bits of the local predictor's counters. */ - unsigned localCtrBits; - - /** Array of local history table entries. */ - std::vector<unsigned> localHistoryTable; - - /** Size of the local history table. */ - unsigned localHistoryTableSize; - - /** Number of bits for each entry of the local history table. - * @todo Doesn't this come from the size of the local predictor? - */ - unsigned localHistoryBits; - - /** Mask to get the proper local history. */ - unsigned localHistoryMask; - - - /** Array of counters that make up the global predictor. */ - std::vector<SatCounter> globalCtrs; - - /** Size of the global predictor. */ - unsigned globalPredictorSize; - - /** Number of bits of the global predictor's counters. */ - unsigned globalCtrBits; - - /** Global history register. */ - unsigned globalHistory; - - /** Number of bits for the global history. */ - unsigned globalHistoryBits; - - /** Mask to get the proper global history. */ - unsigned globalHistoryMask; - - - /** Array of counters that make up the choice predictor. */ - std::vector<SatCounter> choiceCtrs; - - /** Size of the choice predictor (identical to the global predictor). */ - unsigned choicePredictorSize; - - /** Number of bits of the choice predictor's counters. */ - unsigned choiceCtrBits; - - /** Number of bits to shift the instruction over to get rid of the word - * offset. - */ - unsigned instShiftAmt; - - /** Threshold for the counter value; above the threshold is taken, - * equal to or below the threshold is not taken. - */ - unsigned threshold; -}; - -#endif // __CPU_O3_TOURNAMENT_PRED_HH__ diff --git a/cpu/ozone/cpu.cc b/cpu/ozone/cpu.cc deleted file mode 100644 index d2ea0164c..000000000 --- a/cpu/ozone/cpu.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/ozone/cpu_impl.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class OzoneCPU<SimpleImpl>; -template class OzoneCPU<OzoneImpl>; diff --git a/cpu/ozone/cpu.hh b/cpu/ozone/cpu.hh deleted file mode 100644 index 5af2b02b2..000000000 --- a/cpu/ozone/cpu.hh +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_CPU_HH__ -#define __CPU_OZONE_CPU_HH__ - -#include <set> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/rename_table.hh" -#include "cpu/ozone/thread_state.hh" -#include "cpu/pc_event.hh" -#include "cpu/static_inst.hh" -#include "mem/mem_interface.hh" -#include "sim/eventq.hh" - -// forward declarations -#if FULL_SYSTEM -#include "arch/alpha/tlb.hh" - -class AlphaITB; -class AlphaDTB; -class PhysicalMemory; -class MemoryController; - -class Sampler; -class RemoteGDB; -class GDBListener; - -namespace Kernel { - class Statistics; -}; - -#else - -class Process; - -#endif // FULL_SYSTEM - -class Checkpoint; -class EndQuiesceEvent; -class MemInterface; - -namespace Trace { - class InstRecord; -} - -template <class> -class Checker; - -/** - * Declaration of Out-of-Order CPU class. Basically it is a SimpleCPU with - * simple out-of-order capabilities added to it. It is still a 1 CPI machine - * (?), but is capable of handling cache misses. Basically it models having - * a ROB/IQ by only allowing a certain amount of instructions to execute while - * the cache miss is outstanding. - */ - -template <class Impl> -class OzoneCPU : public BaseCPU -{ - private: - typedef typename Impl::FrontEnd FrontEnd; - typedef typename Impl::BackEnd BackEnd; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef TheISA::MiscReg MiscReg; - - public: - class OzoneXC : public ExecContext { - public: - OzoneCPU<Impl> *cpu; - - OzoneThreadState<Impl> *thread; - - BaseCPU *getCpuPtr(); - - void setCpuId(int id); - - int readCpuId() { return thread->cpuId; } - - FunctionalMemory *getMemPtr() { return thread->mem; } - -#if FULL_SYSTEM - System *getSystemPtr() { return cpu->system; } - - PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } - - AlphaITB *getITBPtr() { return cpu->itb; } - - AlphaDTB * getDTBPtr() { return cpu->dtb; } - - Kernel::Statistics *getKernelStats() { return thread->kernelStats; } -#else - Process *getProcessPtr() { return thread->process; } -#endif - - Status status() const { return thread->_status; } - - void setStatus(Status new_status); - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1); - - /// Set the status to Suspended. - void suspend(); - - /// Set the status to Unallocated. - void deallocate(); - - /// Set the status to Halted. - void halt(); - -#if FULL_SYSTEM - void dumpFuncProfile(); -#endif - - void takeOverFrom(ExecContext *old_context); - - void regStats(const std::string &name); - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - -#if FULL_SYSTEM - EndQuiesceEvent *getQuiesceEvent(); - - Tick readLastActivate(); - Tick readLastSuspend(); - - void profileClear(); - void profileSample(); -#endif - - int getThreadNum(); - - // Also somewhat obnoxious. Really only used for the TLB fault. - TheISA::MachInst getInst(); - - void copyArchRegs(ExecContext *xc); - - void clearArchRegs(); - - uint64_t readIntReg(int reg_idx); - - float readFloatRegSingle(int reg_idx); - - double readFloatRegDouble(int reg_idx); - - uint64_t readFloatRegInt(int reg_idx); - - void setIntReg(int reg_idx, uint64_t val); - - void setFloatRegSingle(int reg_idx, float val); - - void setFloatRegDouble(int reg_idx, double val); - - void setFloatRegInt(int reg_idx, uint64_t val); - - uint64_t readPC() { return thread->PC; } - void setPC(Addr val); - - uint64_t readNextPC() { return thread->nextPC; } - void setNextPC(Addr val); - - public: - // ISA stuff: - MiscReg readMiscReg(int misc_reg); - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault); - - Fault setMiscReg(int misc_reg, const MiscReg &val); - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); - - unsigned readStCondFailures() - { return thread->storeCondFailures; } - - void setStCondFailures(unsigned sc_failures) - { thread->storeCondFailures = sc_failures; } - -#if FULL_SYSTEM - bool inPalMode() { return cpu->inPalMode(); } -#endif - - bool misspeculating() { return false; } - -#if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { return thread->renameTable[TheISA::ArgumentReg0 + i]->readIntResult(); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { thread->renameTable[TheISA::ArgumentReg0 + i]->setIntResult(i); } - - void setSyscallReturn(SyscallReturn return_value) - { cpu->setSyscallReturn(return_value, thread->tid); } - - Counter readFuncExeInst() { return thread->funcExeInst; } - - void setFuncExeInst(Counter new_val) - { thread->funcExeInst = new_val; } -#endif - }; - - // execution context proxy - OzoneXC ozoneXC; - ExecContext *xcProxy; - ExecContext *checkerXC; - - typedef OzoneThreadState<Impl> ImplState; - - private: - OzoneThreadState<Impl> thread; - - public: - // main simulation loop (one cycle) - void tick(); - - std::set<InstSeqNum> snList; - std::set<Addr> lockAddrList; - private: - struct TickEvent : public Event - { - OzoneCPU *cpu; - int width; - - TickEvent(OzoneCPU *c, int w); - void process(); - const char *description(); - }; - - TickEvent tickEvent; - - /// Schedule tick event, regardless of its current state. - void scheduleTickEvent(int delay) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(delay)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(delay)); - } - - /// Unschedule tick event, regardless of its current state. - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - private: - Trace::InstRecord *traceData; - - template<typename T> - void trace_data(T data); - - public: - enum Status { - Running, - Idle, - SwitchedOut - }; - - Status _status; - - public: - bool checkInterrupts; - - void post_interrupt(int int_num, int index); - - void zero_fill_64(Addr addr) { - static int warned = 0; - if (!warned) { - warn ("WH64 is not implemented"); - warned = 1; - } - }; - - typedef typename Impl::Params Params; - - OzoneCPU(Params *params); - - virtual ~OzoneCPU(); - - void init(); - - public: - BaseCPU *getCpuPtr() { return this; } - - void setCpuId(int id) { cpuId = id; } - - int readCpuId() { return cpuId; } - - int cpuId; - - void switchOut(Sampler *sampler); - void signalSwitched(); - void takeOverFrom(BaseCPU *oldCPU); - - Sampler *sampler; - - int switchCount; - -#if FULL_SYSTEM - Addr dbg_vtophys(Addr addr); - - bool interval_stats; - - AlphaITB *itb; - AlphaDTB *dtb; - System *system; - - // the following two fields are redundant, since we can always - // look them up through the system pointer, but we'll leave them - // here for now for convenience - MemoryController *memctrl; - PhysicalMemory *physmem; -#endif - - // L1 instruction cache - MemInterface *icacheInterface; - - // L1 data cache - MemInterface *dcacheInterface; - - /** Pointer to memory. */ - FunctionalMemory *mem; - - FrontEnd *frontEnd; - - BackEnd *backEnd; - private: - Status status() const { return _status; } - void setStatus(Status new_status) { _status = new_status; } - - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); - virtual void deallocateContext(int thread_num); - virtual void haltContext(int thread_num); - - // statistics - virtual void regStats(); - virtual void resetStats(); - - // number of simulated instructions - public: - Counter numInst; - Counter startNumInst; - - virtual Counter totalInstructions() const - { - return numInst - startNumInst; - } - - private: - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - // number of idle cycles - Stats::Average<> notIdleFraction; - Stats::Formula idleFraction; - public: - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - -#if FULL_SYSTEM - bool validInstAddr(Addr addr) { return true; } - bool validDataAddr(Addr addr) { return true; } - - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - bool validInstAddr(Addr addr) - { return true; } - - bool validDataAddr(Addr addr) - { return true; } - - int getInstAsid() { return thread.asid; } - int getDataAsid() { return thread.asid; } - - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } -#endif - - /** Old CPU read from memory function. No longer used. */ - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif -#endif - Fault error; - if (req->flags & LOCKED) { - lockAddrList.insert(req->paddr); - lockFlag = true; - } - - error = this->mem->read(req, data); - data = gtoh(data); - return error; - } - - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx) - { - return backEnd->read(req, data, load_idx); - } - - /** Old CPU write to memory function. No longer used. */ - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < this->system->execContexts.size(); i++){ - xc = this->system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif -#endif - - if (req->flags & LOCKED) { - if (req->flags & UNCACHEABLE) { - req->result = 2; - } else { - if (this->lockFlag) { - if (lockAddrList.find(req->paddr) != - lockAddrList.end()) { - req->result = 1; - } else { - req->result = 0; - return NoFault; - } - } else { - req->result = 0; - return NoFault; - } - } - } - - return this->mem->write(req, (T)htog(data)); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx) - { - return backEnd->write(req, data, store_idx); - } - - void prefetch(Addr addr, unsigned flags) - { - // need to do this... - } - - void writeHint(Addr addr, int size, unsigned flags) - { - // need to do this... - } - - Fault copySrcTranslate(Addr src); - - Fault copy(Addr dest); - - InstSeqNum globalSeqNum; - - public: - void squashFromXC(); - - // @todo: This can be a useful debug function. Implement it. - void dumpInsts() { frontEnd->dumpInsts(); } - -#if FULL_SYSTEM - Fault hwrei(); - int readIntrFlag() { return thread.regs.intrflag; } - void setIntrFlag(int val) { thread.regs.intrflag = val; } - bool inPalMode() { return AlphaISA::PcPAL(thread.PC); } - bool inPalMode(Addr pc) { return AlphaISA::PcPAL(pc); } - bool simPalCheck(int palFunc); - void processInterrupts(); -#else - void syscall(); - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - ExecContext *xcBase() { return xcProxy; } - - bool decoupledFrontEnd; - struct CommStruct { - InstSeqNum doneSeqNum; - InstSeqNum nonSpecSeqNum; - bool uncached; - unsigned lqIdx; - - bool stall; - }; - TimeBuffer<CommStruct> comm; - - bool lockFlag; - - Stats::Scalar<> quiesceCycles; - - Checker<DynInstPtr> *checker; -}; - -#endif // __CPU_OZONE_CPU_HH__ diff --git a/cpu/ozone/cpu_impl.hh b/cpu/ozone/cpu_impl.hh deleted file mode 100644 index 5675da3a8..000000000 --- a/cpu/ozone/cpu_impl.hh +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -//#include <cstdio> -//#include <cstdlib> - -#include "arch/isa_traits.hh" // For MachInst -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/checker/exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/ozone/cpu.hh" -#include "cpu/quiesce_event.hh" -#include "cpu/static_inst.hh" -//#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#if FULL_SYSTEM -#include "arch/faults.hh" -#include "arch/alpha/osfpal.hh" -#include "arch/alpha/tlb.hh" -#include "arch/vtophys.hh" -#include "base/callback.hh" -//#include "base/remote_gdb.hh" -#include "cpu/profile.hh" -#include "kern/kernel_stats.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/faults.hh" -#include "sim/sim_events.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#include "sim/process.hh" -#endif // FULL_SYSTEM - -using namespace TheISA; - -template <class Impl> -template<typename T> -void -OzoneCPU<Impl>::trace_data(T data) { - if (traceData) { - traceData->setData(data); - } -} - -template <class Impl> -OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) -{ -} - -template <class Impl> -void -OzoneCPU<Impl>::TickEvent::process() -{ - cpu->tick(); -} - -template <class Impl> -const char * -OzoneCPU<Impl>::TickEvent::description() -{ - return "OzoneCPU tick event"; -} - -template <class Impl> -OzoneCPU<Impl>::OzoneCPU(Params *p) -#if FULL_SYSTEM - : BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width), - mem(p->mem), -#else - : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width), - mem(p->workload[0]->getMemory()), -#endif - comm(5, 5) -{ - frontEnd = new FrontEnd(p); - backEnd = new BackEnd(p); - - _status = Idle; - - if (p->checker) { - BaseCPU *temp_checker = p->checker; - checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); - checker->setMemory(mem); -#if FULL_SYSTEM - checker->setSystem(p->system); -#endif - checkerXC = new CheckerExecContext<OzoneXC>(&ozoneXC, checker); - thread.xcProxy = checkerXC; - xcProxy = checkerXC; - } else { - checker = NULL; - thread.xcProxy = &ozoneXC; - xcProxy = &ozoneXC; - } - - ozoneXC.cpu = this; - ozoneXC.thread = &thread; - - thread.inSyscall = false; - - thread.setStatus(ExecContext::Suspended); -#if FULL_SYSTEM - /***** All thread state stuff *****/ - thread.cpu = this; - thread.tid = 0; - thread.mem = p->mem; - - thread.quiesceEvent = new EndQuiesceEvent(xcProxy); - - system = p->system; - itb = p->itb; - dtb = p->dtb; - memctrl = p->system->memctrl; - physmem = p->system->physmem; - - if (p->profile) { - thread.profile = new FunctionProfile(p->system->kernelSymtab); - // @todo: This might be better as an ExecContext instead of OzoneXC - Callback *cb = - new MakeCallback<OzoneXC, - &OzoneXC::dumpFuncProfile>(&ozoneXC); - 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; - thread.profileNode = &dummyNode; - thread.profilePC = 3; -#else - thread.cpu = this; - thread.tid = 0; - thread.process = p->workload[0]; - thread.asid = 0; -#endif // !FULL_SYSTEM - - numInst = 0; - startNumInst = 0; - - execContexts.push_back(xcProxy); - - frontEnd->setCPU(this); - backEnd->setCPU(this); - - frontEnd->setXC(xcProxy); - backEnd->setXC(xcProxy); - - frontEnd->setThreadState(&thread); - backEnd->setThreadState(&thread); - - frontEnd->setCommBuffer(&comm); - backEnd->setCommBuffer(&comm); - - frontEnd->setBackEnd(backEnd); - backEnd->setFrontEnd(frontEnd); - - decoupledFrontEnd = p->decoupledFrontEnd; - - globalSeqNum = 1; - - checkInterrupts = false; - - for (int i = 0; i < TheISA::TotalNumRegs; ++i) { - thread.renameTable[i] = new DynInst(this); - thread.renameTable[i]->setResultReady(); - } - - frontEnd->renameTable.copyFrom(thread.renameTable); - backEnd->renameTable.copyFrom(thread.renameTable); - -#if !FULL_SYSTEM -// pTable = p->pTable; -#endif - - lockFlag = 0; - - DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n"); -} - -template <class Impl> -OzoneCPU<Impl>::~OzoneCPU() -{ -} - -template <class Impl> -void -OzoneCPU<Impl>::switchOut(Sampler *_sampler) -{ - sampler = _sampler; - switchCount = 0; - // Front end needs state from back end, so switch out the back end first. - backEnd->switchOut(); - frontEnd->switchOut(); -} - -template <class Impl> -void -OzoneCPU<Impl>::signalSwitched() -{ - if (++switchCount == 2) { - backEnd->doSwitchOut(); - frontEnd->doSwitchOut(); - if (checker) - checker->switchOut(sampler); - _status = SwitchedOut; - if (tickEvent.scheduled()) - tickEvent.squash(); - sampler->signalSwitched(); - } - assert(switchCount <= 2); -} - -template <class Impl> -void -OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU) -{ - BaseCPU::takeOverFrom(oldCPU); - - backEnd->takeOverFrom(); - frontEnd->takeOverFrom(); - assert(!tickEvent.scheduled()); - - // @todo: Fix hardcoded number - // Clear out any old information in time buffer. - for (int i = 0; i < 6; ++i) { - comm.advance(); - } - - // 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); - } - } - // Nothing running, change status to reflect that we're no longer - // switched out. - if (_status == SwitchedOut) { - _status = Idle; - } -} - -template <class Impl> -void -OzoneCPU<Impl>::activateContext(int thread_num, int delay) -{ - // Eventually change this in SMT. - assert(thread_num == 0); - - assert(_status == Idle); - notIdleFraction++; - scheduleTickEvent(delay); - _status = Running; - thread._status = ExecContext::Active; - frontEnd->wakeFromQuiesce(); -} - -template <class Impl> -void -OzoneCPU<Impl>::suspendContext(int thread_num) -{ - // Eventually change this in SMT. - assert(thread_num == 0); - // @todo: Figure out how to initially set the status properly so - // this is running. -// assert(_status == Running); - notIdleFraction--; - unscheduleTickEvent(); - _status = Idle; -} - -template <class Impl> -void -OzoneCPU<Impl>::deallocateContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - -template <class Impl> -void -OzoneCPU<Impl>::haltContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - -template <class Impl> -void -OzoneCPU<Impl>::regStats() -{ - using namespace Stats; - - BaseCPU::regStats(); - - thread.numInsts - .name(name() + ".num_insts") - .desc("Number of instructions executed") - ; - - thread.numMemRefs - .name(name() + ".num_refs") - .desc("Number of memory references") - ; - - notIdleFraction - .name(name() + ".not_idle_fraction") - .desc("Percentage of non-idle cycles") - ; - - idleFraction - .name(name() + ".idle_fraction") - .desc("Percentage of idle cycles") - ; - - quiesceCycles - .name(name() + ".quiesce_cycles") - .desc("Number of cycles spent in quiesce") - ; - - idleFraction = constant(1.0) - notIdleFraction; - - frontEnd->regStats(); - backEnd->regStats(); -} - -template <class Impl> -void -OzoneCPU<Impl>::resetStats() -{ - startNumInst = numInst; - notIdleFraction = (_status != Idle); -} - -template <class Impl> -void -OzoneCPU<Impl>::init() -{ - BaseCPU::init(); - - // Mark this as in syscall so it won't need to squash - thread.inSyscall = true; -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif - frontEnd->renameTable.copyFrom(thread.renameTable); - backEnd->renameTable.copyFrom(thread.renameTable); - - thread.inSyscall = false; -} - -template <class Impl> -void -OzoneCPU<Impl>::serialize(std::ostream &os) -{ - BaseCPU::serialize(os); - SERIALIZE_ENUM(_status); - nameOut(os, csprintf("%s.xc", name())); - ozoneXC.serialize(os); - nameOut(os, csprintf("%s.tickEvent", name())); - tickEvent.serialize(os); -} - -template <class Impl> -void -OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string §ion) -{ - BaseCPU::unserialize(cp, section); - UNSERIALIZE_ENUM(_status); - ozoneXC.unserialize(cp, csprintf("%s.xc", section)); - tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); -} - -template <class Impl> -Fault -OzoneCPU<Impl>::copySrcTranslate(Addr src) -{ - panic("Copy not implemented!\n"); - return NoFault; -#if 0 - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - int offset = src & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && - (src >> 40) != 0xfffffc) { - warn("Copied block source spans pages %x.", src); - no_warn = false; - } - - memReq->reset(src & ~(blk_size - 1), blk_size); - - // translate to physical address - Fault fault = xc->translateDataReadReq(memReq); - - assert(fault != Alignment_Fault); - - if (fault == NoFault) { - xc->copySrcAddr = src; - xc->copySrcPhysAddr = memReq->paddr + offset; - } else { - xc->copySrcAddr = 0; - xc->copySrcPhysAddr = 0; - } - return fault; -#endif -} - -template <class Impl> -Fault -OzoneCPU<Impl>::copy(Addr dest) -{ - panic("Copy not implemented!\n"); - return NoFault; -#if 0 - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(xc->copySrcAddr); - int offset = dest & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && - (dest >> 40) != 0xfffffc) { - no_warn = false; - warn("Copied block destination spans pages %x. ", dest); - } - - memReq->reset(dest & ~(blk_size -1), blk_size); - // translate to physical address - Fault fault = xc->translateDataWriteReq(memReq); - - assert(fault != Alignment_Fault); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = xc->copySrcPhysAddr; - xc->mem->read(memReq, data); - memReq->paddr = dest_addr; - xc->mem->write(memReq, data); - if (dcacheInterface) { - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = xc->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - dcacheInterface->access(memReq); - } - } - return fault; -#endif -} - -#if FULL_SYSTEM -template <class Impl> -Addr -OzoneCPU<Impl>::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -#if FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (_status == Idle) { - DPRINTF(IPI,"Suspended Processor awoke\n"); -// thread.activate(); - // Hack for now. Otherwise might have to go through the xcProxy, or - // I need to figure out what's the right thing to call. - activateContext(thread.tid, 1); - } -} -#endif // FULL_SYSTEM - -/* start simulation, program loaded, processor precise state initialized */ -template <class Impl> -void -OzoneCPU<Impl>::tick() -{ - DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n"); - - _status = Running; - thread.renameTable[ZeroReg]->setIntResult(0); - thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]-> - setDoubleResult(0.0); - - comm.advance(); - frontEnd->tick(); - backEnd->tick(); - - // check for instruction-count-based events - comInstEventQueue[0]->serviceEvents(numInst); - - if (!tickEvent.scheduled() && _status == Running) - tickEvent.schedule(curTick + cycles(1)); -} - -template <class Impl> -void -OzoneCPU<Impl>::squashFromXC() -{ - thread.inSyscall = true; - backEnd->generateXCEvent(); -} - -#if !FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::syscall() -{ - // Not sure this copy is needed, depending on how the XC proxy is made. - thread.renameTable.copyFrom(backEnd->renameTable); - - thread.inSyscall = true; - - thread.funcExeInst++; - - DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst); - - thread.process->syscall(xcProxy); - - thread.funcExeInst--; - - thread.inSyscall = false; - - frontEnd->renameTable.copyFrom(thread.renameTable); - backEnd->renameTable.copyFrom(thread.renameTable); -} - -template <class Impl> -void -OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - thread.renameTable[SyscallSuccessReg]->setIntResult(0); - thread.renameTable[ReturnValueReg]->setIntResult( - return_value.value()); - } else { - // got an error, return details - thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1); - thread.renameTable[ReturnValueReg]->setIntResult( - -return_value.value()); - } -} -#else -template <class Impl> -Fault -OzoneCPU<Impl>::hwrei() -{ - // Need to move this to ISA code - // May also need to make this per thread - - lockFlag = false; - lockAddrList.clear(); - thread.kernelStats->hwrei(); - - checkInterrupts = true; - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -void -OzoneCPU<Impl>::processInterrupts() -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - - // Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - checkInterrupts = false; - - if (thread.readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (thread.readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (thread.readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > thread.readMiscReg(IPR_IPLR)) { - thread.setMiscReg(IPR_ISR, summary); - thread.setMiscReg(IPR_INTID, ipl); - // @todo: Make this more transparent - if (checker) { - checker->cpuXCBase()->setMiscReg(IPR_ISR, summary); - checker->cpuXCBase()->setMiscReg(IPR_INTID, ipl); - } - Fault fault = new InterruptFault; - fault->invoke(thread.getXCProxy()); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - thread.readMiscReg(IPR_IPLR), ipl, summary); - } -} - -template <class Impl> -bool -OzoneCPU<Impl>::simPalCheck(int palFunc) -{ - // Need to move this to ISA code - // May also need to make this per thread - thread.kernelStats->callpal(palFunc, xcProxy); - - switch (palFunc) { - case PAL::halt: - haltContext(thread.tid); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (system->breakpoint()) - return false; - break; - } - - return true; -} -#endif - -template <class Impl> -BaseCPU * -OzoneCPU<Impl>::OzoneXC::getCpuPtr() -{ - return cpu; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setCpuId(int id) -{ - cpu->cpuId = id; - thread->cpuId = id; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setStatus(Status new_status) -{ - thread->_status = new_status; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::activate(int delay) -{ - cpu->activateContext(thread->tid, delay); -} - -/// Set the status to Suspended. -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::suspend() -{ - cpu->suspendContext(thread->tid); -} - -/// Set the status to Unallocated. -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::deallocate() -{ - cpu->deallocateContext(thread->tid); -} - -/// Set the status to Halted. -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::halt() -{ - cpu->haltContext(thread->tid); -} - -#if FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::dumpFuncProfile() -{ } -#endif - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::takeOverFrom(ExecContext *old_context) -{ - // some things should already be set up - assert(getMemPtr() == old_context->getMemPtr()); -#if FULL_SYSTEM - assert(getSystemPtr() == old_context->getSystemPtr()); -#else - assert(getProcessPtr() == old_context->getProcessPtr()); -#endif - - // copy over functional state - setStatus(old_context->status()); - copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); - -#if !FULL_SYSTEM - setFuncExeInst(old_context->readFuncExeInst()); -#else - EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); - if (other_quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - other_quiesce->xc = this; - } - if (thread->quiesceEvent) { - thread->quiesceEvent->xc = this; - } - - thread->kernelStats = old_context->getKernelStats(); -// storeCondFailures = 0; - cpu->lockFlag = false; -#endif - - old_context->setStatus(ExecContext::Unallocated); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::regStats(const std::string &name) -{ -#if FULL_SYSTEM - thread->kernelStats = new Kernel::Statistics(cpu->system); - thread->kernelStats->regStats(name + ".kern"); -#endif -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::serialize(std::ostream &os) -{ } - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::unserialize(Checkpoint *cp, const std::string §ion) -{ } - -#if FULL_SYSTEM -template <class Impl> -EndQuiesceEvent * -OzoneCPU<Impl>::OzoneXC::getQuiesceEvent() -{ - return thread->quiesceEvent; -} - -template <class Impl> -Tick -OzoneCPU<Impl>::OzoneXC::readLastActivate() -{ - return thread->lastActivate; -} - -template <class Impl> -Tick -OzoneCPU<Impl>::OzoneXC::readLastSuspend() -{ - return thread->lastSuspend; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::profileClear() -{ - if (thread->profile) - thread->profile->clear(); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::profileSample() -{ - if (thread->profile) - thread->profile->sample(thread->profileNode, thread->profilePC); -} -#endif - -template <class Impl> -int -OzoneCPU<Impl>::OzoneXC::getThreadNum() -{ - return thread->tid; -} - -// Also somewhat obnoxious. Really only used for the TLB fault. -template <class Impl> -TheISA::MachInst -OzoneCPU<Impl>::OzoneXC::getInst() -{ - return thread->inst; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::copyArchRegs(ExecContext *xc) -{ - thread->PC = xc->readPC(); - thread->nextPC = xc->readNextPC(); - - cpu->frontEnd->setPC(thread->PC); - cpu->frontEnd->setNextPC(thread->nextPC); - - for (int i = 0; i < TheISA::TotalNumRegs; ++i) { - if (i < TheISA::FP_Base_DepTag) { - thread->renameTable[i]->setIntResult(xc->readIntReg(i)); - } else if (i < (TheISA::FP_Base_DepTag + TheISA::NumFloatRegs)) { - int fp_idx = i - TheISA::FP_Base_DepTag; - thread->renameTable[i]->setDoubleResult( - xc->readFloatRegDouble(fp_idx)); - } - } - -#if !FULL_SYSTEM - thread->funcExeInst = xc->readFuncExeInst(); -#endif - - // Need to copy the XC values into the current rename table, - // copy the misc regs. - thread->regs.miscRegs.copyMiscRegs(xc); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::clearArchRegs() -{ - panic("Unimplemented!"); -} - -template <class Impl> -uint64_t -OzoneCPU<Impl>::OzoneXC::readIntReg(int reg_idx) -{ - return thread->renameTable[reg_idx]->readIntResult(); -} - -template <class Impl> -float -OzoneCPU<Impl>::OzoneXC::readFloatRegSingle(int reg_idx) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - return thread->renameTable[idx]->readFloatResult(); -} - -template <class Impl> -double -OzoneCPU<Impl>::OzoneXC::readFloatRegDouble(int reg_idx) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - return thread->renameTable[idx]->readDoubleResult(); -} - -template <class Impl> -uint64_t -OzoneCPU<Impl>::OzoneXC::readFloatRegInt(int reg_idx) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - return thread->renameTable[idx]->readIntResult(); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setIntReg(int reg_idx, uint64_t val) -{ - thread->renameTable[reg_idx]->setIntResult(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setFloatRegSingle(int reg_idx, float val) -{ - panic("Unimplemented!"); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setFloatRegDouble(int reg_idx, double val) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - - thread->renameTable[idx]->setDoubleResult(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setFloatRegInt(int reg_idx, uint64_t val) -{ - panic("Unimplemented!"); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setPC(Addr val) -{ - thread->PC = val; - cpu->frontEnd->setPC(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setNextPC(Addr val) -{ - thread->nextPC = val; - cpu->frontEnd->setNextPC(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -TheISA::MiscReg -OzoneCPU<Impl>::OzoneXC::readMiscReg(int misc_reg) -{ - return thread->regs.miscRegs.readReg(misc_reg); -} - -template <class Impl> -TheISA::MiscReg -OzoneCPU<Impl>::OzoneXC::readMiscRegWithEffect(int misc_reg, Fault &fault) -{ - return thread->regs.miscRegs.readRegWithEffect(misc_reg, - fault, this); -} - -template <class Impl> -Fault -OzoneCPU<Impl>::OzoneXC::setMiscReg(int misc_reg, const MiscReg &val) -{ - // Needs to setup a squash event unless we're in syscall mode - Fault ret_fault = thread->regs.miscRegs.setReg(misc_reg, val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } - - return ret_fault; -} - -template <class Impl> -Fault -OzoneCPU<Impl>::OzoneXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) -{ - // Needs to setup a squash event unless we're in syscall mode - Fault ret_fault = thread->regs.miscRegs.setRegWithEffect(misc_reg, val, - this); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } - - return ret_fault; -} diff --git a/cpu/ozone/ea_list.cc b/cpu/ozone/ea_list.cc deleted file mode 100644 index 6114a0ca1..000000000 --- a/cpu/ozone/ea_list.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ooo_cpu/ea_list.hh" - -void -EAList::addAddr(const InstSeqNum &new_sn, const Addr &new_ea) -{ - instEA newEA(new_sn, new_ea); - - eaList.push_back(newEA); -} - -void -EAList::clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear) -{ - eaListIt list_it = eaList.begin(); - - while (list_it != eaList.end() && (*list_it).first != sn_to_clear) { - assert((*list_it).second == ea_to_clear); - } -} - -bool -EAList::checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const -{ - const constEAListIt list_it = eaList.begin(); - - while (list_it != eaList.end() && (*list_it).first < check_sn) { - if ((*list_it).second == check_ea) { - return true; - } - } - - return false; -} - -void -EAList::clear() -{ - eaList.clear(); -} - -void -EAList::commit(const InstSeqNum &commit_sn) -{ - while (!eaList.empty() && eaList.front().first <= commit_sn) { - eaList.pop_front(); - } -} diff --git a/cpu/ozone/ea_list.hh b/cpu/ozone/ea_list.hh deleted file mode 100644 index c0eee4bb8..000000000 --- a/cpu/ozone/ea_list.hh +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_EA_LIST_HH__ -#define __CPU_EA_LIST_HH__ - -#include <list> -#include <utility> - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" - -/** - * Simple class to hold onto a list of pairs, each pair having a memory - * instruction's sequence number and effective addr. This list can be used - * for memory disambiguation. However, if I ever want to forward results, I - * may have to use a list that holds DynInstPtrs. Hence this may change in - * the future. - */ -class EAList { - private: - typedef std::pair<InstSeqNum, Addr> instEA; - typedef std::list<instEA>::iterator eaListIt; - typedef std::list<instEA>::const_iterator constEAListIt; - - std::list<instEA> eaList; - - public: - EAList() { } - ~EAList() { } - - void addAddr(const InstSeqNum &new_sn, const Addr &new_ea); - - void clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear); - - /** Checks if any instructions older than check_sn have a conflicting - * address with check_ea. Note that this function does not handle the - * sequence number rolling over. - */ - bool checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const; - - void clear(); - - void commit(const InstSeqNum &commit_sn); -}; - -#endif // __CPU_EA_LIST_HH__ diff --git a/cpu/pc_event.cc b/cpu/pc_event.cc deleted file mode 100644 index 050bf1a88..000000000 --- a/cpu/pc_event.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <map> -#include <string> -#include <utility> - -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/pc_event.hh" -#include "sim/debug.hh" -#include "sim/root.hh" -#include "sim/system.hh" - -using namespace std; - -PCEventQueue::PCEventQueue() -{} - -PCEventQueue::~PCEventQueue() -{} - -bool -PCEventQueue::remove(PCEvent *event) -{ - int removed = 0; - range_t range = equal_range(event); - for (iterator i = range.first; i != range.second; ++i) { - if (*i == event) { - DPRINTF(PCEvent, "PC based event removed at %#x: %s\n", - event->pc(), event->descr()); - pc_map.erase(i); - ++removed; - } - } - - return removed > 0; -} - -bool -PCEventQueue::schedule(PCEvent *event) -{ - pc_map.push_back(event); - sort(pc_map.begin(), pc_map.end(), MapCompare()); - - DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n", - event->pc(), event->descr()); - - return true; -} - -bool -PCEventQueue::doService(ExecContext *xc) -{ - Addr pc = xc->readPC() & ~0x3; - int serviced = 0; - range_t range = equal_range(pc); - for (iterator i = range.first; i != range.second; ++i) { - // Make sure that the pc wasn't changed as the side effect of - // another event. This for example, prevents two invocations - // of the SkipFuncEvent. Maybe we should have separate PC - // event queues for each processor? - if (pc != (xc->readPC() & ~0x3)) - continue; - - DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n", - (*i)->pc(), (*i)->descr()); - - (*i)->process(xc); - ++serviced; - } - - return serviced > 0; -} - -void -PCEventQueue::dump() const -{ - const_iterator i = pc_map.begin(); - const_iterator e = pc_map.end(); - - for (; i != e; ++i) - cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(), - (*i)->descr()); -} - -PCEventQueue::range_t -PCEventQueue::equal_range(Addr pc) -{ - return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare()); -} - -BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool del) - : PCEvent(q, desc, addr), remove(del) -{ -} - -void -BreakPCEvent::process(ExecContext *xc) -{ - StringWrap name(xc->getCpuPtr()->name() + ".break_event"); - DPRINTFN("break event %s triggered\n", descr()); - debug_break(); - if (remove) - delete this; -} - -#if FULL_SYSTEM -extern "C" -void -sched_break_pc_sys(System *sys, Addr addr) -{ - new BreakPCEvent(&sys->pcEventQueue, "debug break", addr, true); -} - -extern "C" -void -sched_break_pc(Addr addr) -{ - for (vector<System *>::iterator sysi = System::systemList.begin(); - sysi != System::systemList.end(); ++sysi) { - sched_break_pc_sys(*sysi, addr); - } - -} -#endif diff --git a/cpu/pc_event.hh b/cpu/pc_event.hh deleted file mode 100644 index 7fa3902cc..000000000 --- a/cpu/pc_event.hh +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __PC_EVENT_HH__ -#define __PC_EVENT_HH__ - -#include <vector> - -#include "mem/mem_req.hh" - -class ExecContext; -class PCEventQueue; - -class PCEvent -{ - protected: - static const Addr badpc = MemReq::inval_addr; - - protected: - std::string description; - PCEventQueue *queue; - Addr evpc; - - public: - PCEvent(PCEventQueue *q, const std::string &desc, Addr pc); - - virtual ~PCEvent() { if (queue) remove(); } - - // for DPRINTF - virtual const std::string name() const { return description; } - - std::string descr() const { return description; } - Addr pc() const { return evpc; } - - bool remove(); - virtual void process(ExecContext *xc) = 0; -}; - -class PCEventQueue -{ - protected: - typedef PCEvent * record_t; - class MapCompare { - public: - bool operator()(const record_t &l, const record_t &r) const { - return l->pc() < r->pc(); - } - bool operator()(const record_t &l, Addr pc) const { - return l->pc() < pc; - } - bool operator()(Addr pc, const record_t &r) const { - return pc < r->pc(); - } - }; - typedef std::vector<record_t> map_t; - - public: - typedef map_t::iterator iterator; - typedef map_t::const_iterator const_iterator; - - protected: - typedef std::pair<iterator, iterator> range_t; - typedef std::pair<const_iterator, const_iterator> const_range_t; - - protected: - map_t pc_map; - - bool doService(ExecContext *xc); - - public: - PCEventQueue(); - ~PCEventQueue(); - - bool remove(PCEvent *event); - bool schedule(PCEvent *event); - bool service(ExecContext *xc) - { - if (pc_map.empty()) - return false; - - return doService(xc); - } - - range_t equal_range(Addr pc); - range_t equal_range(PCEvent *event) { return equal_range(event->pc()); } - - void dump() const; -}; - - -inline -PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc) - : description(desc), queue(q), evpc(pc) -{ - queue->schedule(this); -} - -inline bool -PCEvent::remove() -{ - if (!queue) - panic("cannot remove an uninitialized event;"); - - return queue->remove(this); -} - -class BreakPCEvent : public PCEvent -{ - protected: - bool remove; - - public: - BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool del = false); - virtual void process(ExecContext *xc); -}; - -#endif // __PC_EVENT_HH__ diff --git a/cpu/profile.cc b/cpu/profile.cc deleted file mode 100644 index fe3458b61..000000000 --- a/cpu/profile.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "base/bitfield.hh" -#include "base/callback.hh" -#include "base/statistics.hh" -#include "base/trace.hh" -#include "base/loader/symtab.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/profile.hh" - -using namespace std; - -ProfileNode::ProfileNode() - : count(0) -{ } - -void -ProfileNode::dump(const string &symbol, uint64_t id, const SymbolTable *symtab, - ostream &os) const -{ - ccprintf(os, "%#x %s %d ", id, symbol, count); - ChildList::const_iterator i, end = children.end(); - for (i = children.begin(); i != end; ++i) { - const ProfileNode *node = i->second; - ccprintf(os, "%#x ", (intptr_t)node); - } - - ccprintf(os, "\n"); - - for (i = children.begin(); i != end; ++i) { - Addr addr = i->first; - string symbol; - if (addr == 1) - symbol = "user"; - else if (addr == 2) - symbol = "console"; - else if (addr == 3) - symbol = "unknown"; - else if (!symtab->findSymbol(addr, symbol)) - panic("could not find symbol for address %#x\n", addr); - - const ProfileNode *node = i->second; - node->dump(symbol, (intptr_t)node, symtab, os); - } -} - -void -ProfileNode::clear() -{ - count = 0; - ChildList::iterator i, end = children.end(); - for (i = children.begin(); i != end; ++i) - i->second->clear(); -} - -FunctionProfile::FunctionProfile(const SymbolTable *_symtab) - : reset(0), symtab(_symtab) -{ - reset = new MakeCallback<FunctionProfile, &FunctionProfile::clear>(this); - Stats::registerResetCallback(reset); -} - -FunctionProfile::~FunctionProfile() -{ - if (reset) - delete reset; -} - -ProfileNode * -FunctionProfile::consume(const vector<Addr> &stack) -{ - ProfileNode *current = ⊤ - for (int i = 0, size = stack.size(); i < size; ++i) { - ProfileNode *&ptr = current->children[stack[size - i - 1]]; - if (ptr == NULL) - ptr = new ProfileNode; - - current = ptr; - } - - return current; -} - -void -FunctionProfile::clear() -{ - top.clear(); - pc_count.clear(); -} - -void -FunctionProfile::dump(ExecContext *xc, ostream &os) const -{ - ccprintf(os, ">>>PC data\n"); - map<Addr, Counter>::const_iterator i, end = pc_count.end(); - for (i = pc_count.begin(); i != end; ++i) { - Addr pc = i->first; - Counter count = i->second; - - std::string symbol; - if (pc == 1) - ccprintf(os, "user %d\n", count); - else if (symtab->findSymbol(pc, symbol) && !symbol.empty()) - ccprintf(os, "%s %d\n", symbol, count); - else - ccprintf(os, "%#x %d\n", pc, count); - } - - ccprintf(os, ">>>function data\n"); - top.dump("top", 0, symtab, os); -} - -void -FunctionProfile::sample(ProfileNode *node, Addr pc) -{ - node->count++; - - Addr symaddr; - if (symtab->findNearestAddr(pc, symaddr)) { - pc_count[symaddr]++; - } else { - // record PC even if we don't have a symbol to avoid - // silently biasing the histogram - pc_count[pc]++; - } -} diff --git a/cpu/profile.hh b/cpu/profile.hh deleted file mode 100644 index d55c9eec9..000000000 --- a/cpu/profile.hh +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_PROFILE_HH__ -#define __CPU_PROFILE_HH__ - -#include <map> - -#include "cpu/static_inst.hh" -#include "sim/host.hh" -#include "arch/stacktrace.hh" - -class ExecContext; - -class ProfileNode -{ - private: - friend class FunctionProfile; - - typedef std::map<Addr, ProfileNode *> ChildList; - ChildList children; - - public: - Counter count; - - public: - ProfileNode(); - - void dump(const std::string &symbol, uint64_t id, - const SymbolTable *symtab, std::ostream &os) const; - void clear(); -}; - -class Callback; -class FunctionProfile -{ - private: - Callback *reset; - const SymbolTable *symtab; - ProfileNode top; - std::map<Addr, Counter> pc_count; - StackTrace trace; - - public: - FunctionProfile(const SymbolTable *symtab); - ~FunctionProfile(); - - ProfileNode *consume(ExecContext *xc, StaticInstPtr inst); - ProfileNode *consume(const std::vector<Addr> &stack); - void clear(); - void dump(ExecContext *xc, std::ostream &out) const; - void sample(ProfileNode *node, Addr pc); -}; - -inline ProfileNode * -FunctionProfile::consume(ExecContext *xc, StaticInstPtr inst) -{ - if (!trace.trace(xc, inst)) - return NULL; - trace.dprintf(); - return consume(trace.getstack()); -} - -#endif // __CPU_PROFILE_HH__ diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc deleted file mode 100644 index c03945ffa..000000000 --- a/cpu/simple/cpu.cc +++ /dev/null @@ -1,955 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cmath> -#include <cstdio> -#include <cstdlib> -#include <iostream> -#include <iomanip> -#include <list> -#include <sstream> -#include <string> - -#include "base/cprintf.hh" -#include "base/inifile.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "base/range.hh" -#include "base/stats/events.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/simple/cpu.hh" -#include "cpu/smt.hh" -#include "cpu/static_inst.hh" -#include "kern/kernel_stats.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "sim/byteswap.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#if FULL_SYSTEM -#include "base/remote_gdb.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#include "arch/tlb.hh" -#include "arch/stacktrace.hh" -#include "arch/vtophys.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#endif // FULL_SYSTEM - -using namespace std; -//The SimpleCPU does alpha only -using namespace AlphaISA; - - -SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) -{ -} - - -void -SimpleCPU::init() -{ - BaseCPU::init(); -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif -} - -void -SimpleCPU::TickEvent::process() -{ - int count = width; - do { - cpu->tick(); - } while (--count > 0 && cpu->status() == Running); -} - -const char * -SimpleCPU::TickEvent::description() -{ - return "SimpleCPU tick event"; -} - - -SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) - : Event(&mainEventQueue), cpu(_cpu) -{ -} - -void SimpleCPU::CacheCompletionEvent::process() -{ - cpu->processCacheCompletion(); -} - -const char * -SimpleCPU::CacheCompletionEvent::description() -{ - return "SimpleCPU cache completion event"; -} - -SimpleCPU::SimpleCPU(Params *p) - : BaseCPU(p), tickEvent(this, p->width), cpuXC(NULL), - cacheCompletionEvent(this) -{ - _status = Idle; -#if FULL_SYSTEM - cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); - -#else - cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, - /* asid */ 0); -#endif // !FULL_SYSTEM - cpuXC->setStatus(ExecContext::Suspended); - xcProxy = cpuXC->getProxy(); - - icacheInterface = p->icache_interface; - dcacheInterface = p->dcache_interface; - - memReq = new MemReq(); - memReq->xc = xcProxy; - memReq->asid = 0; - memReq->data = new uint8_t[64]; - - numInst = 0; - startNumInst = 0; - numLoad = 0; - startNumLoad = 0; - lastIcacheStall = 0; - lastDcacheStall = 0; - - execContexts.push_back(xcProxy); -} - -SimpleCPU::~SimpleCPU() -{ -} - -void -SimpleCPU::switchOut(Sampler *s) -{ - sampler = s; - if (status() == DcacheMissStall) { - DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); - _status = DcacheMissSwitch; - } - else { - _status = SwitchedOut; - - if (tickEvent.scheduled()) - tickEvent.squash(); - - sampler->signalSwitched(); - } -} - - -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); - } - } -} - - -void -SimpleCPU::activateContext(int thread_num, int delay) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Idle || _status == SwitchedOut); - notIdleFraction++; - scheduleTickEvent(delay); - _status = Running; -} - - -void -SimpleCPU::suspendContext(int thread_num) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Running || _status == SwitchedOut); - 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); -} - - -void -SimpleCPU::regStats() -{ - using namespace Stats; - - BaseCPU::regStats(); - - numInsts - .name(name() + ".num_insts") - .desc("Number of instructions executed") - ; - - numMemRefs - .name(name() + ".num_refs") - .desc("Number of memory references") - ; - - notIdleFraction - .name(name() + ".not_idle_fraction") - .desc("Percentage of non-idle cycles") - ; - - idleFraction - .name(name() + ".idle_fraction") - .desc("Percentage of idle cycles") - ; - - icacheStallCycles - .name(name() + ".icache_stall_cycles") - .desc("ICache total stall cycles") - .prereq(icacheStallCycles) - ; - - dcacheStallCycles - .name(name() + ".dcache_stall_cycles") - .desc("DCache total stall cycles") - .prereq(dcacheStallCycles) - ; - - idleFraction = constant(1.0) - notIdleFraction; -} - -void -SimpleCPU::resetStats() -{ - startNumInst = numInst; - notIdleFraction = (_status != Idle); -} - -void -SimpleCPU::serialize(ostream &os) -{ - BaseCPU::serialize(os); - SERIALIZE_ENUM(_status); - SERIALIZE_SCALAR(inst); - nameOut(os, csprintf("%s.xc", name())); - cpuXC->serialize(os); - nameOut(os, csprintf("%s.tickEvent", name())); - tickEvent.serialize(os); - nameOut(os, csprintf("%s.cacheCompletionEvent", name())); - cacheCompletionEvent.serialize(os); -} - -void -SimpleCPU::unserialize(Checkpoint *cp, const string §ion) -{ - BaseCPU::unserialize(cp, section); - UNSERIALIZE_ENUM(_status); - UNSERIALIZE_SCALAR(inst); - cpuXC->unserialize(cp, csprintf("%s.xc", section)); - tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); - cacheCompletionEvent - .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); -} - -void -change_thread_state(int thread_number, int activate, int priority) -{ -} - -Fault -SimpleCPU::copySrcTranslate(Addr src) -{ - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - int offset = src & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (src & PageMask) != ((src + blk_size) & PageMask) && - (src >> 40) != 0xfffffc) { - warn("Copied block source spans pages %x.", src); - no_warn = false; - } - - memReq->reset(src & ~(blk_size - 1), blk_size); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); - - if (fault == NoFault) { - cpuXC->copySrcAddr = src; - cpuXC->copySrcPhysAddr = memReq->paddr + offset; - } else { - assert(!fault->isAlignmentFault()); - - cpuXC->copySrcAddr = 0; - cpuXC->copySrcPhysAddr = 0; - } - return fault; -} - -Fault -SimpleCPU::copy(Addr dest) -{ - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(cpuXC->copySrcAddr); - int offset = dest & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (dest & PageMask) != ((dest + blk_size) & PageMask) && - (dest >> 40) != 0xfffffc) { - no_warn = false; - warn("Copied block destination spans pages %x. ", dest); - } - - memReq->reset(dest & ~(blk_size -1), blk_size); - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = cpuXC->copySrcPhysAddr; - cpuXC->mem->read(memReq, data); - memReq->paddr = dest_addr; - cpuXC->mem->write(memReq, data); - if (dcacheInterface) { - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = cpuXC->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - dcacheInterface->access(memReq); - } - } - else - assert(!fault->isAlignmentFault()); - - return fault; -} - -// precise architected memory state accessor macros -template <class T> -Fault -SimpleCPU::read(Addr addr, T &data, unsigned flags) -{ - if (status() == DcacheMissStall || status() == DcacheMissSwitch) { - Fault fault = cpuXC->read(memReq,data); - - if (traceData) { - traceData->setAddr(memReq->vaddr); - } - return fault; - } - - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); - - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - 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()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } else { - // do functional access - fault = cpuXC->read(memReq, data); - - } - } else if(fault == NoFault) { - // do functional access - fault = cpuXC->read(memReq, data); - - } - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Read"); - - return fault; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -template -Fault -SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -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) -{ - return read(addr, *(uint32_t*)&data, flags); -} - - -template<> -Fault -SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} - - -template <class T> -Fault -SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); - - // do functional access - if (fault == NoFault) - fault = cpuXC->write(memReq, data); - - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Write; - memcpy(memReq->data,(uint8_t *)&data,memReq->size); - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - 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()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } - } - - if (res && (fault == NoFault)) - *res = memReq->result; - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Write"); - - return fault; -} - - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template -Fault -SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint64_t*)&data, addr, flags, res); -} - -template<> -Fault -SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint32_t*)&data, addr, flags, res); -} - - -template<> -Fault -SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); -} - - -#if FULL_SYSTEM -Addr -SimpleCPU::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -void -SimpleCPU::processCacheCompletion() -{ - switch (status()) { - case IcacheMissStall: - icacheStallCycles += curTick - lastIcacheStall; - _status = IcacheMissComplete; - scheduleTickEvent(1); - break; - case DcacheMissStall: - if (memReq->cmd.isRead()) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - dcacheStallCycles += curTick - lastDcacheStall; - _status = Running; - scheduleTickEvent(1); - break; - case DcacheMissSwitch: - if (memReq->cmd.isRead()) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - _status = SwitchedOut; - sampler->signalSwitched(); - 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; - } -} - -#if FULL_SYSTEM -void -SimpleCPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (cpuXC->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - cpuXC->activate(); - } -} -#endif // FULL_SYSTEM - -/* start simulation, program loaded, processor precise state initialized */ -void -SimpleCPU::tick() -{ - numCycles++; - - traceData = NULL; - - Fault fault = NoFault; - -#if FULL_SYSTEM - if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode() && - status() != IcacheMissComplete) { - int ipl = 0; - int summary = 0; - checkInterrupts = false; - - if (cpuXC->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpuXC->cpu->intr_status(); - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - - if (cpuXC->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) { - cpuXC->setMiscReg(IPR_ISR, summary); - cpuXC->setMiscReg(IPR_INTID, ipl); - - Fault(new InterruptFault)->invoke(xcProxy); - - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - cpuXC->readMiscReg(IPR_IPLR), ipl, summary); - } - } -#endif - - // maintain $r0 semantics - cpuXC->setIntReg(ZeroReg, 0); -#ifdef TARGET_ALPHA - cpuXC->setFloatRegDouble(ZeroReg, 0.0); -#endif // TARGET_ALPHA - - if (status() == IcacheMissComplete) { - // We've already fetched an instruction and were stalled on an - // I-cache miss. No need to fetch it again. - - // Set status to running; tick event will get rescheduled if - // necessary at end of tick() function. - _status = Running; - } - else { - // Try to fetch an instruction - - // set up memory request for instruction fetch -#if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 -#else -#define IFETCH_FLAGS(pc) 0 -#endif - - memReq->cmd = Read; - memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), - IFETCH_FLAGS(cpuXC->readPC())); - - fault = cpuXC->translateInstReq(memReq); - - if (fault == NoFault) - fault = cpuXC->mem->read(memReq, inst); - - if (icacheInterface && fault == NoFault) { - memReq->completionEvent = NULL; - - memReq->time = curTick; - memReq->flags |= INST_READ; - 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()) { - memReq->completionEvent = &cacheCompletionEvent; - lastIcacheStall = curTick; - unscheduleTickEvent(); - _status = IcacheMissStall; - return; - } - } - } - - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. - if (fault == NoFault) { - - // keep an instruction count - numInst++; - numInsts++; - - // check for instruction-count-based events - comInstEventQueue[0]->serviceEvents(numInst); - - // decode the instruction - inst = gtoh(inst); - curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC())); - - traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst, - cpuXC->readPC()); - -#if FULL_SYSTEM - cpuXC->setInst(inst); -#endif // FULL_SYSTEM - - cpuXC->func_exe_inst++; - - fault = curStaticInst->execute(this, traceData); - -#if FULL_SYSTEM - if (system->kernelBinning->fnbin) { - assert(cpuXC->getKernelStats()); - system->kernelBinning->execute(xcProxy, inst); - } - - if (cpuXC->profile) { - bool usermode = - (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - cpuXC->profilePC = usermode ? 1 : cpuXC->readPC(); - ProfileNode *node = cpuXC->profile->consume(xcProxy, inst); - if (node) - cpuXC->profileNode = node; - } -#endif - - if (curStaticInst->isMemRef()) { - numMemRefs++; - } - - if (curStaticInst->isLoad()) { - ++numLoad; - comLoadEventQueue[0]->serviceEvents(numLoad); - } - - // If we have a dcache miss, then we can't finialize the instruction - // trace yet because we want to populate it with the data later - if (traceData && - !(status() == DcacheMissStall && memReq->cmd.isRead())) { - traceData->finalize(); - } - - traceFunctions(cpuXC->readPC()); - - } // if (fault == NoFault) - - if (fault != NoFault) { -#if FULL_SYSTEM - fault->invoke(xcProxy); -#else // !FULL_SYSTEM - fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC()); -#endif // FULL_SYSTEM - } - else { -#if THE_ISA != MIPS_ISA - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); -#else - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextNPC()); - cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); -#endif - - } - -#if FULL_SYSTEM - Addr oldpc; - do { - oldpc = cpuXC->readPC(); - system->pcEventQueue.service(xcProxy); - } while (oldpc != cpuXC->readPC()); -#endif - - assert(status() == Running || - status() == Idle || - status() == DcacheMissStall); - - if (status() == Running && !tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); -} - -//////////////////////////////////////////////////////////////////////// -// -// SimpleCPU Simulation Object -// -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - - Param<Counter> max_insts_any_thread; - Param<Counter> max_insts_all_threads; - Param<Counter> max_loads_any_thread; - Param<Counter> max_loads_all_threads; - -#if FULL_SYSTEM - SimObjectParam<AlphaITB *> itb; - SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; - SimObjectParam<System *> system; - Param<int> cpu_id; - Param<Tick> profile; -#else - SimObjectParam<Process *> workload; -#endif // FULL_SYSTEM - - Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - - Param<bool> defer_registration; - Param<int> width; - Param<bool> function_trace; - Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - INIT_PARAM(max_insts_any_thread, - "terminate when any thread reaches this inst count"), - INIT_PARAM(max_insts_all_threads, - "terminate when all threads have reached this inst count"), - INIT_PARAM(max_loads_any_thread, - "terminate when any thread reaches this load count"), - INIT_PARAM(max_loads_all_threads, - "terminate when all threads have reached this load count"), - -#if FULL_SYSTEM - INIT_PARAM(itb, "Instruction TLB"), - INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(profile, ""), -#else - INIT_PARAM(workload, "processes to run"), -#endif // FULL_SYSTEM - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - INIT_PARAM(width, "cpu width"), - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - -CREATE_SIM_OBJECT(SimpleCPU) -{ - SimpleCPU::Params *params = new SimpleCPU::Params(); - params->name = getInstanceName(); - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->deferRegistration = defer_registration; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->icache_interface = (icache) ? icache->getInterface() : NULL; - params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; - params->width = width; - -#if FULL_SYSTEM - params->itb = itb; - params->dtb = dtb; - params->mem = mem; - params->system = system; - params->cpu_id = cpu_id; - params->profile = profile; -#else - params->process = workload; -#endif - - SimpleCPU *cpu = new SimpleCPU(params); - return cpu; -} - -REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) - diff --git a/cpu/simple/cpu.hh b/cpu/simple/cpu.hh deleted file mode 100644 index 4ab9a1c3e..000000000 --- a/cpu/simple/cpu.hh +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ -#define __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/pc_event.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/static_inst.hh" -#include "sim/eventq.hh" - -// forward declarations -#if FULL_SYSTEM -class Processor; -class AlphaITB; -class AlphaDTB; -class PhysicalMemory; - -class RemoteGDB; -class GDBListener; - -#else - -class Process; - -#endif // FULL_SYSTEM - -class ExecContext; -class MemInterface; -class Checkpoint; - -namespace Trace { - class InstRecord; -} - -class SimpleCPU : public BaseCPU -{ - protected: - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscReg MiscReg; - public: - // main simulation loop (one cycle) - void tick(); - virtual void init(); - - private: - struct TickEvent : public Event - { - SimpleCPU *cpu; - int width; - - TickEvent(SimpleCPU *c, int w); - void process(); - const char *description(); - }; - - TickEvent tickEvent; - - /// Schedule tick event, regardless of its current state. - void scheduleTickEvent(int numCycles) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(numCycles)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(numCycles)); - } - - /// Unschedule tick event, regardless of its current state. - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - private: - Trace::InstRecord *traceData; - - public: - // - enum Status { - Running, - Idle, - IcacheMissStall, - IcacheMissComplete, - DcacheMissStall, - DcacheMissSwitch, - SwitchedOut - }; - - private: - Status _status; - - public: - void post_interrupt(int int_num, int index); - - void zero_fill_64(Addr addr) { - static int warned = 0; - if (!warned) { - warn ("WH64 is not implemented"); - warned = 1; - } - }; - - public: - struct Params : public BaseCPU::Params - { - MemInterface *icache_interface; - MemInterface *dcache_interface; - int width; -#if FULL_SYSTEM - AlphaITB *itb; - AlphaDTB *dtb; - FunctionalMemory *mem; -#else - Process *process; -#endif - }; - SimpleCPU(Params *params); - virtual ~SimpleCPU(); - - public: - // execution context - CPUExecContext *cpuXC; - - ExecContext *xcProxy; - - void switchOut(Sampler *s); - void takeOverFrom(BaseCPU *oldCPU); - -#if FULL_SYSTEM - Addr dbg_vtophys(Addr addr); - - bool interval_stats; -#endif - - // L1 instruction cache - MemInterface *icacheInterface; - - // L1 data cache - MemInterface *dcacheInterface; - - // current instruction - MachInst inst; - - // Refcounted pointer to the one memory request. - MemReqPtr memReq; - - // Pointer to the sampler that is telling us to switchover. - // Used to signal the completion of the pipe drain and schedule - // the next switchover - Sampler *sampler; - - StaticInstPtr curStaticInst; - - class CacheCompletionEvent : public Event - { - private: - SimpleCPU *cpu; - - public: - CacheCompletionEvent(SimpleCPU *_cpu); - - virtual void process(); - virtual const char *description(); - }; - - CacheCompletionEvent cacheCompletionEvent; - - Status status() const { return _status; } - - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); - virtual void deallocateContext(int thread_num); - virtual void haltContext(int thread_num); - - // statistics - virtual void regStats(); - virtual void resetStats(); - - // number of simulated instructions - Counter numInst; - Counter startNumInst; - Stats::Scalar<> numInsts; - - virtual Counter totalInstructions() const - { - return numInst - startNumInst; - } - - // number of simulated memory references - Stats::Scalar<> numMemRefs; - - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - // number of idle cycles - Stats::Average<> notIdleFraction; - Stats::Formula idleFraction; - - // number of cycles stalled for I-cache misses - Stats::Scalar<> icacheStallCycles; - Counter lastIcacheStall; - - // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; - - void processCacheCompletion(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - - // These functions are only used in CPU models that split - // effective address computation from the actual memory access. - void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } - - void prefetch(Addr addr, unsigned flags) - { - // need to do this... - } - - void writeHint(Addr addr, int size, unsigned flags) - { - // need to do this... - } - - Fault copySrcTranslate(Addr src); - - Fault copy(Addr dest); - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntReg(const StaticInst *si, int idx) - { - return cpuXC->readIntReg(si->srcRegIdx(idx)); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegSingle(reg_idx); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegDouble(reg_idx); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegInt(reg_idx); - } - - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - cpuXC->setIntReg(si->destRegIdx(idx), val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegSingle(reg_idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegDouble(reg_idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegInt(reg_idx, val); - } - - uint64_t readPC() { return cpuXC->readPC(); } - void setNextPC(uint64_t val) { cpuXC->setNextPC(val); } - - MiscReg readMiscReg(int misc_reg) - { - return cpuXC->readMiscReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return cpuXC->readMiscRegWithEffect(misc_reg, fault); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return cpuXC->setMiscReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return cpuXC->setMiscRegWithEffect(misc_reg, val); - } - -#if FULL_SYSTEM - Fault hwrei() { return cpuXC->hwrei(); } - int readIntrFlag() { return cpuXC->readIntrFlag(); } - void setIntrFlag(int val) { cpuXC->setIntrFlag(val); } - bool inPalMode() { return cpuXC->inPalMode(); } - void ev5_trap(Fault fault) { fault->invoke(xcProxy); } - bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); } -#else - void syscall() { cpuXC->syscall(); } -#endif - - bool misspeculating() { return cpuXC->misspeculating(); } - ExecContext *xcBase() { return xcProxy; } -}; - -#endif // __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ diff --git a/cpu/smt.hh b/cpu/smt.hh deleted file mode 100644 index 9c52abf95..000000000 --- a/cpu/smt.hh +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Defines SMT_MAX_THREADS. - */ - -#ifndef __SMT_HH__ -#define __SMT_HH__ - -#ifndef SMT_MAX_THREADS -/** The number of TPUs in any processor. */ -#define SMT_MAX_THREADS 4 -#endif - -/** - * The maximum number of active threads across all cpus. Used to - * initialize per-thread statistics in the cache. - * - * NB: Be careful to only use it once all the CPUs that you care about - * have been initialized - */ -extern int maxThreadsPerCPU; - -/** - * Changes the status and priority of the thread with the given number. - * @param thread_number The thread to change. - * @param activate The new active status. - * @param priority The new priority. - */ -void change_thread_state(int thread_number, int activate, int priority); - -#endif // __SMT_HH__ diff --git a/cpu/static_inst.cc b/cpu/static_inst.cc deleted file mode 100644 index c307dc6fc..000000000 --- a/cpu/static_inst.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include "cpu/static_inst.hh" -#include "sim/root.hh" - -StaticInstPtr StaticInst::nullStaticInstPtr; - -// Define the decode cache hash map. -StaticInst::DecodeCache StaticInst::decodeCache; - -void -StaticInst::dumpDecodeCacheStats() -{ - using namespace std; - - cerr << "Decode hash table stats @ " << curTick << ":" << endl; - cerr << "\tnum entries = " << decodeCache.size() << endl; - cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl; - vector<int> hist(100, 0); - int max_hist = 0; - for (int i = 0; i < decodeCache.bucket_count(); ++i) { - int count = decodeCache.elems_in_bucket(i); - if (count > max_hist) - max_hist = count; - hist[count]++; - } - for (int i = 0; i <= max_hist; ++i) { - cerr << "\tbuckets of size " << i << " = " << hist[i] << endl; - } -} - -bool -StaticInst::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const -{ - if (isDirectCtrl()) { - tgt = branchTarget(pc); - return true; - } - - if (isIndirectCtrl()) { - tgt = branchTarget(xc); - return true; - } - - return false; -} - diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh deleted file mode 100644 index b9d782b7b..000000000 --- a/cpu/static_inst.hh +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_STATIC_INST_HH__ -#define __CPU_STATIC_INST_HH__ - -#include <bitset> -#include <string> - -#include "base/hashmap.hh" -#include "base/refcnt.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "sim/host.hh" -#include "arch/isa_traits.hh" - -// forward declarations -struct AlphaSimpleImpl; -struct OzoneImpl; -struct SimpleImpl; -class ExecContext; -class DynInst; - -template <class Impl> -class AlphaDynInst; - -template <class Impl> -class OzoneDynInst; - -class CheckerCPU; -class FastCPU; -class SimpleCPU; -class InorderCPU; -class SymbolTable; - -namespace Trace { - class InstRecord; -} - -/** - * Base, ISA-independent static instruction class. - * - * The main component of this class is the vector of flags and the - * associated methods for reading them. Any object that can rely - * solely on these flags can process instructions without being - * recompiled for multiple ISAs. - */ -class StaticInstBase : public RefCounted -{ - protected: - - /// Set of boolean static instruction properties. - /// - /// Notes: - /// - The IsInteger and IsFloating flags are based on the class of - /// registers accessed by the instruction. Although most - /// instructions will have exactly one of these two flags set, it - /// is possible for an instruction to have neither (e.g., direct - /// unconditional branches, memory barriers) or both (e.g., an - /// FP/int conversion). - /// - If IsMemRef is set, then exactly one of IsLoad or IsStore - /// will be set. - /// - If IsControl is set, then exactly one of IsDirectControl or - /// IsIndirect Control will be set, and exactly one of - /// IsCondControl or IsUncondControl will be set. - /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are - /// implemented as flags since in the current model there's no - /// other way for instructions to inject behavior into the - /// pipeline outside of fetch. Once we go to an exec-in-exec CPU - /// model we should be able to get rid of these flags and - /// implement this behavior via the execute() methods. - /// - enum Flags { - IsNop, ///< Is a no-op (no effect at all). - - IsInteger, ///< References integer regs. - IsFloating, ///< References FP regs. - - IsMemRef, ///< References memory (load, store, or prefetch). - IsLoad, ///< Reads from memory (load or prefetch). - IsStore, ///< Writes to memory. - IsStoreConditional, ///< Store conditional instruction. - IsInstPrefetch, ///< Instruction-cache prefetch. - IsDataPrefetch, ///< Data-cache prefetch. - IsCopy, ///< Fast Cache block copy - - IsControl, ///< Control transfer instruction. - IsDirectControl, ///< PC relative control transfer. - IsIndirectControl, ///< Register indirect control transfer. - IsCondControl, ///< Conditional control transfer. - IsUncondControl, ///< Unconditional control transfer. - IsCall, ///< Subroutine call. - IsReturn, ///< Subroutine return. - - IsCondDelaySlot,///< Conditional Delay-Slot Instruction - - IsThreadSync, ///< Thread synchronization operation. - - IsSerializing, ///< Serializes pipeline: won't execute until all - /// older instructions have committed. - IsSerializeBefore, - IsSerializeAfter, - IsMemBarrier, ///< Is a memory barrier - IsWriteBarrier, ///< Is a write barrier - - IsNonSpeculative, ///< Should not be executed speculatively - IsQuiesce, ///< Is a quiesce instruction - - IsIprAccess, ///< Accesses IPRs - IsUnverifiable, ///< Can't be verified by a checker - - NumFlags - }; - - /// Flag values for this instruction. - std::bitset<NumFlags> flags; - - /// See opClass(). - OpClass _opClass; - - /// See numSrcRegs(). - int8_t _numSrcRegs; - - /// See numDestRegs(). - int8_t _numDestRegs; - - /// The following are used to track physical register usage - /// for machines with separate int & FP reg files. - //@{ - int8_t _numFPDestRegs; - int8_t _numIntDestRegs; - //@} - - /// Constructor. - /// It's important to initialize everything here to a sane - /// default, since the decoder generally only overrides - /// the fields that are meaningful for the particular - /// instruction. - StaticInstBase(OpClass __opClass) - : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0), - _numFPDestRegs(0), _numIntDestRegs(0) - { - } - - public: - - /// @name Register information. - /// The sum of numFPDestRegs() and numIntDestRegs() equals - /// numDestRegs(). The former two functions are used to track - /// physical register usage for machines with separate int & FP - /// reg files. - //@{ - /// Number of source registers. - int8_t numSrcRegs() const { return _numSrcRegs; } - /// Number of destination registers. - int8_t numDestRegs() const { return _numDestRegs; } - /// Number of floating-point destination regs. - int8_t numFPDestRegs() const { return _numFPDestRegs; } - /// Number of integer destination regs. - int8_t numIntDestRegs() const { return _numIntDestRegs; } - //@} - - /// @name Flag accessors. - /// These functions are used to access the values of the various - /// instruction property flags. See StaticInstBase::Flags for descriptions - /// of the individual flags. - //@{ - - bool isNop() const { return flags[IsNop]; } - - bool isMemRef() const { return flags[IsMemRef]; } - bool isLoad() const { return flags[IsLoad]; } - bool isStore() const { return flags[IsStore]; } - bool isStoreConditional() const { return flags[IsStoreConditional]; } - bool isInstPrefetch() const { return flags[IsInstPrefetch]; } - bool isDataPrefetch() const { return flags[IsDataPrefetch]; } - bool isCopy() const { return flags[IsCopy];} - - bool isInteger() const { return flags[IsInteger]; } - bool isFloating() const { return flags[IsFloating]; } - - bool isControl() const { return flags[IsControl]; } - bool isCall() const { return flags[IsCall]; } - bool isReturn() const { return flags[IsReturn]; } - bool isDirectCtrl() const { return flags[IsDirectControl]; } - bool isIndirectCtrl() const { return flags[IsIndirectControl]; } - bool isCondCtrl() const { return flags[IsCondControl]; } - bool isUncondCtrl() const { return flags[IsUncondControl]; } - - bool isThreadSync() const { return flags[IsThreadSync]; } - bool isSerializing() const { return flags[IsSerializing] || - flags[IsSerializeBefore] || - flags[IsSerializeAfter]; } - bool isSerializeBefore() const { return flags[IsSerializeBefore]; } - bool isSerializeAfter() const { return flags[IsSerializeAfter]; } - bool isMemBarrier() const { return flags[IsMemBarrier]; } - bool isWriteBarrier() const { return flags[IsWriteBarrier]; } - bool isNonSpeculative() const { return flags[IsNonSpeculative]; } - bool isQuiesce() const { return flags[IsQuiesce]; } - bool isIprAccess() const { return flags[IsIprAccess]; } - bool isUnverifiable() const { return flags[IsUnverifiable]; } - //@} - - /// Operation class. Used to select appropriate function unit in issue. - OpClass opClass() const { return _opClass; } -}; - - -// forward declaration -class StaticInstPtr; - -/** - * Generic yet ISA-dependent static instruction class. - * - * This class builds on StaticInstBase, defining fields and interfaces - * that are generic across all ISAs but that differ in details - * according to the specific ISA being used. - */ -class StaticInst : public StaticInstBase -{ - public: - - /// Binary machine instruction type. - typedef TheISA::MachInst MachInst; - /// Binary extended machine instruction type. - typedef TheISA::ExtMachInst ExtMachInst; - /// Logical register index type. - typedef TheISA::RegIndex RegIndex; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - - /// Return logical index (architectural reg num) of i'th destination reg. - /// Only the entries from 0 through numDestRegs()-1 are valid. - RegIndex destRegIdx(int i) const { return _destRegIdx[i]; } - - /// Return logical index (architectural reg num) of i'th source reg. - /// Only the entries from 0 through numSrcRegs()-1 are valid. - RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; } - - /// Pointer to a statically allocated "null" instruction object. - /// Used to give eaCompInst() and memAccInst() something to return - /// when called on non-memory instructions. - static StaticInstPtr nullStaticInstPtr; - - /** - * Memory references only: returns "fake" instruction representing - * the effective address part of the memory operation. Used to - * obtain the dependence info (numSrcRegs and srcRegIdx[]) for - * just the EA computation. - */ - virtual const - StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; } - - /** - * Memory references only: returns "fake" instruction representing - * the memory access part of the memory operation. Used to - * obtain the dependence info (numSrcRegs and srcRegIdx[]) for - * just the memory access (not the EA computation). - */ - virtual const - StaticInstPtr &memAccInst() const { return nullStaticInstPtr; } - - /// The binary machine instruction. - const ExtMachInst machInst; - - protected: - - /// See destRegIdx(). - RegIndex _destRegIdx[MaxInstDestRegs]; - /// See srcRegIdx(). - RegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** - * Base mnemonic (e.g., "add"). Used by generateDisassembly() - * methods. Also useful to readily identify instructions from - * within the debugger when #cachedDisassembly has not been - * initialized. - */ - const char *mnemonic; - - /** - * String representation of disassembly (lazily evaluated via - * disassemble()). - */ - mutable std::string *cachedDisassembly; - - /** - * Internal function to generate disassembly string. - */ - virtual std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0; - - /// Constructor. - StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass) - : StaticInstBase(__opClass), - machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0) - { - } - - public: - - virtual ~StaticInst() - { - if (cachedDisassembly) - delete cachedDisassembly; - } - -/** - * The execute() signatures are auto-generated by scons based on the - * set of CPU models we are compiling in today. - */ -#include "cpu/static_inst_exec_sigs.hh" - - /** - * Return the target address for a PC-relative branch. - * Invalid if not a PC-relative branch (i.e. isDirectCtrl() - * should be true). - */ - virtual Addr branchTarget(Addr branchPC) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not a PC-relative branch."); - } - - /** - * Return the target address for an indirect branch (jump). The - * register value is read from the supplied execution context, so - * the result is valid only if the execution context is about to - * execute the branch in question. Invalid if not an indirect - * branch (i.e. isIndirectCtrl() should be true). - */ - virtual Addr branchTarget(ExecContext *xc) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not an indirect branch."); - } - - /** - * Return true if the instruction is a control transfer, and if so, - * return the target address as well. - */ - bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const; - - /** - * Return string representation of disassembled instruction. - * The default version of this function will call the internal - * virtual generateDisassembly() function to get the string, - * then cache it in #cachedDisassembly. If the disassembly - * should not be cached, this function should be overridden directly. - */ - virtual const std::string &disassemble(Addr pc, - const SymbolTable *symtab = 0) const - { - if (!cachedDisassembly) - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - - return *cachedDisassembly; - } - - /// Decoded instruction cache type. - /// For now we're using a generic hash_map; this seems to work - /// pretty well. - typedef m5::hash_map<ExtMachInst, StaticInstPtr> DecodeCache; - - /// A cache of decoded instruction objects. - static DecodeCache decodeCache; - - /** - * Dump some basic stats on the decode cache hash map. - * Only gets called if DECODE_CACHE_HASH_STATS is defined. - */ - static void dumpDecodeCacheStats(); - - /// Decode a machine instruction. - /// @param mach_inst The binary instruction to decode. - /// @retval A pointer to the corresponding StaticInst object. - //This is defined as inline below. - static StaticInstPtr decode(ExtMachInst mach_inst); -}; - -typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; - -/// Reference-counted pointer to a StaticInst object. -/// This type should be used instead of "StaticInst *" so that -/// StaticInst objects can be properly reference-counted. -class StaticInstPtr : public RefCountingPtr<StaticInst> -{ - public: - /// Constructor. - StaticInstPtr() - : RefCountingPtr<StaticInst>() - { - } - - /// Conversion from "StaticInst *". - StaticInstPtr(StaticInst *p) - : RefCountingPtr<StaticInst>(p) - { - } - - /// Copy constructor. - StaticInstPtr(const StaticInstPtr &r) - : RefCountingPtr<StaticInst>(r) - { - } - - /// Construct directly from machine instruction. - /// Calls StaticInst::decode(). - StaticInstPtr(TheISA::ExtMachInst mach_inst) - : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst)) - { - } - - /// Convert to pointer to StaticInstBase class. - operator const StaticInstBasePtr() - { - return this->get(); - } -}; - -inline StaticInstPtr -StaticInst::decode(StaticInst::ExtMachInst mach_inst) -{ -#ifdef DECODE_CACHE_HASH_STATS - // Simple stats on decode hash_map. Turns out the default - // hash function is as good as anything I could come up with. - const int dump_every_n = 10000000; - static int decodes_til_dump = dump_every_n; - - if (--decodes_til_dump == 0) { - dumpDecodeCacheStats(); - decodes_til_dump = dump_every_n; - } -#endif - - DecodeCache::iterator iter = decodeCache.find(mach_inst); - if (iter != decodeCache.end()) { - return iter->second; - } - - StaticInstPtr si = TheISA::decodeInst(mach_inst); - decodeCache[mach_inst] = si; - return si; -} - -#endif // __CPU_STATIC_INST_HH__ diff --git a/cpu/trace/opt_cpu.cc b/cpu/trace/opt_cpu.cc deleted file mode 100644 index 6cd23b0dd..000000000 --- a/cpu/trace/opt_cpu.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a memory trace CPU object for optimal caches. Uses a memory - * trace to access a fully associative cache with optimal replacement. - */ - -#include <algorithm> // For heap functions. - -#include "cpu/trace/opt_cpu.hh" -#include "cpu/trace/reader/mem_trace_reader.hh" - -#include "sim/builder.hh" -#include "sim/sim_events.hh" - -using namespace std; - -OptCPU::OptCPU(const string &name, - MemTraceReader *_trace, - int block_size, - int cache_size, - int _assoc) - : SimObject(name), tickEvent(this), trace(_trace), - numBlks(cache_size/block_size), assoc(_assoc), numSets(numBlks/assoc), - setMask(numSets - 1) -{ - int log_block_size = 0; - int tmp_block_size = block_size; - while (tmp_block_size > 1) { - ++log_block_size; - tmp_block_size = tmp_block_size >> 1; - } - assert(1<<log_block_size == block_size); - MemReqPtr req; - trace->getNextReq(req); - refInfo.resize(numSets); - while (req) { - RefInfo temp; - temp.addr = req->paddr >> log_block_size; - int set = temp.addr & setMask; - refInfo[set].push_back(temp); - trace->getNextReq(req); - } - - // Initialize top level of lookup table. - lookupTable.resize(16); - - // Annotate references with next ref time. - for (int k = 0; k < numSets; ++k) { - for (RefIndex i = refInfo[k].size() - 1; i >= 0; --i) { - Addr addr = refInfo[k][i].addr; - initTable(addr, InfiniteRef); - refInfo[k][i].nextRefTime = lookupValue(addr); - setValue(addr, i); - } - } - - // Reset the lookup table - for (int j = 0; j < 16; ++j) { - if (lookupTable[j].size() == (1<<16)) { - for (int k = 0; k < (1<<16); ++k) { - if (lookupTable[j][k].size() == (1<<16)) { - for (int l = 0; l < (1<<16); ++l) { - lookupTable[j][k][l] = -1; - } - } - } - } - } - - tickEvent.schedule(0); - - hits = 0; - misses = 0; -} - -void -OptCPU::processSet(int set) -{ - // Initialize cache - int blks_in_cache = 0; - RefIndex i = 0; - cacheHeap.clear(); - cacheHeap.resize(assoc); - - while (blks_in_cache < assoc) { - RefIndex cache_index = lookupValue(refInfo[set][i].addr); - if (cache_index == -1) { - // First reference to this block - misses++; - cache_index = blks_in_cache++; - setValue(refInfo[set][i].addr, cache_index); - } else { - hits++; - } - // update cache heap to most recent reference - cacheHeap[cache_index] = i; - if (++i >= refInfo[set].size()) { - return; - } - } - for (int start = assoc/2; start >= 0; --start) { - heapify(set,start); - } - //verifyHeap(set,0); - - for (; i < refInfo[set].size(); ++i) { - RefIndex cache_index = lookupValue(refInfo[set][i].addr); - if (cache_index == -1) { - // miss - misses++; - // replace from cacheHeap[0] - // mark replaced block as absent - setValue(refInfo[set][cacheHeap[0]].addr, -1); - setValue(refInfo[set][i].addr, 0); - cacheHeap[0] = i; - heapify(set, 0); - // Make sure its in the cache - assert(lookupValue(refInfo[set][i].addr) != -1); - } else { - // hit - hits++; - assert(refInfo[set][cacheHeap[cache_index]].addr == - refInfo[set][i].addr); - assert(refInfo[set][cacheHeap[cache_index]].nextRefTime == i); - assert(heapLeft(cache_index) >= assoc); - - cacheHeap[cache_index] = i; - processRankIncrease(set, cache_index); - assert(lookupValue(refInfo[set][i].addr) != -1); - } - } -} -void -OptCPU::tick() -{ - // Do opt simulation - - int references = 0; - for (int set = 0; set < numSets; ++set) { - if (!refInfo[set].empty()) { - processSet(set); - } - references += refInfo[set].size(); - } - // exit; - fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses); - fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits); - fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references); - new SimExitEvent("Finshed Memory Trace"); -} - -void -OptCPU::initTable(Addr addr, RefIndex index) -{ - int l1_index = (addr >> 32) & 0x0f; - int l2_index = (addr >> 16) & 0xffff; - assert(l1_index == addr >> 32); - if (lookupTable[l1_index].size() != (1<<16)) { - lookupTable[l1_index].resize(1<<16); - } - if (lookupTable[l1_index][l2_index].size() != (1<<16)) { - lookupTable[l1_index][l2_index].resize(1<<16, index); - } -} - -OptCPU::TickEvent::TickEvent(OptCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -void -OptCPU::TickEvent::process() -{ - cpu->tick(); -} - -const char * -OptCPU::TickEvent::description() -{ - return "OptCPU tick event"; -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(OptCPU) - - SimObjectParam<MemTraceReader *> data_trace; - Param<int> size; - Param<int> block_size; -Param<int> assoc; - -END_DECLARE_SIM_OBJECT_PARAMS(OptCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(OptCPU) - - INIT_PARAM_DFLT(data_trace, "memory trace", NULL), - INIT_PARAM(size, "cache size"), - INIT_PARAM(block_size, "block size"), - INIT_PARAM(assoc,"associativity") - -END_INIT_SIM_OBJECT_PARAMS(OptCPU) - -CREATE_SIM_OBJECT(OptCPU) -{ - return new OptCPU(getInstanceName(), - data_trace, - block_size, - size, - assoc); -} - -REGISTER_SIM_OBJECT("OptCPU", OptCPU) diff --git a/cpu/trace/opt_cpu.hh b/cpu/trace/opt_cpu.hh deleted file mode 100644 index f81691733..000000000 --- a/cpu/trace/opt_cpu.hh +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace CPU object for optimal caches. Uses a memory - * trace to access a fully associative cache with optimal replacement. - */ - -#ifndef __CPU_TRACE_OPT_CPU_HH__ -#define __CPU_TRACE_OPT_CPU_HH__ - -#include <vector> - -#include "mem/mem_req.hh" // for MemReqPtr -#include "sim/eventq.hh" // for Event -#include "sim/sim_object.hh" - -// Forward Declaration -class MemTraceReader; - -/** - * A CPU object to simulate a fully-associative cache with optimal replacement. - */ -class OptCPU : public SimObject -{ - private: - typedef int RefIndex; - - typedef std::vector<RefIndex> L3Table; - typedef std::vector<L3Table> L2Table; - typedef std::vector<L2Table> L1Table; - - /** - * Event to call OptCPU::tick - */ - class TickEvent : public Event - { - private: - /** The associated CPU */ - OptCPU *cpu; - - public: - /** - * Construct this event; - */ - TickEvent(OptCPU *c); - - /** - * Call the tick function. - */ - void process(); - - /** - * Return a string description of this event. - */ - const char *description(); - }; - - TickEvent tickEvent; - - class RefInfo - { - public: - RefIndex nextRefTime; - Addr addr; - }; - - /** Reference Information, per set. */ - std::vector<std::vector<RefInfo> > refInfo; - - /** Lookup table to track blocks in the cache heap */ - L1Table lookupTable; - - /** - * Return the correct value in the lookup table. - */ - RefIndex lookupValue(Addr addr) - { - int l1_index = (addr >> 32) & 0x0f; - int l2_index = (addr >> 16) & 0xffff; - int l3_index = addr & 0xffff; - assert(l1_index == addr >> 32); - return lookupTable[l1_index][l2_index][l3_index]; - } - - /** - * Set the value in the lookup table. - */ - void setValue(Addr addr, RefIndex index) - { - int l1_index = (addr >> 32) & 0x0f; - int l2_index = (addr >> 16) & 0xffff; - int l3_index = addr & 0xffff; - assert(l1_index == addr >> 32); - lookupTable[l1_index][l2_index][l3_index]=index; - } - - /** - * Initialize the lookup table to the given value. - */ - void initTable(Addr addr, RefIndex index); - - void heapSwap(int set, int a, int b) { - RefIndex tmp = cacheHeap[a]; - cacheHeap[a] = cacheHeap[b]; - cacheHeap[b] = tmp; - - setValue(refInfo[set][cacheHeap[a]].addr, a); - setValue(refInfo[set][cacheHeap[b]].addr, b); - } - - int heapLeft(int index) { return index + index + 1; } - int heapRight(int index) { return index + index + 2; } - int heapParent(int index) { return (index - 1) >> 1; } - - RefIndex heapRank(int set, int index) { - return refInfo[set][cacheHeap[index]].nextRefTime; - } - - void heapify(int set, int start){ - int left = heapLeft(start); - int right = heapRight(start); - int max = start; - if (left < assoc && heapRank(set, left) > heapRank(set, start)) { - max = left; - } - if (right < assoc && heapRank(set, right) > heapRank(set, max)) { - max = right; - } - - if (max != start) { - heapSwap(set, start, max); - heapify(set, max); - } - } - - void verifyHeap(int set, int start) { - int left = heapLeft(start); - int right = heapRight(start); - - if (left < assoc) { - assert(heapRank(set, start) >= heapRank(set, left)); - verifyHeap(set, left); - } - if (right < assoc) { - assert(heapRank(set, start) >= heapRank(set, right)); - verifyHeap(set, right); - } - } - - void processRankIncrease(int set, int start) { - int parent = heapParent(start); - while (start > 0 && heapRank(set,parent) < heapRank(set,start)) { - heapSwap(set, parent, start); - start = parent; - parent = heapParent(start); - } - } - - void processSet(int set); - - static const RefIndex InfiniteRef = 0x7fffffff; - - /** Memory reference trace. */ - MemTraceReader *trace; - - /** Cache heap for replacement. */ - std::vector<RefIndex> cacheHeap; - - /** The number of blocks in the cache. */ - const int numBlks; - - const int assoc; - const int numSets; - const int setMask; - - - int misses; - int hits; - - public: - /** - * Construct a OptCPU object. - */ - OptCPU(const std::string &name, - MemTraceReader *_trace, - int block_size, - int cache_size, - int assoc); - - /** - * Perform the optimal replacement simulation. - */ - void tick(); -}; - -#endif // __CPU_TRACE_OPT_CPU_HH__ diff --git a/cpu/trace/reader/ibm_reader.cc b/cpu/trace/reader/ibm_reader.cc deleted file mode 100644 index 420101b63..000000000 --- a/cpu/trace/reader/ibm_reader.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a IBM memory trace format reader. - */ -#include <sstream> - -#include "cpu/trace/reader/ibm_reader.hh" -#include "sim/builder.hh" -#include "base/misc.hh" // for fatal - -using namespace std; - -IBMReader::IBMReader(const string &name, const string &filename) - : MemTraceReader(name) -{ - if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { - // Compressed file, need to use a pipe to gzip. - stringstream buf; - buf << "gzip -d -c " << filename << endl; - trace = popen(buf.str().c_str(), "r"); - } else { - trace = fopen(filename.c_str(), "rb"); - } - if (!trace) { - fatal("Can't open file %s", filename); - } -} - -Tick -IBMReader::getNextReq(MemReqPtr &req) -{ - MemReqPtr tmp_req; - - int c = getc(trace); - if (c != EOF) { - tmp_req = new MemReq(); - //int cpu_id = (c & 0xf0) >> 4; - int type = c & 0x0f; - // We have L1 miss traces, so all accesses are 128 bytes - tmp_req->size = 128; - - tmp_req->paddr = 0; - for (int i = 2; i >= 0; --i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of file"); - } - tmp_req->paddr |= ((c & 0xff) << (8 * i)); - } - tmp_req->paddr = tmp_req->paddr << 7; - - switch(type) { - case IBM_COND_EXCLUSIVE_FETCH: - case IBM_READ_ONLY_FETCH: - tmp_req->cmd = Read; - break; - case IBM_EXCLUSIVE_FETCH: - case IBM_FETCH_NO_DATA: - tmp_req->cmd = Write; - break; - case IBM_INST_FETCH: - tmp_req->cmd = Read; - break; - default: - fatal("Unknown trace entry type."); - } - - } - req = tmp_req; - return 0; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IBMReader) - - Param<string> filename; - -END_DECLARE_SIM_OBJECT_PARAMS(IBMReader) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(IBMReader) - - INIT_PARAM(filename, "trace file") - -END_INIT_SIM_OBJECT_PARAMS(IBMReader) - - -CREATE_SIM_OBJECT(IBMReader) -{ - return new IBMReader(getInstanceName(), filename); -} - -REGISTER_SIM_OBJECT("IBMReader", IBMReader) diff --git a/cpu/trace/reader/ibm_reader.hh b/cpu/trace/reader/ibm_reader.hh deleted file mode 100644 index ce29206a2..000000000 --- a/cpu/trace/reader/ibm_reader.hh +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a IBM memory trace format reader. - */ - -#ifndef __IBM_READER_HH__ -#define __IBM_READER_HH__ - -#include <stdio.h> -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "mem/mem_req.hh" - -/** - * A memory trace reader for the IBM memory trace format. - */ -class IBMReader : public MemTraceReader -{ - /** IBM trace file. */ - FILE* trace; - - enum IBMType { - IBM_INST_FETCH, - IBM_READ_ONLY_FETCH, - IBM_COND_EXCLUSIVE_FETCH, - IBM_EXCLUSIVE_FETCH, - IBM_FETCH_NO_DATA - }; - - public: - /** - * Construct an IBMReader. - */ - IBMReader(const std::string &name, const std::string &filename); - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return IBM traces don't store timing information, return 0 - */ - virtual Tick getNextReq(MemReqPtr &req); -}; - -#endif //__IBM_READER_HH__ - diff --git a/cpu/trace/reader/itx_reader.cc b/cpu/trace/reader/itx_reader.cc deleted file mode 100644 index 39ba27393..000000000 --- a/cpu/trace/reader/itx_reader.cc +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a Intel ITX memory trace format reader. - */ -#include <sstream> - -#include "cpu/trace/reader/itx_reader.hh" -#include "sim/builder.hh" -#include "base/misc.hh" // for fatal - -using namespace std; - -ITXReader::ITXReader(const string &name, const string &filename) - : MemTraceReader(name) -{ - if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { - // Compressed file, need to use a pipe to gzip. - stringstream buf; - buf << "gzip -d -c " << filename << endl; - trace = popen(buf.str().c_str(), "r"); - } else { - trace = fopen(filename.c_str(), "rb"); - } - if (!trace) { - fatal("Can't open file %s", filename); - } - traceFormat = 0; - int c; - for (int i = 0; i < 4; ++i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - traceFormat |= (c & 0xff) << (8 * i); - } - if (traceFormat > 2) - fatal("Invalid trace format."); -} - -Tick -ITXReader::getNextReq(MemReqPtr &req) -{ - MemReqPtr tmp_req = new MemReq(); - bool phys_val; - do { - int c = getc(trace); - if (c != EOF) { - // Decode first byte - // phys_val<1> | type <2:0> | size <3:0> - phys_val = c & 0x80; - tmp_req->size = (c & 0x0f) + 1; - int type = (c & 0x70) >> 4; - - // Could be a compressed instruction entry, expand if necessary - if (type == ITXCodeComp) { - if (traceFormat != 2) { - fatal("Compressed code entry in non CompCode trace."); - } - if (!codeVirtValid) { - fatal("Corrupt CodeComp entry."); - } - - tmp_req->vaddr = codeVirtAddr; - codeVirtAddr += tmp_req->size; - if (phys_val) { - if (!codePhysValid) { - fatal("Corrupt CodeComp entry."); - } - tmp_req->paddr = codePhysAddr; - if (((tmp_req->paddr & 0xfff) + tmp_req->size) & ~0xfff) { - // Crossed page boundary, next physical address is - // invalid - codePhysValid = false; - } else { - codePhysAddr += tmp_req->size; - } - assert(tmp_req->paddr >> 36 == 0); - } else { - codePhysValid = false; - } - type = ITXCode; - tmp_req->cmd = Read; - } else { - // Normal entry - tmp_req->vaddr = 0; - for (int i = 0; i < 4; ++i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - tmp_req->vaddr |= (c & 0xff) << (8 * i); - } - if (type == ITXCode) { - codeVirtAddr = tmp_req->vaddr + tmp_req->size; - codeVirtValid = true; - } - tmp_req->paddr = 0; - if (phys_val) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - // Get the page offset from the virtual address. - tmp_req->paddr = tmp_req->vaddr & 0xfff; - tmp_req->paddr |= (c & 0xf0) << 8; - tmp_req->paddr |= (Addr)(c & 0x0f) << 32; - for (int i = 2; i < 4; ++i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - tmp_req->paddr |= (Addr)(c & 0xff) << (8 * i); - } - if (type == ITXCode) { - if (((tmp_req->paddr & 0xfff) + tmp_req->size) - & ~0xfff) { - // Crossing the page boundary, next physical - // address isn't valid - codePhysValid = false; - } else { - codePhysAddr = tmp_req->paddr + tmp_req->size; - codePhysValid = true; - } - } - assert(tmp_req->paddr >> 36 == 0); - } else if (type == ITXCode) { - codePhysValid = false; - } - switch(type) { - case ITXRead: - tmp_req->cmd = Read; - break; - case ITXWrite: - tmp_req->cmd = Write; - break; - case ITXWriteback: - tmp_req->cmd = Writeback; - break; - case ITXCode: - tmp_req->cmd = Read; - tmp_req->flags |= INST_READ; - break; - default: - fatal("Unknown ITX type"); - } - } - } else { - // EOF need to return a null request - MemReqPtr null_req; - req = null_req; - return 0; - } - } while (!phys_val); - req = tmp_req; - assert(!req || (req->paddr >> 36) == 0); - return 0; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITXReader) - - Param<string> filename; - -END_DECLARE_SIM_OBJECT_PARAMS(ITXReader) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(ITXReader) - - INIT_PARAM(filename, "trace file") - -END_INIT_SIM_OBJECT_PARAMS(ITXReader) - - -CREATE_SIM_OBJECT(ITXReader) -{ - return new ITXReader(getInstanceName(), filename); -} - -REGISTER_SIM_OBJECT("ITXReader", ITXReader) diff --git a/cpu/trace/reader/itx_reader.hh b/cpu/trace/reader/itx_reader.hh deleted file mode 100644 index a16a08085..000000000 --- a/cpu/trace/reader/itx_reader.hh +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a Intel ITX memory trace format reader. - */ - -#ifndef __ITX_READER_HH__ -#define __ITX_READER_HH__ - -#include <stdio.h> -#include <string> - -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "mem/mem_req.hh" - - -/** - * A memory trace reader for the Intel ITX memory trace format. - */ -class ITXReader : public MemTraceReader -{ - private: - /** Trace file. */ - FILE *trace; - - bool codeVirtValid; - Addr codeVirtAddr; - bool codePhysValid; - Addr codePhysAddr; - - int traceFormat; - - enum ITXType { - ITXRead, - ITXWrite, - ITXWriteback, - ITXCode, - ITXCodeComp - }; - - public: - /** - * Construct an ITXReader. - */ - ITXReader(const std::string &name, const std::string &filename); - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return ITX traces don't store timing information, return 0 - */ - virtual Tick getNextReq(MemReqPtr &req); -}; - -#endif //__ITX_READER_HH__ - diff --git a/cpu/trace/reader/m5_reader.cc b/cpu/trace/reader/m5_reader.cc deleted file mode 100644 index ce44672f2..000000000 --- a/cpu/trace/reader/m5_reader.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace reader for a M5 memory trace. - */ - -#include "cpu/trace/reader/m5_reader.hh" -#include "mem/trace/m5_format.hh" -#include "mem/mem_cmd.hh" -#include "sim/builder.hh" - -using namespace std; - -M5Reader::M5Reader(const string &name, const string &filename) - : MemTraceReader(name) -{ - traceFile.open(filename.c_str(), ios::binary); -} - -Tick -M5Reader::getNextReq(MemReqPtr &req) -{ - M5Format ref; - - MemReqPtr tmp_req; - // Need to read EOF char before eof() will return true. - traceFile.read((char*) &ref, sizeof(ref)); - if (!traceFile.eof()) { - //traceFile.read((char*) &ref, sizeof(ref)); -#ifndef NDEBUG - int gcount = traceFile.gcount(); - assert(gcount != 0 || traceFile.eof()); - assert(gcount == sizeof(ref)); - assert(ref.cmd < 12); -#endif - tmp_req = new MemReq(); - tmp_req->paddr = ref.paddr; - tmp_req->asid = ref.asid; - // Assume asid == thread_num - tmp_req->thread_num = ref.asid; - tmp_req->cmd = (MemCmdEnum)ref.cmd; - tmp_req->size = ref.size; - tmp_req->dest = ref.dest; - } else { - ref.cycle = 0; - } - req = tmp_req; - return ref.cycle; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(M5Reader) - - Param<string> filename; - -END_DECLARE_SIM_OBJECT_PARAMS(M5Reader) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(M5Reader) - - INIT_PARAM(filename, "trace file") - -END_INIT_SIM_OBJECT_PARAMS(M5Reader) - - -CREATE_SIM_OBJECT(M5Reader) -{ - return new M5Reader(getInstanceName(), filename); -} - -REGISTER_SIM_OBJECT("M5Reader", M5Reader) diff --git a/cpu/trace/reader/m5_reader.hh b/cpu/trace/reader/m5_reader.hh deleted file mode 100644 index 974a83ffa..000000000 --- a/cpu/trace/reader/m5_reader.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a memory trace reader for a M5 memory trace. - */ - -#ifndef __M5_READER_HH__ -#define __M5_READER_HH__ - -#include <fstream> - -#include "cpu/trace/reader/mem_trace_reader.hh" - -/** - * A memory trace reader for an M5 memory trace. @sa M5Writer. - */ -class M5Reader : public MemTraceReader -{ - /** The traceFile. */ - std::ifstream traceFile; - - std::string fn; - - public: - /** - * Construct an M5 memory trace reader. - */ - M5Reader(const std::string &name, const std::string &filename); - - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return The cycle the reference was started. - */ - virtual Tick getNextReq(MemReqPtr &req); -}; - -#endif // __M5_READER_HH__ diff --git a/cpu/trace/reader/mem_trace_reader.cc b/cpu/trace/reader/mem_trace_reader.cc deleted file mode 100644 index 769f0be27..000000000 --- a/cpu/trace/reader/mem_trace_reader.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * SimObject Declaration of pure virtual MemTraceReader class. - */ - -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "sim/param.hh" - -DEFINE_SIM_OBJECT_CLASS_NAME("MemTraceReader", MemTraceReader); diff --git a/cpu/trace/reader/mem_trace_reader.hh b/cpu/trace/reader/mem_trace_reader.hh deleted file mode 100644 index b433cdbdd..000000000 --- a/cpu/trace/reader/mem_trace_reader.hh +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * Definitions for a pure virtual interface to a memory trace reader. - */ - -#ifndef __MEM_TRACE_READER_HH__ -#define __MEM_TRACE_READER_HH__ - -#include "sim/sim_object.hh" -#include "mem/mem_req.hh" // For MemReqPtr - -/** - * Pure virtual base class for memory trace readers. - */ -class MemTraceReader : public SimObject -{ - public: - /** Construct this MemoryTrace reader. */ - MemTraceReader(const std::string &name) : SimObject(name) {} - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return The cycle of the request, 0 if none in trace. - */ - virtual Tick getNextReq(MemReqPtr &req) = 0; -}; - -#endif //__MEM_TRACE_READER_HH__ diff --git a/cpu/trace/trace_cpu.cc b/cpu/trace/trace_cpu.cc deleted file mode 100644 index 20d0a567f..000000000 --- a/cpu/trace/trace_cpu.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace CPU object. Uses a memory trace to drive the - * provided memory hierarchy. - */ - -#include <algorithm> // For min - -#include "cpu/trace/trace_cpu.hh" -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "mem/base_mem.hh" // For PARAM constructor -#include "mem/mem_interface.hh" -#include "sim/builder.hh" -#include "sim/sim_events.hh" - -using namespace std; - -TraceCPU::TraceCPU(const string &name, - MemInterface *icache_interface, - MemInterface *dcache_interface, - MemTraceReader *data_trace) - : SimObject(name), icacheInterface(icache_interface), - dcacheInterface(dcache_interface), - dataTrace(data_trace), outstandingRequests(0), tickEvent(this) -{ - assert(dcacheInterface); - nextCycle = dataTrace->getNextReq(nextReq); - tickEvent.schedule(0); -} - -void -TraceCPU::tick() -{ - assert(outstandingRequests >= 0); - assert(outstandingRequests < 1000); - int instReqs = 0; - int dataReqs = 0; - - while (nextReq && curTick >= nextCycle) { - assert(nextReq->thread_num < 4 && "Not enough threads"); - if (nextReq->isInstRead() && icacheInterface) { - if (icacheInterface->isBlocked()) - break; - - nextReq->time = curTick; - if (nextReq->cmd == Squash) { - icacheInterface->squash(nextReq->asid); - } else { - ++instReqs; - if (icacheInterface->doEvents()) { - nextReq->completionEvent = - new TraceCompleteEvent(nextReq, this); - icacheInterface->access(nextReq); - } else { - icacheInterface->access(nextReq); - completeRequest(nextReq); - } - } - } else { - if (dcacheInterface->isBlocked()) - break; - - ++dataReqs; - nextReq->time = curTick; - if (dcacheInterface->doEvents()) { - nextReq->completionEvent = - new TraceCompleteEvent(nextReq, this); - dcacheInterface->access(nextReq); - } else { - dcacheInterface->access(nextReq); - completeRequest(nextReq); - } - - } - nextCycle = dataTrace->getNextReq(nextReq); - } - - if (!nextReq) { - // No more requests to send. Finish trailing events and exit. - if (mainEventQueue.empty()) { - new SimExitEvent("Finshed Memory Trace"); - } else { - tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1)); - } - } else { - tickEvent.schedule(max(curTick + cycles(1), nextCycle)); - } -} - -void -TraceCPU::completeRequest(MemReqPtr& req) -{ -} - -void -TraceCompleteEvent::process() -{ - tester->completeRequest(req); -} - -const char * -TraceCompleteEvent::description() -{ - return "trace access complete"; -} - -TraceCPU::TickEvent::TickEvent(TraceCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -void -TraceCPU::TickEvent::process() -{ - cpu->tick(); -} - -const char * -TraceCPU::TickEvent::description() -{ - return "TraceCPU tick event"; -} - - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) - - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - SimObjectParam<MemTraceReader *> data_trace; - -END_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TraceCPU) - - INIT_PARAM_DFLT(icache, "instruction cache", NULL), - INIT_PARAM_DFLT(dcache, "data cache", NULL), - INIT_PARAM_DFLT(data_trace, "data trace", NULL) - -END_INIT_SIM_OBJECT_PARAMS(TraceCPU) - -CREATE_SIM_OBJECT(TraceCPU) -{ - return new TraceCPU(getInstanceName(), - (icache) ? icache->getInterface() : NULL, - (dcache) ? dcache->getInterface() : NULL, - data_trace); -} - -REGISTER_SIM_OBJECT("TraceCPU", TraceCPU) - diff --git a/cpu/trace/trace_cpu.hh b/cpu/trace/trace_cpu.hh deleted file mode 100644 index 69ca35321..000000000 --- a/cpu/trace/trace_cpu.hh +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace CPU object. Uses a memory trace to drive the - * provided memory hierarchy. - */ - -#ifndef __CPU_TRACE_TRACE_CPU_HH__ -#define __CPU_TRACE_TRACE_CPU_HH__ - -#include <string> - -#include "mem/mem_req.hh" // for MemReqPtr -#include "sim/eventq.hh" // for Event -#include "sim/sim_object.hh" - -// Forward declaration. -class MemInterface; -class MemTraceReader; - -/** - * A cpu object for running memory traces through a memory hierarchy. - */ -class TraceCPU : public SimObject -{ - private: - /** Interface for instruction trace requests, if any. */ - MemInterface *icacheInterface; - /** Interface for data trace requests, if any. */ - MemInterface *dcacheInterface; - - /** Data reference trace. */ - MemTraceReader *dataTrace; - - /** Number of outstanding requests. */ - int outstandingRequests; - - /** Cycle of the next request, 0 if not available. */ - Tick nextCycle; - - /** Next request. */ - MemReqPtr nextReq; - - /** - * Event to call the TraceCPU::tick - */ - class TickEvent : public Event - { - private: - /** The associated CPU */ - TraceCPU *cpu; - - public: - /** - * Construct this event; - */ - TickEvent(TraceCPU *c); - - /** - * Call the tick function. - */ - void process(); - - /** - * Return a string description of this event. - */ - const char *description(); - }; - - TickEvent tickEvent; - - public: - /** - * Construct a TraceCPU object. - */ - TraceCPU(const std::string &name, - MemInterface *icache_interface, - MemInterface *dcache_interface, - MemTraceReader *data_trace); - - inline Tick cycles(int numCycles) { return numCycles; } - - /** - * Perform all the accesses for one cycle. - */ - void tick(); - - /** - * Handle a completed memory request. - */ - void completeRequest(MemReqPtr &req); -}; - -class TraceCompleteEvent : public Event -{ - MemReqPtr req; - TraceCPU *tester; - - public: - - TraceCompleteEvent(MemReqPtr &_req, TraceCPU *_tester) - : Event(&mainEventQueue), req(_req), tester(_tester) - { - setFlags(AutoDelete); - } - - void process(); - - virtual const char *description(); -}; - -#endif // __CPU_TRACE_TRACE_CPU_HH__ - |