diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2009-04-06 10:19:36 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2009-04-06 10:19:36 -0700 |
commit | d080581db1f9ee4e1e6d07d2b01c13c67908a391 (patch) | |
tree | cc484b289fa5a30c4631f9faa1d8b456bffeebfc /src/cpu | |
parent | 7a7c4c5fca83a8d47c7e71c9c080a882ebe204a9 (diff) | |
parent | 639cb0a42d953ee32bc7e96b0cdfa96cd40e9fc1 (diff) | |
download | gem5-d080581db1f9ee4e1e6d07d2b01c13c67908a391.tar.xz |
Merge ARM into the head. ARM will compile but may not actually work.
Diffstat (limited to 'src/cpu')
187 files changed, 17510 insertions, 5703 deletions
diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index c2a865113..f3688e991 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -26,7 +26,7 @@ # # Authors: Nathan Binkert -from m5.SimObject import SimObject +from MemObject import MemObject from m5.params import * from m5.proxy import * from m5 import build_env @@ -39,50 +39,84 @@ default_tracer = ExeTracer() if build_env['TARGET_ISA'] == 'alpha': from AlphaTLB import AlphaDTB, AlphaITB + if build_env['FULL_SYSTEM']: + from AlphaInterrupts import AlphaInterrupts elif build_env['TARGET_ISA'] == 'sparc': from SparcTLB import SparcDTB, SparcITB + if build_env['FULL_SYSTEM']: + from SparcInterrupts import SparcInterrupts elif build_env['TARGET_ISA'] == 'x86': from X86TLB import X86DTB, X86ITB + if build_env['FULL_SYSTEM']: + from X86LocalApic import X86LocalApic elif build_env['TARGET_ISA'] == 'mips': from MipsTLB import MipsTLB,MipsDTB, MipsITB, MipsUTB + if build_env['FULL_SYSTEM']: + from MipsInterrupts import MipsInterrupts elif build_env['TARGET_ISA'] == 'arm': from ArmTLB import ArmTLB, ArmDTB, ArmITB, ArmUTB + if build_env['FULL_SYSTEM']: + from ArmInterrupts import ArmInterrupts -class BaseCPU(SimObject): +class BaseCPU(MemObject): type = 'BaseCPU' abstract = True system = Param.System(Parent.any, "system object") - cpu_id = Param.Int("CPU identifier") + cpu_id = Param.Int(-1, "CPU identifier") + numThreads = Param.Unsigned(1, "number of HW thread contexts") + + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") + + checker = Param.BaseCPU(NULL, "checker CPU") + + do_checkpoint_insts = Param.Bool(True, + "enable checkpoint pseudo instructions") + do_statistics_insts = Param.Bool(True, + "enable statistics pseudo instructions") if build_env['FULL_SYSTEM']: + profile = Param.Latency('0ns', "trace the kernel stack") do_quiesce = Param.Bool(True, "enable quiesce instructions") - do_checkpoint_insts = Param.Bool(True, - "enable checkpoint pseudo instructions") - do_statistics_insts = Param.Bool(True, - "enable statistics pseudo instructions") else: workload = VectorParam.Process("processes to run") if build_env['TARGET_ISA'] == 'sparc': dtb = Param.SparcDTB(SparcDTB(), "Data TLB") itb = Param.SparcITB(SparcITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.SparcInterrupts( + SparcInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'alpha': dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB") itb = Param.AlphaITB(AlphaITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.AlphaInterrupts( + AlphaInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'x86': dtb = Param.X86DTB(X86DTB(), "Data TLB") itb = Param.X86ITB(X86ITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + _localApic = X86LocalApic(pio_addr=0x2000000000000000) + interrupts = \ + Param.X86LocalApic(_localApic, "Interrupt Controller") elif build_env['TARGET_ISA'] == 'mips': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.MipsDTB(MipsDTB(), "Data TLB") itb = Param.MipsITB(MipsITB(), "Instruction TLB") tlb = Param.MipsUTB(MipsUTB(), "Unified TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.MipsInterrupts( + MipsInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'arm': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.ArmDTB(ArmDTB(), "Data TLB") itb = Param.ArmITB(ArmITB(), "Instruction TLB") tlb = Param.ArmUTB(ArmUTB(), "Unified TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.ArmInterrupts( + ArmInterrupts(), "Interrupt Controller") else: print "Don't know what TLB to use for ISA %s" % \ build_env['TARGET_ISA'] @@ -109,7 +143,10 @@ class BaseCPU(SimObject): _mem_ports = [] if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']: - _mem_ports = ["itb.walker.port", "dtb.walker.port"] + _mem_ports = ["itb.walker.port", + "dtb.walker.port", + "interrupts.pio", + "interrupts.int_port"] def connectMemPorts(self, bus): for p in self._mem_ports: diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py new file mode 100644 index 000000000..bff9af62d --- /dev/null +++ b/src/cpu/CheckerCPU.py @@ -0,0 +1,42 @@ +# Copyright (c) 2007 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. +# +# Authors: Nathan Binkert + +from m5.params import * +from m5 import build_env +from BaseCPU import BaseCPU + +class CheckerCPU(BaseCPU): + type = 'CheckerCPU' + abstract = True + exitOnError = Param.Bool(False, "Exit on an error") + updateOnError = Param.Bool(False, + "Update the checker with the main CPU's state on an error") + warnOnlyOnLoadError = Param.Bool(False, + "If a load result is incorrect, only print a warning and do not exit") + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py index e904f9e7d..5754f5d5b 100644 --- a/src/cpu/ExeTracer.py +++ b/src/cpu/ExeTracer.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class ExeTracer(InstTracer): type = 'ExeTracer' - cxx_namespace = 'Trace' - cxx_class = 'ExeTracer' + cxx_class = 'Trace::ExeTracer' diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py index 6e8f567b3..3642f3174 100644 --- a/src/cpu/IntelTrace.py +++ b/src/cpu/IntelTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class IntelTrace(InstTracer): type = 'IntelTrace' - cxx_namespace = 'Trace' - cxx_class = 'IntelTrace' + cxx_class = 'Trace::IntelTrace' diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py index f9b6470a6..d450dd00e 100644 --- a/src/cpu/LegionTrace.py +++ b/src/cpu/LegionTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class LegionTrace(InstTracer): type = 'LegionTrace' - cxx_namespace = 'Trace' - cxx_class = 'LegionTrace' + cxx_class = 'Trace::LegionTrace' diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py index 96b4e991b..f410b5473 100644 --- a/src/cpu/NativeTrace.py +++ b/src/cpu/NativeTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class NativeTrace(InstTracer): type = 'NativeTrace' - cxx_namespace = 'Trace' - cxx_class = 'NativeTrace' + cxx_class = 'Trace::NativeTrace' diff --git a/src/cpu/SConscript b/src/cpu/SConscript index c7d0c33bd..eee8edca4 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -48,12 +48,14 @@ execfile(models_db.srcnode().abspath) # Template for execute() signature. exec_sig_template = ''' -virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; -virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const +virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0; +virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const { panic("initiateAcc not defined!"); M5_DUMMY_RETURN }; -virtual Fault completeAcc(Packet *pkt, %s *xc, +virtual Fault completeAcc(Packet *pkt, %(type)s *xc, Trace::InstRecord *traceData) const { panic("completeAcc not defined!"); M5_DUMMY_RETURN }; +virtual int memAccSize(%(type)s *xc) +{ panic("memAccSize not defined!"); M5_DUMMY_RETURN }; ''' mem_ini_sig_template = ''' @@ -71,6 +73,7 @@ temp_cpu_list = env['CPU_MODELS'][:] if env['USE_CHECKER']: temp_cpu_list.append('CheckerCPU') + SimObject('CheckerCPU.py') # Generate header. def gen_cpu_exec_signatures(target, source, env): @@ -81,7 +84,7 @@ def gen_cpu_exec_signatures(target, source, env): ''' for cpu in temp_cpu_list: xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % (xc_type, xc_type, xc_type) + print >> f, exec_sig_template % { 'type' : xc_type } print >> f, ''' #endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ ''' @@ -165,10 +168,12 @@ TraceFlag('ExecSpeculative') TraceFlag('ExecSymbol') TraceFlag('ExecThread') TraceFlag('ExecTicks') +TraceFlag('ExecMicro') +TraceFlag('ExecMacro') TraceFlag('Fetch') TraceFlag('IntrControl') TraceFlag('PCEvent') TraceFlag('Quiesce') CompoundFlag('Exec', [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', 'ExecThread', - 'ExecEffAddr', 'ExecResult', 'ExecSymbol' ]) + 'ExecEffAddr', 'ExecResult', 'ExecSymbol', 'ExecMicro' ]) diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc index 15e0556ad..a2a34edf9 100644 --- a/src/cpu/activity.cc +++ b/src/cpu/activity.cc @@ -28,15 +28,18 @@ * Authors: Kevin Lim */ -#include <cstring> +#include <string> #include "base/timebuf.hh" #include "cpu/activity.hh" -ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency, - int activity) - : activityBuffer(longest_latency, 0), longestLatency(longest_latency), - activityCount(activity), numStages(num_stages) +using namespace std; + +ActivityRecorder::ActivityRecorder(const string &name, int num_stages, + int longest_latency, int activity) + : _name(name), activityBuffer(longest_latency, 0), + longestLatency(longest_latency), activityCount(activity), + numStages(num_stages) { stageActive = new bool[numStages]; std::memset(stageActive, 0, numStages); diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh index e99927339..d75ff150e 100644 --- a/src/cpu/activity.hh +++ b/src/cpu/activity.hh @@ -49,9 +49,11 @@ * idle. If count is zero, then the CPU can safely idle as it has no * more outstanding work to do. */ -class ActivityRecorder { +class ActivityRecorder +{ public: - ActivityRecorder(int num_stages, int longest_latency, int count); + ActivityRecorder(const std::string &name, int num_stages, + int longest_latency, int count); /** Records that there is activity this cycle. */ void activity(); @@ -92,6 +94,10 @@ class ActivityRecorder { void validate(); private: + // provide name() for DPRINTF. + std::string _name; + const std::string &name() { return _name; } + /** Time buffer that tracks if any cycles has active communication * in them. It should be as long as the longest communication * latency in the system. Each time any time buffer is written, diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 23195f720..0ef206d90 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -37,17 +37,17 @@ #include "base/loader/symtab.hh" #include "base/misc.hh" #include "base/output.hh" +#include "base/trace.hh" #include "cpu/base.hh" #include "cpu/cpuevent.hh" #include "cpu/thread_context.hh" #include "cpu/profile.hh" +#include "params/BaseCPU.hh" #include "sim/sim_exit.hh" #include "sim/process.hh" #include "sim/sim_events.hh" #include "sim/system.hh" -#include "base/trace.hh" - // Hack #include "sim/stat_control.hh" @@ -60,13 +60,12 @@ vector<BaseCPU *> BaseCPU::cpuList; // been initialized int maxThreadsPerCPU = 1; -CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival, - BaseCPU *_cpu) - : Event(q, Event::Progress_Event_Pri), interval(ival), - lastNumInst(0), cpu(_cpu) +CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival) + : Event(Event::Progress_Event_Pri), interval(ival), lastNumInst(0), + cpu(_cpu) { if (interval) - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } void @@ -84,7 +83,7 @@ CPUProgressEvent::process() curTick, cpu->name(), temp - lastNumInst); #endif lastNumInst = temp; - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } const char * @@ -95,21 +94,29 @@ CPUProgressEvent::description() const #if FULL_SYSTEM BaseCPU::BaseCPU(Params *p) - : MemObject(makeParams(p->name)), clock(p->clock), instCnt(0), - params(p), number_of_threads(p->numberOfThreads), system(p->system), + : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id), + interrupts(p->interrupts), + number_of_threads(p->numThreads), system(p->system), phase(p->phase) #else BaseCPU::BaseCPU(Params *p) - : MemObject(makeParams(p->name)), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads), system(p->system), + : MemObject(p), clock(p->clock), _cpuId(p->cpu_id), + number_of_threads(p->numThreads), system(p->system), phase(p->phase) #endif { // currentTick = curTick; + // if Python did not provide a valid ID, do it here + if (_cpuId == -1 ) { + _cpuId = cpuList.size(); + } + // add self to global list of CPUs cpuList.push_back(this); + DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId); + if (number_of_threads > maxThreadsPerCPU) maxThreadsPerCPU = number_of_threads; @@ -121,22 +128,26 @@ BaseCPU::BaseCPU(Params *p) // // 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) - schedExitSimLoop("a thread reached the max instruction count", - p->max_insts_any_thread, 0, - comInstEventQueue[i]); + if (p->max_insts_any_thread != 0) { + const char *cause = "a thread reached the max instruction count"; + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new SimLoopExitEvent(cause, 0); + comInstEventQueue[i]->schedule(event, p->max_insts_any_thread); + } + } if (p->max_insts_all_threads != 0) { + const char *cause = "all threads reached the max instruction count"; + // 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); + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new CountedExitEvent(cause, *counter); + comInstEventQueue[i]->schedule(event, p->max_insts_any_thread); + } } // allocate per-thread load-based event queues @@ -147,53 +158,49 @@ BaseCPU::BaseCPU(Params *p) // // 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) - schedExitSimLoop("a thread reached the max load count", - p->max_loads_any_thread, 0, - comLoadEventQueue[i]); + if (p->max_loads_any_thread != 0) { + const char *cause = "a thread reached the max load count"; + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new SimLoopExitEvent(cause, 0); + comLoadEventQueue[i]->schedule(event, p->max_loads_any_thread); + } + } if (p->max_loads_all_threads != 0) { + const char *cause = "all threads reached the max load count"; // 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); + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new CountedExitEvent(cause, *counter); + comLoadEventQueue[i]->schedule(event, p->max_loads_all_threads); + } } functionTracingEnabled = false; - if (p->functionTrace) { + if (p->function_trace) { functionTraceStream = simout.find(csprintf("ftrace.%s", name())); currentFunctionStart = currentFunctionEnd = 0; - functionEntryTick = p->functionTraceStart; + functionEntryTick = p->function_trace_start; - if (p->functionTraceStart == 0) { + if (p->function_trace_start == 0) { functionTracingEnabled = true; } else { - new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, - p->functionTraceStart, - true); + typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap; + Event *event = new wrap(this, true); + schedule(event, p->function_trace_start); } } #if FULL_SYSTEM - profileEvent = NULL; - if (params->profile) - profileEvent = new ProfileEvent(this, params->profile); -#endif - tracer = params->tracer; -} + interrupts->setCPU(this); -BaseCPU::Params::Params() -{ -#if FULL_SYSTEM - profile = false; + profileEvent = NULL; + if (params()->profile) + profileEvent = new ProfileEvent(this, params()->profile); #endif - checker = NULL; - tracer = NULL; + tracer = params()->tracer; } void @@ -209,7 +216,7 @@ BaseCPU::~BaseCPU() void BaseCPU::init() { - if (!params->deferRegistration) + if (!params()->defer_registration) registerThreadContexts(); } @@ -217,14 +224,14 @@ void BaseCPU::startup() { #if FULL_SYSTEM - if (!params->deferRegistration && profileEvent) - profileEvent->schedule(curTick); + if (!params()->defer_registration && profileEvent) + schedule(profileEvent, curTick); #endif - if (params->progress_interval) { - new CPUProgressEvent(&mainEventQueue, - ticks(params->progress_interval), - this); + if (params()->progress_interval) { + Tick num_ticks = ticks(params()->progress_interval); + Event *event = new CPUProgressEvent(this, num_ticks); + schedule(event, curTick + num_ticks); } } @@ -280,14 +287,19 @@ BaseCPU::registerThreadContexts() for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; -#if FULL_SYSTEM - int id = params->cpu_id; - if (id != -1) - id += i; - - tc->setCpuId(system->registerThreadContext(tc, id)); -#else - tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc)); + /** This is so that contextId and cpuId match where there is a + * 1cpu:1context relationship. Otherwise, the order of registration + * could affect the assignment and cpu 1 could have context id 3, for + * example. We may even want to do something like this for SMT so that + * cpu 0 has the lowest thread contexts and cpu N has the highest, but + * I'll just do this for now + */ + if (number_of_threads == 1) + tc->setContextId(system->registerThreadContext(tc, _cpuId)); + else + tc->setContextId(system->registerThreadContext(tc)); +#if !FULL_SYSTEM + tc->getProcessPtr()->assignThreadContext(tc->contextId()); #endif } } @@ -309,7 +321,7 @@ BaseCPU::switchOut() // panic("This CPU doesn't support sampling!"); #if FULL_SYSTEM if (profileEvent && profileEvent->scheduled()) - profileEvent->deschedule(); + deschedule(profileEvent); #endif } @@ -318,6 +330,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) { assert(threadContexts.size() == oldCPU->threadContexts.size()); + _cpuId = oldCPU->cpuId(); + for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *newTC = threadContexts[i]; ThreadContext *oldTC = oldCPU->threadContexts[i]; @@ -326,53 +340,49 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) CpuEvent::replaceThreadContext(oldTC, newTC); - assert(newTC->readCpuId() == oldTC->readCpuId()); -#if FULL_SYSTEM - system->replaceThreadContext(newTC, newTC->readCpuId()); -#else - assert(newTC->getProcessPtr() == oldTC->getProcessPtr()); - newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId()); -#endif + assert(newTC->contextId() == oldTC->contextId()); + assert(newTC->threadId() == oldTC->threadId()); + system->replaceThreadContext(newTC, newTC->contextId()); - if (DTRACE(Context)) + /* This code no longer works since the zero register (e.g., + * r31 on Alpha) doesn't necessarily contain zero at this + * point. + if (DTRACE(Context)) ThreadContext::compare(oldTC, newTC); + */ } #if FULL_SYSTEM interrupts = oldCPU->interrupts; + interrupts->setCPU(this); for (int i = 0; i < threadContexts.size(); ++i) threadContexts[i]->profileClear(); if (profileEvent) - profileEvent->schedule(curTick); + schedule(profileEvent, curTick); #endif // Connect new CPU to old CPU's memory only if new CPU isn't // connected to anything. Also connect old CPU's memory to new // CPU. - Port *peer; - if (ic->getPeer() == NULL || ic->getPeer()->isDefaultPort()) { - peer = oldCPU->getPort("icache_port")->getPeer(); + if (!ic->isConnected()) { + Port *peer = oldCPU->getPort("icache_port")->getPeer(); ic->setPeer(peer); - } else { - peer = ic->getPeer(); + peer->setPeer(ic); } - peer->setPeer(ic); - if (dc->getPeer() == NULL || dc->getPeer()->isDefaultPort()) { - peer = oldCPU->getPort("dcache_port")->getPeer(); + if (!dc->isConnected()) { + Port *peer = oldCPU->getPort("dcache_port")->getPeer(); dc->setPeer(peer); - } else { - peer = dc->getPeer(); + peer->setPeer(dc); } - peer->setPeer(dc); } #if FULL_SYSTEM -BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) - : Event(&mainEventQueue), cpu(_cpu), interval(_interval) +BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) + : cpu(_cpu), interval(_interval) { } void @@ -383,45 +393,21 @@ BaseCPU::ProfileEvent::process() tc->profileSample(); } - schedule(curTick + interval); -} - -void -BaseCPU::post_interrupt(int int_num, int index) -{ - interrupts.post(int_num, index); -} - -void -BaseCPU::clear_interrupt(int int_num, int index) -{ - interrupts.clear(int_num, index); -} - -void -BaseCPU::clear_interrupts() -{ - interrupts.clear_all(); -} - -uint64_t -BaseCPU::get_interrupts(int int_num) -{ - return interrupts.get_vec(int_num); + cpu->schedule(this, curTick + interval); } void BaseCPU::serialize(std::ostream &os) { SERIALIZE_SCALAR(instCnt); - interrupts.serialize(os); + interrupts->serialize(os); } void BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(instCnt); - interrupts.unserialize(cp, section); + interrupts->unserialize(cp, section); } #endif // FULL_SYSTEM diff --git a/src/cpu/base.hh b/src/cpu/base.hh index bdc7d7c8b..8af3295eb 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -35,6 +35,7 @@ #include <vector> #include "arch/isa_traits.hh" +#include "arch/microcode_rom.hh" #include "base/statistics.hh" #include "config/full_system.hh" #include "sim/eventq.hh" @@ -45,6 +46,7 @@ #include "arch/interrupts.hh" #endif +class BaseCPUParams; class BranchPred; class CheckerCPU; class ThreadContext; @@ -64,7 +66,7 @@ class CPUProgressEvent : public Event BaseCPU *cpu; public: - CPUProgressEvent(EventQueue *q, Tick ival, BaseCPU *_cpu); + CPUProgressEvent(BaseCPU *_cpu, Tick ival); void process(); @@ -78,8 +80,16 @@ class BaseCPU : public MemObject Tick clock; // @todo remove me after debugging with legion done Tick instCnt; + // every cpu has an id, put it in the base cpu + // Set at initialization, only time a cpuId might change is during a + // takeover (which should be done from within the BaseCPU anyway, + // therefore no setCpuId() method is provided + int _cpuId; public: + /** Reads this CPU's ID. */ + int cpuId() { return _cpuId; } + // Tick currentTick; inline Tick frequency() const { return Clock::Frequency / clock; } inline Tick ticks(int numCycles) const { return clock * numCycles; } @@ -102,29 +112,54 @@ class BaseCPU : public MemObject */ Tick nextCycle(Tick begin_tick); + TheISA::MicrocodeRom microcodeRom; + #if FULL_SYSTEM protected: -// uint64_t interrupts[TheISA::NumInterruptLevels]; -// uint64_t intstatus; - TheISA::Interrupts interrupts; + TheISA::Interrupts *interrupts; public: - virtual void post_interrupt(int int_num, int index); - virtual void clear_interrupt(int int_num, int index); - virtual void clear_interrupts(); - virtual uint64_t get_interrupts(int int_num); + TheISA::Interrupts * + getInterruptController() + { + return interrupts; + } + + virtual void wakeup() = 0; + + void + postInterrupt(int int_num, int index) + { + interrupts->post(int_num, index); + wakeup(); + } + + void + clearInterrupt(int int_num, int index) + { + interrupts->clear(int_num, index); + } + + void + clearInterrupts() + { + interrupts->clearAll(); + } - bool check_interrupts(ThreadContext * tc) const - { return interrupts.check_interrupts(tc); } + bool + checkInterrupts(ThreadContext *tc) const + { + return interrupts->checkInterrupts(tc); + } class ProfileEvent : public Event { private: BaseCPU *cpu; - int interval; + Tick interval; public: - ProfileEvent(BaseCPU *cpu, int interval); + ProfileEvent(BaseCPU *cpu, Tick interval); void process(); }; ProfileEvent *profileEvent; @@ -162,40 +197,9 @@ class BaseCPU : public MemObject ThreadContext *getContext(int tn) { return threadContexts[tn]; } 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; - System *system; - int cpu_id; - Trace::InstTracer * tracer; - - Tick phase; -#if FULL_SYSTEM - Tick profile; - - bool do_statistics_insts; - bool do_checkpoint_insts; - bool do_quiesce; -#endif - Tick progress_interval; - BaseCPU *checker; - - TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core - - Params(); - }; - - const Params *params; - + typedef BaseCPUParams Params; + const Params *params() const + { return reinterpret_cast<const Params *>(_params); } BaseCPU(Params *params); virtual ~BaseCPU(); @@ -221,6 +225,8 @@ class BaseCPU : public MemObject */ int number_of_threads; + TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core + /** * Vector of per-thread instruction-based event queues. Used for * scheduling events based on number of instructions committed by @@ -298,7 +304,7 @@ class BaseCPU : public MemObject public: // Number of CPU cycles simulated - Stats::Scalar<> numCycles; + Stats::Scalar numCycles; }; #endif // __CPU_BASE_HH__ diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index bea680fac..41c57cf39 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -77,8 +77,8 @@ class BaseDynInst : public FastAlloc, public RefCounted typedef typename std::list<DynInstPtr>::iterator ListIt; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs }; /** The StaticInst used by this BaseDynInst. */ @@ -115,9 +115,6 @@ class BaseDynInst : public FastAlloc, public RefCounted template <class T> Fault read(Addr addr, T &data, unsigned flags); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - /** * Does a write to a given address. * @param data The data to be written. @@ -130,9 +127,6 @@ class BaseDynInst : public FastAlloc, public RefCounted Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - void prefetch(Addr addr, unsigned flags); void writeHint(Addr addr, int size, unsigned flags); Fault copySrcTranslate(Addr src); @@ -258,9 +252,6 @@ class BaseDynInst : public FastAlloc, public RefCounted public: - /** Count of total number of dynamic instructions. */ - static int instcount; - #ifdef DEBUG void dumpSNList(); #endif @@ -412,7 +403,10 @@ class BaseDynInst : public FastAlloc, public RefCounted void dump(std::string &outstring); /** Read this CPU's ID. */ - int readCpuId() { return cpu->readCpuId(); } + int cpuId() { return cpu->cpuId(); } + + /** Read this context's system-wide ID **/ + int contextId() { return thread->contextId(); } /** Returns the fault type. */ Fault getFault() { return fault; } @@ -486,24 +480,24 @@ class BaseDynInst : public FastAlloc, public RefCounted // // 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 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 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 isCondCtrl() const { return staticInst->isCondCtrl(); } + bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); } bool isThreadSync() const { return staticInst->isThreadSync(); } bool isSerializing() const { return staticInst->isSerializing(); } @@ -560,7 +554,7 @@ class BaseDynInst : public FastAlloc, public RefCounted Addr branchTarget() const { return staticInst->branchTarget(PC); } /** Returns the number of source registers. */ - int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } + int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } /** Returns the number of destination registers. */ int8_t numDestRegs() const { return staticInst->numDestRegs(); } @@ -857,29 +851,6 @@ class BaseDynInst : public FastAlloc, public RefCounted }; template<class Impl> -Fault -BaseDynInst<Impl>::translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - if (traceData) { - traceData->setAddr(vaddr); - } - - reqMade = true; - Request *req = new Request(); - req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->readCpuId(), threadNumber); - - fault = cpu->translateDataReadReq(req, thread); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - -template<class Impl> template<class T> inline Fault BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) @@ -887,9 +858,9 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->translateDataReadReq(req, thread); + fault = cpu->dtb->translateAtomic(req, thread->getTC(), false); if (req->isUncacheable()) isUncacheable = true; @@ -931,29 +902,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) } template<class Impl> -Fault -BaseDynInst<Impl>::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - if (traceData) { - traceData->setAddr(vaddr); - } - - reqMade = true; - Request *req = new Request(); - req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->readCpuId(), threadNumber); - - fault = cpu->translateDataWriteReq(req, thread); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - -template<class Impl> template<class T> inline Fault BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) @@ -966,9 +914,9 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->translateDataWriteReq(req, thread); + fault = cpu->dtb->translateAtomic(req, thread->getTC(), true); if (req->isUncacheable()) isUncacheable = true; diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index 5c18ae694..4ee7d2f2c 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -168,18 +168,21 @@ BaseDynInst<Impl>::initVars() // Initialize the fault to be NoFault. fault = NoFault; - ++instcount; +#ifndef NDEBUG + ++cpu->instcount; - if (instcount > 1500) { - cpu->dumpInsts(); + if (cpu->instcount > 1500) { #ifdef DEBUG + cpu->dumpInsts(); dumpSNList(); #endif - assert(instcount <= 1500); + assert(cpu->instcount <= 1500); } - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", - seqNum, instcount); + DPRINTF(DynInst, + "DynInst: [sn:%lli] Instruction created. Instcount for %s = %i\n", + seqNum, cpu->name(), cpu->instcount); +#endif #ifdef DEBUG cpu->snList.insert(seqNum); @@ -199,10 +202,13 @@ BaseDynInst<Impl>::~BaseDynInst() fault = NoFault; - --instcount; +#ifndef NDEBUG + --cpu->instcount; - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", - seqNum, instcount); + DPRINTF(DynInst, + "DynInst: [sn:%lli] Instruction destroyed. Instcount for %s = %i\n", + seqNum, cpu->name(), cpu->instcount); +#endif #ifdef DEBUG cpu->snList.erase(seqNum); #endif diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc index a6af98d66..14777bc12 100644 --- a/src/cpu/checker/cpu.cc +++ b/src/cpu/checker/cpu.cc @@ -159,7 +159,7 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - translateDataReadReq(memReq); + dtb->translateAtomic(memReq, tc, false); PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); @@ -229,7 +229,7 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - thread->translateDataWriteReq(memReq); + dtb->translateAtomic(memReq, tc, true); // Can compare the write data and result only if it's cacheable, // not a store conditional, or is a store conditional that @@ -325,57 +325,6 @@ CheckerCPU::dbg_vtophys(Addr addr) #endif // FULL_SYSTEM bool -CheckerCPU::translateInstReq(Request *req) -{ -#if FULL_SYSTEM - return (thread->translateInstReq(req) == NoFault); -#else - thread->translateInstReq(req); - return true; -#endif -} - -void -CheckerCPU::translateDataReadReq(Request *req) -{ - thread->translateDataReadReq(req); - - if (req->getVaddr() != unverifiedReq->getVaddr()) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->getVaddr(), req->getVaddr()); - handleError(); - } - req->setPaddr(unverifiedReq->getPaddr()); - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->getFlags(), req->getFlags()); - handleError(); - } -} - -void -CheckerCPU::translateDataWriteReq(Request *req) -{ - thread->translateDataWriteReq(req); - - if (req->getVaddr() != unverifiedReq->getVaddr()) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->getVaddr(), req->getVaddr()); - handleError(); - } - req->setPaddr(unverifiedReq->getPaddr()); - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->getFlags(), req->getFlags()); - handleError(); - } -} - -bool CheckerCPU::checkFlags(Request *req) { // Remove any dynamic flags that don't have to do with the request itself. diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 35dc59ff4..0d3dddded 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -65,6 +65,7 @@ class Process; #endif // FULL_SYSTEM template <class> class BaseDynInst; +class CheckerCPUParams; class ThreadContext; class MemInterface; class Checkpoint; @@ -96,20 +97,10 @@ class CheckerCPU : public BaseCPU public: virtual void init(); - struct Params : public BaseCPU::Params - { -#if FULL_SYSTEM - TheISA::ITB *itb; - TheISA::DTB *dtb; -#else - Process *process; -#endif - bool exitOnError; - bool updateOnError; - bool warnOnlyOnLoadError; - }; - public: + typedef CheckerCPUParams Params; + const Params *params() const + { return reinterpret_cast<const Params *>(_params); } CheckerCPU(Params *p); virtual ~CheckerCPU(); @@ -189,7 +180,7 @@ class CheckerCPU : public BaseCPU // 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"); } + Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } void prefetch(Addr addr, unsigned flags) { @@ -340,10 +331,6 @@ class CheckerCPU : public BaseCPU this->dtb->demapPage(vaddr, asn); } - bool translateInstReq(Request *req); - void translateDataWriteReq(Request *req); - void translateDataReadReq(Request *req); - #if FULL_SYSTEM Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index f3f8a0bb3..26571ed68 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -141,9 +141,9 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) // Try to fetch the instruction #if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 +#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 #else -#define IFETCH_FLAGS(pc) 0 +#define IFETCH_FLAGS(pc) 0 #endif uint64_t fetch_PC = thread->readPC() & ~3; @@ -152,9 +152,10 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) memReq = new Request(inst->threadNumber, fetch_PC, sizeof(uint32_t), IFETCH_FLAGS(thread->readPC()), - fetch_PC, thread->readCpuId(), inst->threadNumber); + fetch_PC, thread->contextId(), + inst->threadNumber); - bool succeeded = translateInstReq(memReq); + bool succeeded = itb->translateAtomic(memReq, thread); if (!succeeded) { if (inst->getFault() == NoFault) { diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 15454c3fe..3c87f841f 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -82,7 +82,7 @@ class CheckerThreadContext : public ThreadContext checkerTC->setCpuId(id); } - int readCpuId() { return actualTC->readCpuId(); } + int cpuId() { return actualTC->cpuId(); } TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } @@ -98,10 +98,8 @@ class CheckerThreadContext : public ThreadContext FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) + VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } - - void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } @@ -155,7 +153,7 @@ class CheckerThreadContext : public ThreadContext void profileSample() { return actualTC->profileSample(); } #endif - int getThreadNum() { return actualTC->getThreadNum(); } + int threadId() { return actualTC->threadId(); } // @todo: Do I need this? MachInst getInst() { return actualTC->getInst(); } @@ -279,29 +277,8 @@ class CheckerThreadContext : public ThreadContext bool misspeculating() { return actualTC->misspeculating(); } #if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { - checkerTC->setSyscallArg(i, val); - actualTC->setSyscallArg(i, val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - checkerTC->setSyscallReturn(return_value); - actualTC->setSyscallReturn(return_value); - } - Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - actualTC->changeRegFileContext(param, val); - checkerTC->changeRegFileContext(param, val); - } }; #endif // __CPU_CHECKER_EXEC_CONTEXT_HH__ diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py index 5b0c6c4da..793f8c646 100644 --- a/src/cpu/cpu_models.py +++ b/src/cpu/cpu_models.py @@ -82,3 +82,6 @@ CpuModel('CheckerCPU', 'checker_cpu_exec.cc', CpuModel('O3CPU', 'o3_cpu_exec.cc', '#include "cpu/o3/isa_specific.hh"', { 'CPU_exec_context': 'O3DynInst' }) +CpuModel('InOrderCPU', 'inorder_cpu_exec.cc', + '#include "cpu/inorder/inorder_dyn_inst.hh"', + { 'CPU_exec_context': 'InOrderDynInst' }) diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh index 5816c6ca1..65f0e87e1 100644 --- a/src/cpu/cpuevent.hh +++ b/src/cpu/cpuevent.hh @@ -58,8 +58,8 @@ class CpuEvent : public Event ThreadContext *tc; public: - CpuEvent(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri) - : Event(q, p), tc(_tc) + CpuEvent(ThreadContext *_tc, Priority p = Default_Pri) + : Event(p), tc(_tc) { cpuEventList.push_back(this); } /** delete the cpu event from the global list. */ @@ -81,9 +81,8 @@ class CpuEventWrapper : public CpuEvent T *object; public: - CpuEventWrapper(T *obj, ThreadContext *_tc, - EventQueue *q = &mainEventQueue, Priority p = Default_Pri) - : CpuEvent(q, _tc, p), object(obj) + CpuEventWrapper(T *obj, ThreadContext *_tc, Priority p = Default_Pri) + : CpuEvent(_tc, p), object(obj) { } void process() { (object->*F)(tc); } }; diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 0118dbde1..ea53fb6f5 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -46,12 +46,18 @@ using namespace TheISA; namespace Trace { void -Trace::ExeTracerRecord::dump() +ExeTracerRecord::dumpTicks(ostream &outs) +{ + ccprintf(outs, "%7d: ", when); +} + +void +Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran) { ostream &outs = Trace::output(); if (IsOn(ExecTicks)) - ccprintf(outs, "%7d: ", when); + dumpTicks(outs); outs << thread->getCpuPtr()->name() << " "; @@ -59,46 +65,59 @@ Trace::ExeTracerRecord::dump() outs << (misspeculating ? "-" : "+") << " "; if (IsOn(ExecThread)) - outs << "T" << thread->getThreadNum() << " : "; - + outs << "T" << thread->threadId() << " : "; std::string sym_str; Addr sym_addr; if (debugSymbolTable && IsOn(ExecSymbol) +#if FULL_SYSTEM + && !inUserMode(thread) +#endif && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { if (PC != sym_addr) sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; + outs << "@" << sym_str; } else { - outs << "0x" << hex << PC << " : "; + outs << "0x" << hex << PC; } + if (inst->isMicroop()) { + outs << "." << setw(2) << dec << upc; + } else { + outs << " "; + } + + outs << " : "; + // // Print decoded instruction // outs << setw(26) << left; - outs << staticInst->disassemble(PC, debugSymbolTable); - outs << " : "; + outs << inst->disassemble(PC, debugSymbolTable); - if (IsOn(ExecOpClass)) { - outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; - } + if (ran) { + outs << " : "; - if (IsOn(ExecResult) && data_status != DataInvalid) { - ccprintf(outs, " D=%#018x", data.as_int); - } + if (IsOn(ExecOpClass)) { + outs << Enums::OpClassStrings[inst->opClass()] << " : "; + } + + if (IsOn(ExecResult) && data_status != DataInvalid) { + ccprintf(outs, " D=%#018x", data.as_int); + } - if (IsOn(ExecEffAddr) && addr_valid) - outs << " A=0x" << hex << addr; + if (IsOn(ExecEffAddr) && addr_valid) + outs << " A=0x" << hex << addr; - if (IsOn(ExecFetchSeq) && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; + if (IsOn(ExecFetchSeq) && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; - if (IsOn(ExecCPSeq) && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; + if (IsOn(ExecCPSeq) && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; + } // // End of line... @@ -106,6 +125,29 @@ Trace::ExeTracerRecord::dump() outs << endl; } +void +Trace::ExeTracerRecord::dump() +{ + /* + * The behavior this check tries to achieve is that if ExecMacro is on, + * the macroop will be printed. If it's on and microops are also on, it's + * printed before the microops start printing to give context. If the + * microops aren't printed, then it's printed only when the final microop + * finishes. Macroops then behave like regular instructions and don't + * complete/print when they fault. + */ + if (IsOn(ExecMacro) && staticInst->isMicroop() && + ((IsOn(ExecMicro) && + macroStaticInst && staticInst->isFirstMicroop()) || + (!IsOn(ExecMicro) && + macroStaticInst && staticInst->isLastMicroop()))) { + traceInst(macroStaticInst, false); + } + if (IsOn(ExecMicro) || !staticInst->isMicroop()) { + traceInst(staticInst, true); + } +} + /* namespace Trace */ } //////////////////////////////////////////////////////////////////////// diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh index 84660432b..e49a2bb59 100644 --- a/src/cpu/exetrace.hh +++ b/src/cpu/exetrace.hh @@ -47,12 +47,17 @@ class ExeTracerRecord : public InstRecord { public: ExeTracerRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } + void traceInst(StaticInstPtr inst, bool ran); + void dump(); + virtual void dumpTicks(std::ostream &outs); }; class ExeTracer : public InstTracer @@ -64,7 +69,8 @@ class ExeTracer : public InstTracer InstRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (!IsOn(ExecEnable)) return NULL; @@ -76,7 +82,7 @@ class ExeTracer : public InstTracer return NULL; return new ExeTracerRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py new file mode 100644 index 000000000..9faadc68c --- /dev/null +++ b/src/cpu/inorder/InOrderCPU.py @@ -0,0 +1,79 @@ +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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. +# +# Authors: Korey Sewell + +from m5.params import * +from m5.proxy import * +from m5 import build_env +from BaseCPU import BaseCPU + +class InOrderCPU(BaseCPU): + type = 'InOrderCPU' + activity = Param.Unsigned(0, "Initial count") + + cachePorts = Param.Unsigned(2, "Cache Ports") + stageWidth = Param.Unsigned(1, "Stage width") + + fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from") + dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from") + icache_port = Port("Instruction Port") + dcache_port = Port("Data Port") + _mem_ports = ['icache_port', 'dcache_port'] + + predType = Param.String("tournament", "Branch predictor type ('local', 'tournament')") + localPredictorSize = Param.Unsigned(2048, "Size of local predictor") + localCtrBits = Param.Unsigned(2, "Bits per counter") + localHistoryTableSize = Param.Unsigned(2048, "Size of local history table") + localHistoryBits = Param.Unsigned(11, "Bits for the local history") + globalPredictorSize = Param.Unsigned(8192, "Size of global predictor") + globalCtrBits = Param.Unsigned(2, "Bits per counter") + globalHistoryBits = Param.Unsigned(13, "Bits of history") + choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor") + choiceCtrBits = Param.Unsigned(2, "Bits of choice counters") + + BTBEntries = Param.Unsigned(4096, "Number of BTB entries") + BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits") + + RASSize = Param.Unsigned(16, "RAS size") + + instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") + functionTrace = Param.Bool(False, "Enable function trace") + functionTraceStart = Param.Tick(0, "Cycle to start function trace") + stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU") + + memBlockSize = Param.Unsigned(64, "Memory Block Size") + + multLatency = Param.Unsigned(1, "Latency for Multiply Operations") + multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations") + div8Latency = Param.Unsigned(1, "Latency for 8-bit Divide Operations") + div8RepeatRate = Param.Unsigned(1, "Repeat Rate for 8-bit Divide Operations") + div16Latency = Param.Unsigned(1, "Latency for 16-bit Divide Operations") + div16RepeatRate = Param.Unsigned(1, "Repeat Rate for 16-bit Divide Operations") + div24Latency = Param.Unsigned(1, "Latency for 24-bit Divide Operations") + div24RepeatRate = Param.Unsigned(1, "Repeat Rate for 24-bit Divide Operations") + div32Latency = Param.Unsigned(1, "Latency for 32-bit Divide Operations") + div32RepeatRate = Param.Unsigned(1, "Repeat Rate for 32-bit Divide Operations") diff --git a/src/cpu/inorder/InOrderTrace.py b/src/cpu/inorder/InOrderTrace.py new file mode 100644 index 000000000..3453fa675 --- /dev/null +++ b/src/cpu/inorder/InOrderTrace.py @@ -0,0 +1,35 @@ +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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. +# +# Authors: Korey Sewell + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class InOrderTrace(InstTracer): + type = 'InOrderTrace' + cxx_class = 'Trace::InOrderTrace' diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript new file mode 100644 index 000000000..af237a777 --- /dev/null +++ b/src/cpu/inorder/SConscript @@ -0,0 +1,90 @@ +# -*- mode:python -*- + +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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. +# +# Authors: Korey Sewell + +Import('*') + +if 'InOrderCPU' in env['CPU_MODELS']: + SimObject('InOrderCPU.py') + SimObject('InOrderTrace.py') + + TraceFlag('ResReqCount') + TraceFlag('FreeList') + TraceFlag('InOrderStage') + TraceFlag('InOrderStall') + TraceFlag('InOrderCPU') + TraceFlag('RegDepMap') + TraceFlag('InOrderDynInst') + TraceFlag('Resource') + TraceFlag('InOrderAGEN') + TraceFlag('InOrderFetchSeq') + TraceFlag('InOrderTLB') + TraceFlag('InOrderCachePort') + TraceFlag('InOrderBPred') + TraceFlag('InOrderDecode') + TraceFlag('InOrderExecute') + TraceFlag('InOrderInstBuffer') + TraceFlag('InOrderUseDef') + TraceFlag('InOrderMDU') + TraceFlag('InOrderGraduation') + TraceFlag('RefCount') + + CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', + 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred', + 'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef', + 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource']) + + Source('pipeline_traits.cc') + Source('inorder_dyn_inst.cc') + Source('inorder_cpu_builder.cc') + Source('inorder_trace.cc') + Source('pipeline_stage.cc') + Source('first_stage.cc') + Source('resource.cc') + Source('resources/agen_unit.cc') + Source('resources/execution_unit.cc') + Source('resources/bpred_unit.cc') + Source('resources/branch_predictor.cc') + Source('resources/cache_unit.cc') + Source('resources/use_def.cc') + Source('resources/decode_unit.cc') + Source('resources/inst_buffer.cc') + Source('resources/graduation_unit.cc') + Source('resources/tlb_unit.cc') + Source('resources/fetch_seq_unit.cc') + Source('resources/mult_div_unit.cc') + Source('resource_pool.cc') + Source('reg_dep_map.cc') + Source('../o3/btb.cc') + Source('../o3/tournament_pred.cc') + Source('../o3/2bit_local_pred.cc') + Source('../o3/ras.cc') + Source('thread_context.cc') + Source('cpu.cc') + diff --git a/src/cpu/inorder/SConsopts b/src/cpu/inorder/SConsopts new file mode 100644 index 000000000..82ebd18ea --- /dev/null +++ b/src/cpu/inorder/SConsopts @@ -0,0 +1,33 @@ +# -*- mode:python -*- + +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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. +# +# Authors: Korey Sewell + +Import('*') + +all_cpu_list.append('InOrderCPU') diff --git a/src/cpu/inorder/comm.hh b/src/cpu/inorder/comm.hh new file mode 100644 index 000000000..18bb24169 --- /dev/null +++ b/src/cpu/inorder/comm.hh @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_COMM_HH__ +#define __CPU_INORDER_COMM_HH__ + +#include <vector> + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inst_seq.hh" +#include "sim/host.hh" + +/** Struct that defines the information passed from in between stages */ +/** This information mainly goes forward through the pipeline. */ +struct InterStageStruct { + int size; + ThePipeline::DynInstPtr insts[ThePipeline::StageWidth]; + bool squash; + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + InstSeqNum squashedSeqNum; + bool includeSquashInst; + + InterStageStruct() + :size(0), squash(false), + branchMispredict(false), branchTaken(false), + mispredPC(0), nextPC(0), + squashedSeqNum(0), includeSquashInst(false) + { } + +}; + +/** Turn This into a Class */ +/** Struct that defines all backwards communication. */ +struct TimeStruct { + struct stageComm { + bool squash; + bool predIncorrect; + uint64_t branchAddr; + + // @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; + + // 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; + InstSeqNum bdelayDoneSeqNum; + bool squashDelaySlot; + + //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; + + bool uncached; + ThePipeline::DynInstPtr uncachedLoad; + + bool interruptPending; + bool clearInterrupt; + }; + + stageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads]; + + bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads]; + bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads]; +}; + +#endif //__CPU_INORDER_COMM_HH__ diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc new file mode 100644 index 000000000..70877aae4 --- /dev/null +++ b/src/cpu/inorder/cpu.cc @@ -0,0 +1,1253 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/activity.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/thread_context.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "mem/translating_port.hh" +#include "sim/process.hh" +#include "sim/stat_control.hh" +#include <algorithm> + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InOrderCPU::TickEvent::TickEvent(InOrderCPU *c) + : Event(CPU_Tick_Pri), cpu(c) +{ } + + +void +InOrderCPU::TickEvent::process() +{ + cpu->tick(); +} + + +const char * +InOrderCPU::TickEvent::description() +{ + return "InOrderCPU tick event"; +} + +InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, + Fault fault, unsigned _tid, unsigned _vpe) + : Event(CPU_Tick_Pri), cpu(_cpu) +{ + setEvent(e_type, fault, _tid, _vpe); +} + +void +InOrderCPU::CPUEvent::process() +{ + switch (cpuEventType) + { + case ActivateThread: + cpu->activateThread(tid); + break; + + //@TODO: Consider Implementing "Suspend Thread" as Separate from Deallocate + case SuspendThread: // Suspend & Deallocate are same for now. + //cpu->suspendThread(tid); + //break; + case DeallocateThread: + cpu->deallocateThread(tid); + break; + + case EnableVPEs: + cpu->enableVPEs(vpe); + break; + + case DisableVPEs: + cpu->disableVPEs(tid, vpe); + break; + + case EnableThreads: + cpu->enableThreads(vpe); + break; + + case DisableThreads: + cpu->disableThreads(tid, vpe); + break; + + case Trap: + cpu->trapCPU(fault, tid); + break; + + default: + fatal("Unrecognized Event Type %d", cpuEventType); + } + + cpu->cpuEventRemoveList.push(this); +} + +const char * +InOrderCPU::CPUEvent::description() +{ + return "InOrderCPU event"; +} + +void +InOrderCPU::CPUEvent::scheduleEvent(int delay) +{ + if (squashed()) + mainEventQueue.reschedule(this,curTick + cpu->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this,curTick + cpu->ticks(delay)); +} + +void +InOrderCPU::CPUEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} + +InOrderCPU::InOrderCPU(Params *params) + : BaseCPU(params), + cpu_id(params->cpu_id), + coreType("default"), + _status(Idle), + tickEvent(this), + miscRegFile(this), + timeBuffer(2 , 2), + removeInstsThisCycle(false), + activityRec(params->name, NumStages, 10, params->activity), + switchCount(0), + deferRegistration(false/*params->deferRegistration*/), + stageTracing(params->stageTracing), + numThreads(params->numThreads), + numVirtProcs(1) +{ + cpu_params = params; + + resPool = new ResourcePool(this, params); + + // Resize for Multithreading CPUs + thread.resize(numThreads); + + int active_threads = params->workload.size(); + + if (active_threads > MaxThreads) { + panic("Workload Size too large. Increase the 'MaxThreads'" + "in your InOrder implementation or " + "edit your workload size."); + } + + // Bind the fetch & data ports from the resource pool. + fetchPortIdx = resPool->getPortIdx(params->fetchMemPort); + if (fetchPortIdx == 0) { + warn("Unable to find port to fetch instructions from.\n"); + } + + dataPortIdx = resPool->getPortIdx(params->dataMemPort); + if (dataPortIdx == 0) { + warn("Unable to find port for data.\n"); + } + + + for (int i = 0; i < numThreads; ++i) { + if (i < params->workload.size()) { + DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n", + i, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], + i); + + // Start thread's off in "Suspended" status + this->thread[i]->setStatus(ThreadContext::Suspended); + + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = params->workload[0]; + this->thread[i] = new Thread(this, i, dummy_proc, i); + } + + // Setup the TC that will serve as the interface to the threads/CPU. + InOrderThreadContext *tc = new InOrderThreadContext; + tc->cpu = this; + tc->thread = this->thread[i]; + + // Give the thread the TC. + thread[i]->tc = tc; + thread[i]->setFuncExeInst(0); + globalSeqNum[i] = 1; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + // Initialize TimeBuffer Stage Queues + for (int stNum=0; stNum < NumStages - 1; stNum++) { + stageQueue[stNum] = new StageQueue(NumStages, NumStages); + stageQueue[stNum]->id(stNum); + } + + + // Set Up Pipeline Stages + for (int stNum=0; stNum < NumStages; stNum++) { + if (stNum == 0) + pipelineStage[stNum] = new FirstStage(params, stNum); + else + pipelineStage[stNum] = new PipelineStage(params, stNum); + + pipelineStage[stNum]->setCPU(this); + pipelineStage[stNum]->setActiveThreads(&activeThreads); + pipelineStage[stNum]->setTimeBuffer(&timeBuffer); + + // Take Care of 1st/Nth stages + if (stNum > 0) + pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]); + if (stNum < NumStages - 1) + pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]); + } + + // Initialize thread specific variables + for (int tid=0; tid < numThreads; tid++) { + archRegDepMap[tid].setCPU(this); + + nonSpecInstActive[tid] = false; + nonSpecSeqNum[tid] = 0; + + squashSeqNum[tid] = MaxAddr; + lastSquashCycle[tid] = 0; + + intRegFile[tid].clear(); + floatRegFile[tid].clear(); + } + + // Update miscRegFile if necessary + if (numThreads > 1) { + miscRegFile.expandForMultithreading(numThreads, numVirtProcs); + } + + miscRegFile.clear(); + + lastRunningCycle = curTick; + contextSwitch = false; + + // Define dummy instructions and resource requests to be used. + DynInstPtr dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0); + dummyReq = new ResourceRequest(NULL, NULL, 0, 0, 0, 0); + + // Reset CPU to reset state. +#if FULL_SYSTEM + Fault resetFault = new ResetFault(); + resetFault->invoke(tcBase()); +#else + reset(); +#endif + + // Schedule First Tick Event, CPU will reschedule itself from here on out. + scheduleTickEvent(0); +} + + +void +InOrderCPU::regStats() +{ + /* Register the Resource Pool's stats here.*/ + resPool->regStats(); + + /* Register any of the InOrderCPU'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); + + threadCycles + .init(numThreads) + .name(name() + ".threadCycles") + .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)"); + + smtCycles + .name(name() + ".smtCycles") + .desc("Total number of cycles that the CPU was simultaneous multithreading.(SMT)"); + + committedInsts + .init(numThreads) + .name(name() + ".committedInsts") + .desc("Number of Instructions Simulated (Per-Thread)"); + + smtCommittedInsts + .init(numThreads) + .name(name() + ".smtCommittedInsts") + .desc("Number of SMT Instructions Simulated (Per-Thread)"); + + totalCommittedInsts + .name(name() + ".committedInsts_total") + .desc("Number of Instructions Simulated (Total)"); + + cpi + .name(name() + ".cpi") + .desc("CPI: Cycles Per Instruction (Per-Thread)") + .precision(6); + cpi = threadCycles / committedInsts; + + smtCpi + .name(name() + ".smt_cpi") + .desc("CPI: Total SMT-CPI") + .precision(6); + smtCpi = smtCycles / smtCommittedInsts; + + totalCpi + .name(name() + ".cpi_total") + .desc("CPI: Total CPI of All Threads") + .precision(6); + totalCpi = numCycles / totalCommittedInsts; + + ipc + .name(name() + ".ipc") + .desc("IPC: Instructions Per Cycle (Per-Thread)") + .precision(6); + ipc = committedInsts / threadCycles; + + smtIpc + .name(name() + ".smt_ipc") + .desc("IPC: Total SMT-IPC") + .precision(6); + smtIpc = smtCommittedInsts / smtCycles; + + totalIpc + .name(name() + ".ipc_total") + .desc("IPC: Total IPC of All Threads") + .precision(6); + totalIpc = totalCommittedInsts / numCycles; + + BaseCPU::regStats(); +} + + +void +InOrderCPU::tick() +{ + DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n"); + + ++numCycles; + + //Tick each of the stages + for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) { + pipelineStage[stNum]->tick(); + } + + // Now advance the time buffers one tick + timeBuffer.advance(); + for (int sqNum=0; sqNum < NumStages - 1; sqNum++) { + stageQueue[sqNum]->advance(); + } + activityRec.advance(); + + // Any squashed requests, events, or insts then remove them now + cleanUpRemovedReqs(); + cleanUpRemovedEvents(); + cleanUpRemovedInsts(); + + // Re-schedule CPU for this cycle + if (!tickEvent.scheduled()) { + if (_status == SwitchedOut) { + // increment stat + lastRunningCycle = curTick; + } else if (!activityRec.active()) { + DPRINTF(InOrderCPU, "sleeping CPU.\n"); + lastRunningCycle = curTick; + timesIdled++; + } else { + //Tick next_tick = curTick + cycles(1); + //tickEvent.schedule(next_tick); + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + 1)); + DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n", nextCycle() + curTick); + } + } + + tickThreadStats(); + updateThreadPriority(); +} + + +void +InOrderCPU::init() +{ + if (!deferRegistration) { + registerThreadContexts(); + } + + // 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++) { + + ThreadContext *src_tc = thread[tid]->getTC(); + + // Threads start in the Suspended State + if (src_tc->status() != ThreadContext::Suspended) { + continue; + } + + } + + // Clear inSyscall. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = false; + + // Call Initializiation Routine for Resource Pool + resPool->init(); +} + +void +InOrderCPU::readFunctional(Addr addr, uint32_t &buffer) +{ + tcBase()->getMemPort()->readBlob(addr, (uint8_t*)&buffer, sizeof(uint32_t)); + buffer = gtoh(buffer); +} + +void +InOrderCPU::reset() +{ + miscRegFile.reset(coreType, numThreads, numVirtProcs, dynamic_cast<BaseCPU*>(this)); +} + +Port* +InOrderCPU::getPort(const std::string &if_name, int idx) +{ + return resPool->getPort(if_name, idx); +} + +void +InOrderCPU::trap(Fault fault, unsigned tid, int delay) +{ + scheduleCpuEvent(Trap, fault, tid, 0/*vpe*/, delay); +} + +void +InOrderCPU::trapCPU(Fault fault, unsigned tid) +{ + fault->invoke(tcBase(tid)); +} + +void +InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault, + unsigned tid, unsigned vpe, unsigned delay) +{ + CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, vpe); + + if (delay >= 0) { + DPRINTF(InOrderCPU, "Scheduling CPU Event Type #%i for cycle %i.\n", + c_event, curTick + delay); + mainEventQueue.schedule(cpu_event,curTick + delay); + } else { + cpu_event->process(); + cpuEventRemoveList.push(cpu_event); + } + + // Broadcast event to the Resource Pool + DynInstPtr dummy_inst = new InOrderDynInst(this, NULL, getNextEventNum(), tid); + resPool->scheduleEvent(c_event, dummy_inst, 0, 0, tid); +} + +inline bool +InOrderCPU::isThreadActive(unsigned tid) +{ + list<unsigned>::iterator isActive = std::find( + activeThreads.begin(), activeThreads.end(), tid); + + return (isActive != activeThreads.end()); +} + + +void +InOrderCPU::activateThread(unsigned tid) +{ + if (!isThreadActive(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to active threads list in CPU.\n", + tid); + activeThreads.push_back(tid); + + wakeCPU(); + } +} + +void +InOrderCPU::deactivateThread(unsigned tid) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid); + + if (isThreadActive(tid)) { + DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n", + tid); + list<unsigned>::iterator thread_it = std::find(activeThreads.begin(), + activeThreads.end(), tid); + + removePipelineStalls(*thread_it); + + //@TODO: change stage status' to Idle? + + activeThreads.erase(thread_it); + } +} + +void +InOrderCPU::removePipelineStalls(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n", + tid); + + for (int stNum = 0; stNum < NumStages ; stNum++) { + pipelineStage[stNum]->removeStalls(tid); + } + +} +bool +InOrderCPU::isThreadInCPU(unsigned tid) +{ + list<unsigned>::iterator isCurrent = std::find( + currentThreads.begin(), currentThreads.end(), tid); + + return (isCurrent != currentThreads.end()); +} + +void +InOrderCPU::addToCurrentThreads(unsigned tid) +{ + if (!isThreadInCPU(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n", + tid); + currentThreads.push_back(tid); + } +} + +void +InOrderCPU::removeFromCurrentThreads(unsigned tid) +{ + if (isThreadInCPU(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n", + tid); + list<unsigned>::iterator isCurrent = std::find( + currentThreads.begin(), currentThreads.end(), tid); + currentThreads.erase(isCurrent); + } +} + +bool +InOrderCPU::isThreadSuspended(unsigned tid) +{ + list<unsigned>::iterator isSuspended = std::find( + suspendedThreads.begin(), suspendedThreads.end(), tid); + + return (isSuspended!= suspendedThreads.end()); +} + +void +InOrderCPU::enableVirtProcElement(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling " + "Enabling of concurrent virtual processor execution", + vpe); + + scheduleCpuEvent(EnableVPEs, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::enableVPEs(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Concurrent Execution " + "virtual processors %i", vpe); + + list<unsigned>::iterator thread_it = currentThreads.begin(); + + while (thread_it != currentThreads.end()) { + if (!isThreadSuspended(*thread_it)) { + activateThread(*thread_it); + } + thread_it++; + } +} + +void +InOrderCPU::disableVirtProcElement(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling " + "Disabling of concurrent virtual processor execution", + vpe); + + scheduleCpuEvent(DisableVPEs, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::disableVPEs(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Disabling Concurrent Execution of " + "virtual processors %i", vpe); + + unsigned base_vpe = TheISA::getVirtProcNum(tcBase(tid)); + + list<unsigned>::iterator thread_it = activeThreads.begin(); + + std::vector<list<unsigned>::iterator> removeList; + + while (thread_it != activeThreads.end()) { + if (base_vpe != vpe) { + removeList.push_back(thread_it); + } + thread_it++; + } + + for (int i = 0; i < removeList.size(); i++) { + activeThreads.erase(removeList[i]); + } +} + +void +InOrderCPU::enableMultiThreading(unsigned vpe) +{ + // Schedule event to take place at end of cycle + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling Enable Multithreading on " + "virtual processor %i", vpe); + + scheduleCpuEvent(EnableThreads, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::enableThreads(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Multithreading on " + "virtual processor %i", vpe); + + list<unsigned>::iterator thread_it = currentThreads.begin(); + + while (thread_it != currentThreads.end()) { + if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) { + if (!isThreadSuspended(*thread_it)) { + activateThread(*thread_it); + } + } + thread_it++; + } +} +void +InOrderCPU::disableMultiThreading(unsigned tid, unsigned vpe) +{ + // Schedule event to take place at end of cycle + DPRINTF(InOrderCPU, "[tid:%i]: Scheduling Disable Multithreading on " + "virtual processor %i", tid, vpe); + + scheduleCpuEvent(DisableThreads, NoFault, tid, vpe); +} + +void +InOrderCPU::disableThreads(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Disabling Multithreading on " + "virtual processor %i", tid, vpe); + + list<unsigned>::iterator thread_it = activeThreads.begin(); + + std::vector<list<unsigned>::iterator> removeList; + + while (thread_it != activeThreads.end()) { + if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) { + removeList.push_back(thread_it); + } + thread_it++; + } + + for (int i = 0; i < removeList.size(); i++) { + activeThreads.erase(removeList[i]); + } +} + +void +InOrderCPU::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); + } +} + +inline void +InOrderCPU::tickThreadStats() +{ + /** Keep track of cycles that each thread is active */ + list<unsigned>::iterator thread_it = activeThreads.begin(); + while (thread_it != activeThreads.end()) { + threadCycles[*thread_it]++; + thread_it++; + } + + // Keep track of cycles where SMT is active + if (activeThreads.size() > 1) { + smtCycles++; + } +} + +void +InOrderCPU::activateContext(unsigned tid, int delay) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid); + + scheduleCpuEvent(ActivateThread, NoFault, tid, 0/*vpe*/, delay); + + // Be sure to signal that there's some activity so the CPU doesn't + // deschedule itself. + activityRec.activity(); + + _status = Running; +} + + +void +InOrderCPU::suspendContext(unsigned tid, int delay) +{ + scheduleCpuEvent(SuspendThread, NoFault, tid, 0/*vpe*/, delay); + //_status = Idle; +} + +void +InOrderCPU::suspendThread(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid: %i]: Suspended ...\n", tid); + deactivateThread(tid); +} + +void +InOrderCPU::deallocateContext(unsigned tid, int delay) +{ + scheduleCpuEvent(DeallocateThread, NoFault, tid, 0/*vpe*/, delay); +} + +void +InOrderCPU::deallocateThread(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid); + + removeFromCurrentThreads(tid); + + deactivateThread(tid); + + squashThreadInPipeline(tid); +} + +void +InOrderCPU::squashThreadInPipeline(unsigned tid) +{ + //Squash all instructions in each stage + for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) { + pipelineStage[stNum]->squash(0 /*seq_num*/, tid); + } +} + +void +InOrderCPU::haltContext(unsigned tid, int delay) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Halt context called.\n", tid); + + // Halt is same thing as deallocate for now + // @TODO: Differentiate between halt & deallocate in the CPU + // model + deallocateContext(tid, delay); +} + +void +InOrderCPU::insertThread(unsigned tid) +{ + panic("Unimplemented Function\n."); +} + +void +InOrderCPU::removeThread(unsigned tid) +{ + DPRINTF(InOrderCPU, "Removing Thread %i from CPU.\n", tid); + + /** Broadcast to CPU resources*/ +} + +void +InOrderCPU::activateWhenReady(int tid) +{ + panic("Unimplemented Function\n."); +} + + +uint64_t +InOrderCPU::readPC(unsigned tid) +{ + return PC[tid]; +} + + +void +InOrderCPU::setPC(Addr new_PC, unsigned tid) +{ + PC[tid] = new_PC; +} + + +uint64_t +InOrderCPU::readNextPC(unsigned tid) +{ + return nextPC[tid]; +} + + +void +InOrderCPU::setNextPC(uint64_t new_NPC, unsigned tid) +{ + nextPC[tid] = new_NPC; +} + + +uint64_t +InOrderCPU::readNextNPC(unsigned tid) +{ + return nextNPC[tid]; +} + + +void +InOrderCPU::setNextNPC(uint64_t new_NNPC, unsigned tid) +{ + nextNPC[tid] = new_NNPC; +} + +uint64_t +InOrderCPU::readIntReg(int reg_idx, unsigned tid) +{ + return intRegFile[tid].readReg(reg_idx); +} + +FloatReg +InOrderCPU::readFloatReg(int reg_idx, unsigned tid, int width) +{ + + return floatRegFile[tid].readReg(reg_idx, width); +} + +FloatRegBits +InOrderCPU::readFloatRegBits(int reg_idx, unsigned tid, int width) +{; + return floatRegFile[tid].readRegBits(reg_idx, width); +} + +void +InOrderCPU::setIntReg(int reg_idx, uint64_t val, unsigned tid) +{ + intRegFile[tid].setReg(reg_idx, val); +} + + +void +InOrderCPU::setFloatReg(int reg_idx, FloatReg val, unsigned tid, int width) +{ + floatRegFile[tid].setReg(reg_idx, val, width); +} + + +void +InOrderCPU::setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, int width) +{ + floatRegFile[tid].setRegBits(reg_idx, val, width); +} + +uint64_t +InOrderCPU::readRegOtherThread(unsigned reg_idx, unsigned tid) +{ + // If Default value is set, then retrieve target thread + if (tid == -1) { + tid = TheISA::getTargetThread(tcBase(tid)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + return readIntReg(reg_idx, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + return readFloatRegBits(reg_idx, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + return readMiscReg(reg_idx, tid); // Misc. Register File + } +} +void +InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val, unsigned tid) +{ + // If Default value is set, then retrieve target thread + if (tid == -1) { + tid = TheISA::getTargetThread(tcBase(tid)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + setIntReg(reg_idx, val, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + setFloatRegBits(reg_idx, val, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + setMiscReg(reg_idx, val, tid); // Misc. Register File + } +} + +MiscReg +InOrderCPU::readMiscRegNoEffect(int misc_reg, unsigned tid) +{ + return miscRegFile.readRegNoEffect(misc_reg, tid); +} + +MiscReg +InOrderCPU::readMiscReg(int misc_reg, unsigned tid) +{ + return miscRegFile.readReg(misc_reg, tcBase(tid), tid); +} + +void +InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid) +{ + miscRegFile.setRegNoEffect(misc_reg, val, tid); +} + +void +InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +{ + miscRegFile.setReg(misc_reg, val, tcBase(tid), tid); +} + + +InOrderCPU::ListIt +InOrderCPU::addInst(DynInstPtr &inst) +{ + int tid = inst->readTid(); + + instList[tid].push_back(inst); + + return --(instList[tid].end()); +} + +void +InOrderCPU::instDone(DynInstPtr inst, unsigned tid) +{ + // Set the CPU's PCs - This contributes to the precise state of the CPU which can be used + // when restoring a thread to the CPU after a fork or after an exception + // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if it's a branch or not + setPC(inst->readPC(), tid); + setNextPC(inst->readNextPC(), tid); + setNextNPC(inst->readNextNPC(), tid); + + // Finalize Trace Data For Instruction + if (inst->traceData) { + //inst->traceData->setCycle(curTick); + inst->traceData->setFetchSeq(inst->seqNum); + //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst); + inst->traceData->dump(); + delete inst->traceData; + inst->traceData = NULL; + } + + // Set Last Graduated Instruction In Thread State + //thread[tid]->lastGradInst = inst; + + // Increment thread-state's instruction count + thread[tid]->numInst++; + + // Increment thread-state's instruction stats + thread[tid]->numInsts++; + + // Count committed insts per thread stats + committedInsts[tid]++; + + // Count total insts committed stat + totalCommittedInsts++; + + // Count SMT-committed insts per thread stat + if (numActiveThreads() > 1) { + smtCommittedInsts[tid]++; + } + + // Check for instruction-count-based events. + comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); + + // Broadcast to other resources an instruction + // has been completed + resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, tid); + + // Finally, remove instruction from CPU + removeInst(inst); +} + +void +InOrderCPU::addToRemoveList(DynInstPtr &inst) +{ + removeInstsThisCycle = true; + + removeList.push(inst->getInstListIt()); +} + +void +InOrderCPU::removeInst(DynInstPtr &inst) +{ + DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x " + "[sn:%lli]\n", + inst->threadNumber, inst->readPC(), inst->seqNum); + + removeInstsThisCycle = true; + + // Remove the instruction. + removeList.push(inst->getInstListIt()); +} + +void +InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num, + unsigned tid) +{ + //assert(!instList[tid].empty()); + + removeInstsThisCycle = true; + + ListIt inst_iter = instList[tid].end(); + + inst_iter--; + + DPRINTF(InOrderCPU, "Deleting instructions from CPU 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[tid].begin()); + + squashInstIt(inst_iter, tid); + + inst_iter--; + + if (break_loop) + break; + } +} + + +inline void +InOrderCPU::squashInstIt(const ListIt &instIt, const unsigned &tid) +{ + if ((*instIt)->threadNumber == tid) { + DPRINTF(InOrderCPU, "Squashing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*instIt)->threadNumber, + (*instIt)->seqNum, + (*instIt)->readPC()); + + (*instIt)->setSquashed(); + + removeList.push(instIt); + } +} + + +void +InOrderCPU::cleanUpRemovedInsts() +{ + while (!removeList.empty()) { + DPRINTF(InOrderCPU, "Removing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*removeList.front())->threadNumber, + (*removeList.front())->seqNum, + (*removeList.front())->readPC()); + + DynInstPtr inst = *removeList.front(); + int tid = inst->threadNumber; + + // Make Sure Resource Schedule Is Emptied Out + ThePipeline::ResSchedule *inst_sched = &inst->resSched; + while (!inst_sched->empty()) { + ThePipeline::ScheduleEntry* sch_entry = inst_sched->top(); + inst_sched->pop(); + delete sch_entry; + } + + // Remove From Register Dependency Map, If Necessary + archRegDepMap[(*removeList.front())->threadNumber]. + remove((*removeList.front())); + + + // Clear if Non-Speculative + if (inst->staticInst && + inst->seqNum == nonSpecSeqNum[tid] && + nonSpecInstActive[tid] == true) { + nonSpecInstActive[tid] = false; + } + + instList[tid].erase(removeList.front()); + + removeList.pop(); + + DPRINTF(RefCount, "pop from remove list: [sn:%i]: Refcount = %i.\n", + inst->seqNum, + 0/*inst->curCount()*/); + + } + + removeInstsThisCycle = false; +} + +void +InOrderCPU::cleanUpRemovedReqs() +{ + while (!reqRemoveList.empty()) { + ResourceRequest *res_req = reqRemoveList.front(); + + DPRINTF(RefCount, "[tid:%i]: Removing Request, " + "[sn:%lli] [slot:%i] [stage_num:%i] [res:%s] [refcount:%i].\n", + res_req->inst->threadNumber, + res_req->inst->seqNum, + res_req->getSlot(), + res_req->getStageNum(), + res_req->res->name(), + 0/*res_req->inst->curCount()*/); + + reqRemoveList.pop(); + + delete res_req; + + DPRINTF(RefCount, "after remove request: [sn:%i]: Refcount = %i.\n", + res_req->inst->seqNum, + 0/*res_req->inst->curCount()*/); + } +} + +void +InOrderCPU::cleanUpRemovedEvents() +{ + while (!cpuEventRemoveList.empty()) { + Event *cpu_event = cpuEventRemoveList.front(); + cpuEventRemoveList.pop(); + delete cpu_event; + } +} + + +void +InOrderCPU::dumpInsts() +{ + int num = 0; + + ListIt inst_list_it = instList[0].begin(); + + cprintf("Dumping Instruction List\n"); + + while (inst_list_it != instList[0].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; + } +} + +void +InOrderCPU::wakeCPU() +{ + if (/*activityRec.active() || */tickEvent.scheduled()) { + DPRINTF(Activity, "CPU already running.\n"); + return; + } + + DPRINTF(Activity, "Waking up CPU\n"); + + //@todo: figure out how to count idleCycles correctly + //idleCycles += (curTick - 1) - lastRunningCycle; + + mainEventQueue.schedule(&tickEvent, curTick); +} + +void +InOrderCPU::syscall(int64_t callnum, int tid) +{ + DPRINTF(InOrderCPU, "[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(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); + + // Clear Non-Speculative Block Variable + nonSpecInstActive[tid] = false; +} + +Fault +InOrderCPU::read(DynInstPtr inst) +{ + Resource *mem_res = resPool->getResource(dataPortIdx); + return mem_res->doDataAccess(inst); +} + +Fault +InOrderCPU::write(DynInstPtr inst) +{ + Resource *mem_res = resPool->getResource(dataPortIdx); + return mem_res->doDataAccess(inst); +} diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh new file mode 100644 index 000000000..adcd28019 --- /dev/null +++ b/src/cpu/inorder/cpu.hh @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_CPU_HH__ +#define __CPU_INORDER_CPU_HH__ + +#include <iostream> +#include <list> +#include <queue> +#include <set> +#include <vector> + +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/activity.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/o3/dep_graph.hh" +#include "cpu/o3/rename_map.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" +#include "sim/process.hh" + +class ThreadContext; +class MemInterface; +class MemObject; +class Process; +class ResourcePool; + +class InOrderCPU : public BaseCPU +{ + + protected: + typedef ThePipeline::Params Params; + typedef InOrderThreadState Thread; + + //ISA TypeDefs + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + + //DynInstPtr TypeDefs + typedef ThePipeline::DynInstPtr DynInstPtr; + typedef std::list<DynInstPtr>::iterator ListIt; + + //TimeBuffer TypeDefs + typedef TimeBuffer<InterStageStruct> StageQueue; + + friend class Resource; + + public: + /** Constructs a CPU with the given parameters. */ + InOrderCPU(Params *params); + + /** CPU ID */ + int cpu_id; + + /** Type of core that this is */ + std::string coreType; + + int readCpuId() { return cpu_id; } + + void setCpuId(int val) { cpu_id = val; } + + Params *cpu_params; + + TheISA::ITB * itb; + TheISA::DTB * dtb; + + public: + enum Status { + Running, + Idle, + Halted, + Blocked, + SwitchedOut + }; + + /** Overall CPU status. */ + Status _status; + + private: + /** Define TickEvent for the CPU */ + class TickEvent : public Event + { + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Constructs a tick event. */ + TickEvent(InOrderCPU *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()) + mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay))); + else if (!tickEvent.scheduled()) + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay))); + } + + /** Unschedule tick event, regardless of its current state. */ + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + public: + // List of Events That can be scheduled from + // within the CPU. + // NOTE(1): The Resource Pool also uses this event list + // to schedule events broadcast to all resources interfaces + // NOTE(2): CPU Events usually need to schedule a corresponding resource + // pool event. + enum CPUEventType { + ActivateThread, + DeallocateThread, + SuspendThread, + DisableThreads, + EnableThreads, + DisableVPEs, + EnableVPEs, + Trap, + InstGraduated, + SquashAll, + UpdatePCs, + NumCPUEvents + }; + + /** Define CPU Event */ + class CPUEvent : public Event + { + protected: + InOrderCPU *cpu; + + public: + CPUEventType cpuEventType; + unsigned tid; + unsigned vpe; + Fault fault; + + public: + /** Constructs a CPU event. */ + CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault, + unsigned _tid, unsigned _vpe); + + /** Set Type of Event To Be Scheduled */ + void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe) + { + fault = _fault; + cpuEventType = e_type; + tid = _tid; + vpe = _vpe; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + /** Schedule a CPU Event */ + void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid, + unsigned vpe, unsigned delay = 0); + + public: + /** Interface between the CPU and CPU resources. */ + ResourcePool *resPool; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** Used by resources to signify a denied access to a resource. */ + ResourceRequest *dummyReq; + + /** Identifies the resource id that identifies a fetch + * access unit. + */ + unsigned fetchPortIdx; + + /** Identifies the resource id that identifies a data + * access unit. + */ + unsigned dataPortIdx; + + /** The Pipeline Stages for the CPU */ + PipelineStage *pipelineStage[ThePipeline::NumStages]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** The Register File for the CPU */ + TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];; + TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];; + TheISA::MiscRegFile miscRegFile; + + /** Dependency Tracker for Integer & Floating Point Regs */ + RegDepMap archRegDepMap[ThePipeline::MaxThreads]; + + /** Global communication structure */ + TimeBuffer<TimeStruct> timeBuffer; + + /** Communication structure that sits in between pipeline stages */ + StageQueue *stageQueue[ThePipeline::NumStages-1]; + + public: + + /** Registers statistics. */ + void regStats(); + + /** 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(); + + /** Reset State in the CPU */ + void reset(); + + /** Get a Memory Port */ + Port* getPort(const std::string &if_name, int idx = 0); + + /** trap() - sets up a trap event on the cpuTraps to handle given fault. + * trapCPU() - Traps to handle given fault + */ + void trap(Fault fault, unsigned tid, int delay = 0); + void trapCPU(Fault fault, unsigned tid); + + /** 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); + + /** Add Thread to Active Threads List. */ + void activateContext(unsigned tid, int delay = 0); + void activateThread(unsigned tid); + + /** Remove Thread from Active Threads List */ + void suspendContext(unsigned tid, int delay = 0); + void suspendThread(unsigned tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(unsigned tid, int delay = 0); + void deallocateThread(unsigned tid); + void deactivateThread(unsigned tid); + + int + contextId() + { + hack_once("return a bogus context id"); + return 0; + } + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(unsigned tid, int delay = 0); + + void removePipelineStalls(unsigned tid); + + void squashThreadInPipeline(unsigned tid); + + /// Notify the CPU to enable a virtual processor element. + virtual void enableVirtProcElement(unsigned vpe); + void enableVPEs(unsigned vpe); + + /// Notify the CPU to disable a virtual processor element. + virtual void disableVirtProcElement(unsigned tid, unsigned vpe); + void disableVPEs(unsigned tid, unsigned vpe); + + /// Notify the CPU that multithreading is enabled. + virtual void enableMultiThreading(unsigned vpe); + void enableThreads(unsigned vpe); + + /// Notify the CPU that multithreading is disabled. + virtual void disableMultiThreading(unsigned tid, unsigned vpe); + void disableThreads(unsigned tid, unsigned vpe); + + // Sets a thread-rescheduling condition. + void setThreadRescheduleCondition(uint32_t tid) + { + //@TODO: IMPLEMENT ME + } + + /** 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(); + + /** Switches a Pipeline Stage to Active. (Unused currently) */ + void switchToActive(int stage_idx) + { /*pipelineStage[stage_idx]->switchToActive();*/ } + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum getAndIncrementInstSeq(unsigned tid) + { return globalSeqNum[tid]++; } + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum nextInstSeqNum(unsigned tid) + { return globalSeqNum[tid]; } + + /** Increment Instruction Sequence Number */ + void incrInstSeqNum(unsigned tid) + { globalSeqNum[tid]++; } + + /** Set Instruction Sequence Number */ + void setInstSeqNum(unsigned tid, InstSeqNum seq_num) + { + globalSeqNum[tid] = seq_num; + } + + /** Get & Update Next Event Number */ + InstSeqNum getNextEventNum() + { + return cpuEventNum++; + } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->getDataAsid(); } + + /** Register file accessors */ + uint64_t readIntReg(int reg_idx, unsigned tid); + + FloatReg readFloatReg(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + FloatRegBits readFloatRegBits(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + void setIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setFloatReg(int reg_idx, FloatReg val, unsigned tid, + int width = TheISA::SingleWidth); + + void setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, + int width = TheISA::SingleWidth); + + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg, unsigned tid = 0); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0); + + /** Reads a int/fp/misc reg. from another thread depending on ISA-defined + * target thread + */ + uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1); + + /** Sets a int/fp/misc reg. from another thread depending on an ISA-defined + * target thread + */ + void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid); + + /** Reads the commit PC of a specific thread. */ + uint64_t readPC(unsigned tid); + + /** Sets the commit PC of a specific thread. */ + void setPC(Addr new_PC, unsigned tid); + + /** Reads the next PC of a specific thread. */ + uint64_t readNextPC(unsigned tid); + + /** Sets the next PC of a specific thread. */ + void setNextPC(uint64_t val, unsigned tid); + + /** Reads the next NPC of a specific thread. */ + uint64_t readNextNPC(unsigned tid); + + /** Sets the next NPC of a specific thread. */ + void setNextNPC(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(DynInstPtr inst, unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from CPU */ + void removeInst(DynInstPtr &inst); + + /** Remove all instructions younger than the given sequence number. */ + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); + + /** Removes the instruction pointed to by the iterator. */ + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); + + /** Cleans up all instructions on the instruction remove list. */ + void cleanUpRemovedInsts(); + + /** Cleans up all instructions on the request remove list. */ + void cleanUpRemovedReqs(); + + /** Cleans up all instructions on the CPU event remove list. */ + void cleanUpRemovedEvents(); + + /** Debug function to print all instructions on the list. */ + void dumpInsts(); + + /** Forwards an instruction read to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault read(DynInstPtr inst); + + /** Forwards an instruction write. to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault write(DynInstPtr inst); + + /** Executes a syscall.*/ + void syscall(int64_t callnum, int tid); + + public: + /** Per-Thread List of all the instructions in flight. */ + std::list<DynInstPtr> instList[ThePipeline::MaxThreads]; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue<ListIt> removeList; + + /** List of all the resource requests that will be removed at the end of this + * cycle. + */ + std::queue<ResourceRequest*> reqRemoveList; + + /** List of all the cpu event requests that will be removed at the end of + * the current cycle. + */ + std::queue<Event*> cpuEventRemoveList; + + /** Records if instructions need to be removed this cycle due to + * being retired or squashed. + */ + bool removeInstsThisCycle; + + /** True if there is non-speculative Inst Active In Pipeline. Lets any + * execution unit know, NOT to execute while the instruction is active. + */ + bool nonSpecInstActive[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of current non-speculative instruction. */ + InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of last instruction squashed in pipeline */ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Last Cycle that the CPU squashed instruction end. */ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + std::list<unsigned> fetchPriorityList; + + protected: + /** Active Threads List */ + std::list<unsigned> activeThreads; + + /** Current Threads List */ + std::list<unsigned> currentThreads; + + /** Suspended Threads List */ + std::list<unsigned> suspendedThreads; + + /** Thread Status Functions (Unused Currently) */ + bool isThreadInCPU(unsigned tid); + bool isThreadActive(unsigned tid); + bool isThreadSuspended(unsigned tid); + void addToCurrentThreads(unsigned tid); + void removeFromCurrentThreads(unsigned tid); + + private: + /** The activity recorder; used to tell if the CPU has any + * activity remaining or if it can go to idle and deschedule + * itself. + */ + ActivityRecorder activityRec; + + public: + void readFunctional(Addr addr, uint32_t &buffer); + + /** Number of Active Threads in the CPU */ + int numActiveThreads() { return activeThreads.size(); } + + /** Records that there was time buffer activity this cycle. */ + void activityThisCycle() { activityRec.activity(); } + + /** Changes a stage's status to active within the activity recorder. */ + void activateStage(const int idx) + { activityRec.activateStage(idx); } + + /** Changes a stage's status to inactive within the activity recorder. */ + void deactivateStage(const int 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(); + + // LL/SC debug functionality + unsigned stCondFails; + unsigned readStCondFailures() { return stCondFails; } + unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; } + + /** Returns a pointer to a thread context. */ + ThreadContext *tcBase(unsigned tid = 0) + { + return thread[tid]->getTC(); + } + + /** The global sequence number counter. */ + InstSeqNum globalSeqNum[ThePipeline::MaxThreads]; + + /** The global event number counter. */ + InstSeqNum cpuEventNum; + + /** Counter of how many stages have completed switching out. */ + int switchCount; + + /** Pointers to all of the threads in the CPU. */ + std::vector<Thread *> thread; + + /** 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; + + /** Per-Stage Instruction Tracing */ + bool stageTracing; + + /** 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 the CPU can process */ + unsigned numThreads; + + /** Number of Virtual Processors the CPU can process */ + unsigned numVirtProcs; + + /** Update Thread , used for statistic purposes*/ + inline void tickThreadStats(); + + /** Per-Thread Tick */ + Stats::Vector threadCycles; + + /** Tick for SMT */ + Stats::Scalar smtCycles; + + /** 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 number of committed instructions per thread. */ + Stats::Vector smtCommittedInsts; + + /** Stat for the total number of committed instructions. */ + Stats::Scalar totalCommittedInsts; + + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + + /** Stat for the SMT-CPI per thread. */ + Stats::Formula smtCpi; + + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + + /** Stat for the total IPC. */ + Stats::Formula smtIpc; + + /** Stat for the total IPC. */ + Stats::Formula totalIpc; +}; + +#endif // __CPU_O3_CPU_HH__ diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc new file mode 100644 index 000000000..5e389b256 --- /dev/null +++ b/src/cpu/inorder/first_stage.cc @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "base/str.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderTrace.hh" + +using namespace std; +using namespace ThePipeline; + +FirstStage::FirstStage(Params *params, unsigned stage_num) + : PipelineStage(params, stage_num), numFetchingThreads(1), + fetchPolicy(FirstStage::RoundRobin) +{ + for(int tid=0; tid < this->numThreads; tid++) { + stageStatus[tid] = Running; + } +} + +void +FirstStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + fetchPriorityList = &cpu->fetchPriorityList; + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); +} + + +void +FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + //stageStatus[tid] = Squashing; + + // Clear the instruction list and skid buffer in case they have any + // insts in them. + DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n"); + while (!insts[tid].empty()) { + if (insts[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= " + "squashing seqNum %i.\n", + tid, + insts[tid].front()->seqNum, + squash_seq_num); + + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + insts[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, insts[tid].front()->seqNum, insts[tid].front()->PC); + insts[tid].pop(); + } + + // Now that squash has propagated to the first stage, + // Alert CPU to remove instructions from the CPU instruction list. + // @todo: Move this to the CPU object. + cpu->removeInstsUntil(squash_seq_num, tid); +} + +void +FirstStage::processStage(bool &status_change) +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + status_change = checkSignalsAndUpdate(tid) || status_change; + } + + for (int threadFetched = 0; threadFetched < numFetchingThreads; + threadFetched++) { + int tid = getFetchingThread(fetchPolicy); + + if (tid >= 0) { + DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid); + processThread(status_change, tid); + } else { + DPRINTF(InOrderStage, "No more threads to fetch from.\n"); + } + } +} + +//@TODO: Note in documentation, that when you make a pipeline stage change, then +//make sure you change the first stage too +void +FirstStage::processInsts(unsigned tid) +{ + bool all_reqs_completed = true; + + for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) { + DynInstPtr inst; + bool new_inst = false; + + if (!insts[tid].empty()) { + inst = insts[tid].front(); + } else { + // Get new instruction. + new_inst = true; + + inst = new InOrderDynInst(cpu, + cpu->thread[tid], + cpu->nextInstSeqNum(tid), + tid); + +#if TRACING_ON + inst->traceData = + tracer->getInstRecord(ThePipeline::NumStages, + cpu->stageTracing, + cpu->thread[tid]->getTC()); + +#endif // TRACING_ON + + DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Add instruction to the CPU's list of instructions. + inst->setInstListIt(cpu->addInst(inst)); + + DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Create Front-End Resource Schedule For Instruction + ThePipeline::createFrontEndSchedule(inst); + } + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + all_reqs_completed = processInstSchedule(inst); + + if (!all_reqs_completed) { + if (new_inst) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all " + "requests for this stage. Keep in stage inst. " + "list.\n", tid, inst->seqNum); + insts[tid].push(inst); + } + break; + } else if (!insts[tid].empty()){ + insts[tid].pop(); + } + + sendInstToNextStage(inst); + //++stageProcessedInsts; + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +int +FirstStage::getFetchingThread(FetchPriority &fetch_priority) +{ + if (numThreads > 1) { + switch (fetch_priority) { + + case SingleThread: + return 0; + + case RoundRobin: + return roundRobin(); + + default: + return -1; + } + } else { + int tid = *((*activeThreads).begin()); + + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + return tid; + } else { + return -1; + } + } + +} + +int +FirstStage::roundRobin() +{ + list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin(); + list<unsigned>::iterator end = (*fetchPriorityList).end(); + + int high_pri; + + while (pri_iter != end) { + high_pri = *pri_iter; + + assert(high_pri <= numThreads); + + if (stageStatus[high_pri] == Running || + stageStatus[high_pri] == Idle) { + + (*fetchPriorityList).erase(pri_iter); + (*fetchPriorityList).push_back(high_pri); + + return high_pri; + } + + pri_iter++; + } + + return -1; +} diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh new file mode 100644 index 000000000..55914c85c --- /dev/null +++ b/src/cpu/inorder/first_stage.hh @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_FIRST_STAGE_HH__ +#define __CPU_INORDER_FIRST_STAGE_HH__ + +#include <queue> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "cpu/inorder/params.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" + +class InOrderCPU; + +class FirstStage : public PipelineStage { + public: + FirstStage(ThePipeline::Params *params, unsigned stage_num); + + /** Set Pointer to CPU */ + void setCPU(InOrderCPU *cpu_ptr); + + /** Evaluate Stage Info. & Execute Stage */ + void processStage(bool &status_change); + + /** Process All Instructions Available */ + void processInsts(unsigned tid); + + /** Squash Instructions Above a Seq. Num */ + void squash(InstSeqNum squash_seq_num, unsigned tid); + + /** There are no insts. coming from previous stages, so there is + * no need to sort insts here + */ + void sortInsts() {} + + /** There are no skidBuffers for the first stage. So + * just use an empty function. + */ + void skidInsert(unsigned tid) { } + + /** The number of fetching threads in the CPU */ + int numFetchingThreads; + + //@TODO: Add fetch priority information to a resource class... + /** Fetching Policy, Add new policies here.*/ + enum FetchPriority { + SingleThread, + RoundRobin + }; + + /** Fetch policy. */ + FetchPriority fetchPolicy; + + /** List that has the threads organized by priority. */ + std::list<unsigned> *fetchPriorityList; + + /** Return the next fetching thread */ + int getFetchingThread(FetchPriority &fetch_priority); + + /** Return next thred given Round Robin Policy for Thread Fetching */ + int roundRobin(); +}; + +#endif // __CPU_INORDER_FIRST_STAGE_HH__ diff --git a/src/cpu/o3/mips/thread_context.cc b/src/cpu/inorder/inorder_cpu_builder.cc index 0061a2a63..0088a3bd9 100755..100644 --- a/src/cpu/o3/mips/thread_context.cc +++ b/src/cpu/inorder/inorder_cpu_builder.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,12 +25,36 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim - * Korey Sewell + * Authors: Korey Sewell + * */ -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" +#include <string> + +#include "cpu/base.hh" +#include "cpu/inst_seq.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "params/InOrderCPU.hh" + +InOrderCPU * +InOrderCPUParams::create() +{ + int actual_num_threads = + (numThreads >= workload.size()) ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } + + numThreads = actual_num_threads; + + instShiftAmt = 2; + + return new InOrderCPU(this); +} + -template class O3ThreadContext<MipsSimpleImpl>; diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc new file mode 100644 index 000000000..ceb3cbe51 --- /dev/null +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#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/request.hh" + +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC, + Addr pred_PC, InstSeqNum seq_num, + InOrderCPU *cpu) + : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu) +{ + seqNum = seq_num; + + PC = inst_PC; + nextPC = PC + sizeof(MachInst); + nextNPC = nextPC + sizeof(MachInst); + predPC = pred_PC; + + initVars(); +} + +InOrderDynInst::InOrderDynInst(InOrderCPU *cpu, + InOrderThreadState *state, + InstSeqNum seq_num, + unsigned tid) + : traceData(NULL), cpu(cpu) +{ + seqNum = seq_num; + thread = state; + threadNumber = tid; + initVars(); +} + +InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst) + : seqNum(0), staticInst(_staticInst), traceData(NULL) +{ + initVars(); +} + +InOrderDynInst::InOrderDynInst() + : seqNum(0), traceData(NULL), cpu(cpu) +{ + initVars(); +} + +int InOrderDynInst::instcount = 0; + + +void +InOrderDynInst::setMachInst(ExtMachInst machInst) +{ + staticInst = StaticInst::decode(machInst, PC); + + 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; + } +} + +void +InOrderDynInst::initVars() +{ + req = NULL; + effAddr = 0; + physEffAddr = 0; + + readyRegs = 0; + + nextStage = 0; + nextInstStageNum = 0; + + for(int i = 0; i < MaxInstDestRegs; i++) + instResult[i].val.integer = 0; + + status.reset(); + + memAddrReady = false; + eaCalcDone = false; + memOpDone = false; + + predictTaken = false; + procDelaySlotOnMispred = false; + + lqIdx = -1; + sqIdx = -1; + + // Also make this a parameter, or perhaps get it from xc or cpu. + asid = 0; + + virtProcNumber = 0; + + // Initialize the fault to be NoFault. + fault = NoFault; + + // 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. + if (this->staticInst) { + 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; + } + } + + // Update Instruction Count for this instruction + ++instcount; + if (instcount > 500) { + fatal("Number of Active Instructions in CPU is too high. " + "(Not Dereferencing Ptrs. Correctly?)\n"); + } + + + + DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n", + threadNumber, seqNum, instcount); +} + + +InOrderDynInst::~InOrderDynInst() +{ + if (req) { + delete req; + } + + if (traceData) { + delete traceData; + } + + fault = NoFault; + + --instcount; + + deleteStages(); + + DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n", + threadNumber, seqNum, instcount); +} + +void +InOrderDynInst::setStaticInst(StaticInstPtr &static_inst) +{ + this->staticInst = static_inst; + + // 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. + if (this->staticInst) { + 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; + } + } +} + +Fault +InOrderDynInst::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). 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; +} + +Fault +InOrderDynInst::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). 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; +} + + +Fault +InOrderDynInst::completeAcc(Packet *pkt) +{ + this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); + + return this->fault; +} + +InstStage *InOrderDynInst::addStage() +{ + this->currentInstStage = new InstStage(this, nextInstStageNum++); + instStageList.push_back( this->currentInstStage ); + return this->currentInstStage; +} + +InstStage *InOrderDynInst::addStage(int stage_num) +{ + nextInstStageNum = stage_num; + return InOrderDynInst::addStage(); +} + +void InOrderDynInst::deleteStages() { + std::list<InstStage*>::iterator list_it = instStageList.begin(); + std::list<InstStage*>::iterator list_end = instStageList.end(); + + while(list_it != list_end) { + delete *list_it; + list_it++; + } +} + +Fault +InOrderDynInst::calcEA() +{ + return staticInst->eaCompInst()->execute(this, this->traceData); +} + +Fault +InOrderDynInst::memAccess() +{ + //return staticInst->memAccInst()->execute(this, this->traceData); + return initiateAcc( ); +} + +void +InOrderDynInst::syscall(int64_t callnum) +{ + cpu->syscall(callnum, this->threadNumber); +} + +void +InOrderDynInst::prefetch(Addr addr, unsigned flags) +{ + panic("Prefetch Unimplemented\n"); +} + +void +InOrderDynInst::writeHint(Addr addr, int size, unsigned flags) +{ + panic("Write-Hint Unimplemented\n"); +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +Fault +InOrderDynInst::copySrcTranslate(Addr src) +{ + // Not currently supported. + return NoFault; +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +Fault +InOrderDynInst::copy(Addr dest) +{ + // Not currently supported. + return NoFault; +} + +void +InOrderDynInst::releaseReq(ResourceRequest* req) +{ + std::list<ResourceRequest*>::iterator list_it = reqList.begin(); + std::list<ResourceRequest*>::iterator list_end = reqList.end(); + + while(list_it != list_end) { + if((*list_it)->getResIdx() == req->getResIdx() && + (*list_it)->getSlot() == req->getSlot()) { + DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n", + threadNumber, seqNum, req->res->name()); + reqList.erase(list_it); + return; + } + list_it++; + } + + panic("Releasing Res. Request That Isnt There!\n"); +} + +/** Records an integer source register being set to a value. */ +void +InOrderDynInst::setIntSrc(int idx, uint64_t val) +{ + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n", + threadNumber, seqNum, idx, val); + instSrc[idx].integer = val; +} + +/** Records an fp register being set to a value. */ +void +InOrderDynInst::setFloatSrc(int idx, FloatReg val, int width) +{ + if (width == 32) + instSrc[idx].fp = val; + else if (width == 64) + instSrc[idx].dbl = val; + else + panic("Unsupported width!"); +} + +/** Records an fp register being set to an integer value. */ +void +InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val) +{ + instSrc[idx].integer = val; +} + +/** Reads a integer register. */ +IntReg +InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, unsigned tid) +{ + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n", + threadNumber, seqNum, idx, instSrc[idx].integer); + return instSrc[idx].integer; +} + +/** Reads a FP register. */ +FloatReg +InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx, int width) +{ + return instSrc[idx].fp; +} + + +/** Reads a FP register as a integer. */ +FloatRegBits +InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx, int width) +{ + return instSrc[idx].integer; +} + +/** Reads a miscellaneous register. */ +MiscReg +InOrderDynInst::readMiscReg(int misc_reg) +{ + return this->cpu->readMiscReg(misc_reg, threadNumber); +} + +/** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ +MiscReg +InOrderDynInst::readMiscRegNoEffect(int misc_reg) +{ + return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber); +} + +/** Reads a miscellaneous register. */ +MiscReg +InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx) +{ + int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return cpu->readMiscRegNoEffect(reg, this->threadNumber); +} + +/** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ +MiscReg +InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx) +{ + int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return this->cpu->readMiscReg(reg, this->threadNumber); +} + +/** Sets a misc. register. */ +void +InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) +{ + instResult[si->destRegIdx(idx)].val.integer = val; + instResult[si->destRegIdx(idx)].tick = curTick; + + this->cpu->setMiscRegNoEffect( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); +} + +/** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ +void +InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx, + const MiscReg &val) +{ + instResult[si->destRegIdx(idx)].val.integer = val; + instResult[si->destRegIdx(idx)].tick = curTick; + + this->cpu->setMiscReg( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); +} + +MiscReg +InOrderDynInst::readRegOtherThread(unsigned reg_idx, int tid) +{ + if (tid == -1) { + tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + return this->cpu->readIntReg(reg_idx, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + return this->cpu->readFloatRegBits(reg_idx, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File + } +} + +/** Sets a Integer register. */ +void +InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val) +{ + instResult[idx].val.integer = val; + instResult[idx].tick = curTick; +} + +/** Sets a FP register. */ +void +InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width) +{ + if (width == 32) + instResult[idx].val.fp = val; + else if (width == 64) + instResult[idx].val.dbl = val; + else + panic("Unsupported Floating Point Width!"); + + instResult[idx].tick = curTick; +} + +/** Sets a FP register as a integer. */ +void +InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val, int width) +{ + instResult[idx].val.integer = val; + instResult[idx].tick = curTick; +} + +/** Sets a misc. register. */ +/* Alter this when wanting to *speculate* on Miscellaneous registers */ +void +InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val) +{ + this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber); +} + +/** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ +/* Alter this if/when wanting to *speculate* on Miscellaneous registers */ +void +InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val) +{ + this->cpu->setMiscReg(misc_reg, val, threadNumber); +} + +void +InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val, int tid) +{ + if (tid == -1) { + tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + this->cpu->setIntReg(reg_idx, val, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + this->cpu->setFloatRegBits(reg_idx, val, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File + } +} + +void +InOrderDynInst::deallocateContext(int thread_num) +{ + this->cpu->deallocateContext(thread_num); +} + +void +InOrderDynInst::enableVirtProcElement(unsigned vpe) +{ + this->cpu->enableVirtProcElement(vpe); +} + +void +InOrderDynInst::disableVirtProcElement(unsigned vpe) +{ + this->cpu->disableVirtProcElement(threadNumber, vpe); +} + +void +InOrderDynInst::enableMultiThreading(unsigned vpe) +{ + this->cpu->enableMultiThreading(vpe); +} + +void +InOrderDynInst::disableMultiThreading(unsigned vpe) +{ + this->cpu->disableMultiThreading(threadNumber, vpe); +} + +void +InOrderDynInst::setThreadRescheduleCondition(uint32_t cond) +{ + this->cpu->setThreadRescheduleCondition(cond); +} + +template<class T> +inline Fault +InOrderDynInst::read(Addr addr, T &data, unsigned flags) +{ + return cpu->read(this); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +InOrderDynInst::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +InOrderDynInst::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + +template<> +Fault +InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + +template<class T> +inline Fault +InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + //memcpy(memData, gtoh(data), sizeof(T)); + storeData = data; + + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n", + threadNumber, seqNum, memData); + return cpu->write(this); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +InOrderDynInst::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +InOrderDynInst::dump() +{ + cprintf("T%d : %#08d `", threadNumber, PC); + cout << staticInst->disassemble(PC); + cprintf("'\n"); +} + +void +InOrderDynInst::dump(std::string &outstring) +{ + std::ostringstream s; + s << "T" << threadNumber << " : 0x" << PC << " " + << staticInst->disassemble(PC); + + outstring = s.str(); +} + + +#define NOHASH +#ifndef NOHASH + +#include "base/hashmap.hh" + +unsigned int MyHashFunc(const InOrderDynInst *addr) +{ + unsigned a = (unsigned)addr; + unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; + + return hash; +} + +typedef m5::hash_map<const InOrderDynInst *, const InOrderDynInst *, MyHashFunc> +my_hash_t; + +my_hash_t thishash; +#endif diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh new file mode 100644 index 000000000..55c61ffb9 --- /dev/null +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_INORDER_DYN_INST_HH__ +#define __CPU_INORDER_DYN_INST_HH__ + +#include <bitset> +#include <list> +#include <string> + +#include "arch/faults.hh" +#include "base/fast_alloc.hh" +#include "base/trace.hh" +#include "cpu/inorder/inorder_trace.hh" +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/inst_seq.hh" +#include "cpu/op_class.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "mem/packet.hh" +#include "sim/system.hh" + +/** + * @file + * Defines a dynamic instruction context for a inorder CPU model. + */ + +// Forward declaration. +class StaticInstPtr; +class ResourceRequest; + +class InOrderDynInst : public FastAlloc, public RefCounted +{ + public: + // 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 type. + typedef TheISA::IntReg IntReg; + // Floating point register type. + typedef TheISA::FloatReg FloatReg; + // Floating point register type. + typedef TheISA::MiscReg MiscReg; + + typedef short int PhysRegIndex; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst*. + */ + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + + // The list of instructions iterator type. + typedef std::list<DynInstPtr>::iterator ListIt; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + }; + + 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. + */ + InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, + InOrderCPU *cpu); + + /** BaseDynInst constructor given a binary instruction. + * @param seq_num The sequence number of the instruction. + * @param cpu Pointer to the instruction's CPU. + * NOTE: Must set Binary Instrution through Member Function + */ + InOrderDynInst(InOrderCPU *cpu, InOrderThreadState *state, InstSeqNum seq_num, + unsigned tid); + + /** BaseDynInst constructor given a StaticInst pointer. + * @param _staticInst The StaticInst for this BaseDynInst. + */ + InOrderDynInst(StaticInstPtr &_staticInst); + + /** Skeleton Constructor. */ + InOrderDynInst(); + + /** InOrderDynInst destructor. */ + ~InOrderDynInst(); + + public: + /** The sequence number of the instruction. */ + InstSeqNum seqNum; + + /** The sequence number of the instruction. */ + InstSeqNum bdelaySeqNum; + + enum Status { + RegDepMapEntry, /// Instruction has been entered onto the RegDepMap + IqEntry, /// Instruction is in the IQ + RobEntry, /// Instruction is in the ROB + LsqEntry, /// Instruction is in the LSQ + Completed, /// Instruction has completed + ResultReady, /// Instruction has its result + CanIssue, /// Instruction can issue and execute + Issued, /// Instruction has issued + Executed, /// Instruction has executed + CanCommit, /// Instruction can commit + AtCommit, /// Instruction has reached commit + Committed, /// Instruction has committed + Squashed, /// Instruction is squashed + SquashedInIQ, /// Instruction is squashed in the IQ + SquashedInLSQ, /// Instruction is squashed in the LSQ + SquashedInROB, /// Instruction is squashed in the ROB + RecoverInst, /// Is a recover instruction + BlockingInst, /// Is a blocking instruction + ThreadsyncWait, /// Is a thread synchronization instruction + SerializeBefore, /// Needs to serialize on + /// instructions ahead of it + SerializeAfter, /// Needs to serialize instructions behind it + SerializeHandled, /// Serialization has been handled + NumStatus + }; + + /** The status of this BaseDynInst. Several bits can be set. */ + std::bitset<NumStatus> status; + + /** The thread this instruction is from. */ + short threadNumber; + + /** data address space ID, for loads & stores. */ + short asid; + + /** The virtual processor number */ + short virtProcNumber; + + /** The StaticInst used by this BaseDynInst. */ + StaticInstPtr staticInst; + + /** InstRecord that tracks this instructions. */ + Trace::InOrderTraceRecord *traceData; + + /** Pointer to the Impl's CPU object. */ + InOrderCPU *cpu; + + /** Pointer to the thread state. */ + InOrderThreadState *thread; + + /** The kind of fault this instruction has generated. */ + Fault fault; + + /** The memory request. */ + Request *req; + + /** Pointer to the data for the memory access. */ + uint8_t *memData; + + /** Data used for a store for operation. */ + uint64_t loadData; + + /** Data used for a store for operation. */ + uint64_t storeData; + + /** The resource schedule for this inst */ + ThePipeline::ResSchedule resSched; + + /** List of active resource requests for this instruction */ + std::list<ResourceRequest*> reqList; + + /** 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; + + /** How many source registers are ready. */ + unsigned readyRegs; + + /** An instruction src/dest has to be one of these types */ + union InstValue { + uint64_t integer; + float fp; + double dbl; + }; + + /** Result of an instruction execution */ + struct InstResult { + InstValue val; + Tick tick; + }; + + /** The source of the instruction; assumes for now that there's only one + * destination register. + */ + InstValue instSrc[MaxInstSrcRegs]; + + /** The result of the instruction; assumes for now that there's only one + * destination register. + */ + InstResult instResult[MaxInstDestRegs]; + + /** 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; + + /** Next 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 nextNPC; + + /** Predicted next PC. */ + Addr predPC; + + /** Address to fetch from */ + Addr fetchAddr; + + /** Address to get/write data from/to */ + Addr memAddr; + + /** Whether or not the source register is ready. + * @todo: Not sure this should be here vs the derived class. + */ + bool _readySrcRegIdx[MaxInstSrcRegs]; + + /** 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]; + + int nextStage; + + /* vars to keep track of InstStage's - used for resource sched defn */ + int nextInstStageNum; + ThePipeline::InstStage *currentInstStage; + std::list<ThePipeline::InstStage*> instStageList; + + private: + /** Function to initialize variables in the constructors. */ + void initVars(); + + public: + Tick memTime; + + //////////////////////////////////////////////////////////// + // + // BASE INSTRUCTION INFORMATION. + // + //////////////////////////////////////////////////////////// + void setMachInst(ExtMachInst inst); + + /** Sets the StaticInst. */ + void setStaticInst(StaticInstPtr &static_inst); + + /** Sets the sequence number. */ + void setSeqNum(InstSeqNum seq_num) { seqNum = seq_num; } + + /** Sets the ASID. */ + void setASID(short addr_space_id) { asid = addr_space_id; } + + /** Reads the thread id. */ + short readTid() { return threadNumber; } + + /** Sets the thread id. */ + void setTid(unsigned tid) { threadNumber = tid; } + + void setVpn(int id) { virtProcNumber = id; } + + int readVpn() { return virtProcNumber; } + + /** Sets the pointer to the thread state. */ + void setThreadState(InOrderThreadState *state) { thread = state; } + + /** Returns the thread context. */ + ThreadContext *tcBase() { return thread->getTC(); } + + /** Returns the fault type. */ + Fault getFault() { return fault; } + + //////////////////////////////////////////////////////////// + // + // 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 isCondDelaySlot() const { return staticInst->isCondDelaySlot(); } + + bool isThreadSync() const { return staticInst->isThreadSync(); } + bool isSerializing() const { return staticInst->isSerializing(); } + bool isSerializeBefore() const + { return staticInst->isSerializeBefore() || status[SerializeBefore]; } + bool isSerializeAfter() const + { return staticInst->isSerializeAfter() || status[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(); } + + ///////////////////////////////////////////// + // + // RESOURCE SCHEDULING + // + ///////////////////////////////////////////// + + void setNextStage(int stage_num) { nextStage = stage_num; } + int getNextStage() { return nextStage; } + + ThePipeline::InstStage *addStage(); + ThePipeline::InstStage *addStage(int stage); + ThePipeline::InstStage *currentStage() { return currentInstStage; } + void deleteStages(); + + /** Add A Entry To Reource Schedule */ + void addToSched(ThePipeline::ScheduleEntry* sched_entry) + { resSched.push(sched_entry); } + + + /** Print Resource Schedule */ + void printSched() + { + using namespace ThePipeline; + + ResSchedule tempSched; + std::cerr << "\tInst. Res. Schedule: "; + while (!resSched.empty()) { + std::cerr << '\t' << resSched.top()->stageNum << "-" + << resSched.top()->resNum << ", "; + + tempSched.push(resSched.top()); + resSched.pop(); + } + + std::cerr << std::endl; + resSched = tempSched; + } + + /** Return Next Resource Stage To Be Used */ + int nextResStage() + { + if (resSched.empty()) + return -1; + else + return resSched.top()->stageNum; + } + + + /** Return Next Resource To Be Used */ + int nextResource() + { + if (resSched.empty()) + return -1; + else + return resSched.top()->resNum; + } + + /** Remove & Deallocate a schedule entry */ + void popSchedEntry() + { + if (!resSched.empty()) { + ThePipeline::ScheduleEntry* sked = resSched.top(); + resSched.pop(); + delete sked; + } + } + + /** Release a Resource Request (Currently Unused) */ + void releaseReq(ResourceRequest* req); + + //////////////////////////////////////////// + // + // INSTRUCTION EXECUTION + // + //////////////////////////////////////////// + /** Returns the opclass of this instruction. */ + OpClass opClass() const { return staticInst->opClass(); } + + /** Executes the instruction.*/ + Fault execute(); + + unsigned curResSlot; + + unsigned getCurResSlot() { return curResSlot; } + + void setCurResSlot(unsigned slot_num) { curResSlot = slot_num; } + + /** Calls a syscall. */ + void syscall(int64_t callnum); + void prefetch(Addr addr, unsigned flags); + void writeHint(Addr addr, int size, unsigned flags); + Fault copySrcTranslate(Addr src); + Fault copy(Addr dest); + + //////////////////////////////////////////////////////////// + // + // MULTITHREADING INTERFACE TO CPU MODELS + // + //////////////////////////////////////////////////////////// + virtual void deallocateContext(int thread_num); + + virtual void enableVirtProcElement(unsigned vpe); + virtual void disableVirtProcElement(unsigned vpe); + + virtual void enableMultiThreading(unsigned vpe); + virtual void disableMultiThreading(unsigned vpe); + + virtual void setThreadRescheduleCondition(uint32_t cond); + + //////////////////////////////////////////////////////////// + // + // PROGRAM COUNTERS - PC/NPC/NPC + // + //////////////////////////////////////////////////////////// + /** Read the PC of this instruction. */ + const Addr readPC() const { return PC; } + + /** Sets the PC of this instruction. */ + void setPC(Addr pc) { PC = pc; } + + /** 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 next PC of this instruction (its actual target). */ + void setNextPC(uint64_t val) { nextPC = val; } + + /** Returns the next NPC. This could be the speculative next NPC if it is + * called prior to the actual branch target being calculated. + */ + Addr readNextNPC() { return nextNPC; } + + /** Set the next PC of this instruction (its actual target). */ + void setNextNPC(uint64_t val) { nextNPC = val; } + + //////////////////////////////////////////////////////////// + // + // BRANCH PREDICTION + // + //////////////////////////////////////////////////////////// + /** 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 predictTaken; } + + /** Returns whether the instruction mispredicted. */ + bool mispredicted() + { + // Special case since a not-taken, cond. delay slot, effectively + // nullifies the delay slot instruction + if (isCondDelaySlot() && !predictTaken) { + return predPC != nextPC; + } else { + return predPC != nextNPC; + } + } + + /** Returns whether the instruction mispredicted. */ + bool mistargeted() { return predPC != nextNPC; } + + /** Returns the branch target address. */ + Addr branchTarget() const { return staticInst->branchTarget(PC); } + + /** 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; } + + void setBranchPred(bool prediction) { predictTaken = prediction; } + + int squashingStage; + + bool predictTaken; + + bool procDelaySlotOnMispred; + + //////////////////////////////////////////// + // + // MEMORY ACCESS + // + //////////////////////////////////////////// + /** + * 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); + + /** Initiates a memory access - Calculate Eff. Addr & Initiate Memory Access + * Only valid for memory operations. + */ + Fault initiateAcc(); + + /** Completes a memory access - Only valid for memory operations. */ + Fault completeAcc(Packet *pkt); + + /** Calculates Eff. Addr. part of a memory instruction. */ + Fault calcEA(); + + /** Read Effective Address from instruction & do memory access */ + Fault memAccess(); + + RequestPtr memReq; + + bool memAddrReady; + + bool validMemAddr() + { return memAddrReady; } + + void setMemAddr(Addr addr) + { memAddr = addr; memAddrReady = true;} + + void unsetMemAddr() + { memAddrReady = false;} + + Addr getMemAddr() + { return memAddr; } + + int getMemAccSize() { return staticInst->memAccSize(this); } + + int getMemFlags() { return staticInst->memAccFlags(); } + + /** Sets the effective address. */ + void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; } + + /** Returns the effective address. */ + const Addr &getEA() const { return instEffAddr; } + + /** 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. + * Assume 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) + */ + bool eaSrcsReady() + { + for (int i = 1; i < numSrcRegs(); ++i) { + if (!_readySrcRegIdx[i]) + return false; + } + + return true; + } + + ////////////////////////////////////////////////// + // + // SOURCE-DESTINATION REGISTER INDEXING + // + ////////////////////////////////////////////////// + /** 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); } + + ////////////////////////////////////////////////// + // + // RENAME/PHYSICAL REGISTER FILE SUPPORT + // + ////////////////////////////////////////////////// + /** 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]; + } + + /** Returns if a source register is ready. */ + bool isReadySrcRegIdx(int idx) const + { + return this->_readySrcRegIdx[idx]; + } + + /** Records that one of the source registers is ready. */ + void markSrcRegReady() + { + if (++readyRegs == numSrcRegs()) { + status.set(CanIssue); + } + } + + /** Marks a specific register as ready. */ + void markSrcRegReady(RegIndex src_idx) + { + _readySrcRegIdx[src_idx] = true; + + markSrcRegReady(); + } + + /** 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; + } + + + PhysRegIndex readDestRegIdx(int idx) + { + return _destRegIdx[idx]; + } + + void setDestRegIdx(int idx, PhysRegIndex dest_idx) + { + _destRegIdx[idx] = dest_idx; + } + + int getDestIdxNum(PhysRegIndex dest_idx) + { + for (int i=0; i < staticInst->numDestRegs(); i++) { + if (_destRegIdx[i] == dest_idx) + return i; + } + + return -1; + } + + PhysRegIndex readSrcRegIdx(int idx) + { + return _srcRegIdx[idx]; + } + + void setSrcRegIdx(int idx, PhysRegIndex src_idx) + { + _srcRegIdx[idx] = src_idx; + } + + int getSrcIdxNum(PhysRegIndex src_idx) + { + for (int i=0; i < staticInst->numSrcRegs(); i++) { + if (_srcRegIdx[i] == src_idx) + return i; + } + + return -1; + } + + //////////////////////////////////////////////////// + // + // SOURCE-DESTINATION REGISTER VALUES + // + //////////////////////////////////////////////////// + + /** Functions that sets an integer or floating point + * source register to a value. */ + void setIntSrc(int idx, uint64_t val); + void setFloatSrc(int idx, FloatReg val, int width = 32); + void setFloatRegBitsSrc(int idx, uint64_t val); + + uint64_t* getIntSrcPtr(int idx) { return &instSrc[idx].integer; } + uint64_t readIntSrc(int idx) { return instSrc[idx].integer; } + + /** These Instructions read a integer/float/misc. source register + * value in the instruction. The instruction's execute function will + * call these and it is the interface that is used by the ISA descr. + * language (which is why the name isnt readIntSrc(...)) Note: That + * the source reg. value is set using the setSrcReg() function. + */ + IntReg readIntRegOperand(const StaticInst *si, int idx, unsigned tid=0); + FloatReg readFloatRegOperand(const StaticInst *si, int idx, + int width = TheISA::SingleWidth); + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, + int width = TheISA::SingleWidth); + MiscReg readMiscReg(int misc_reg); + MiscReg readMiscRegNoEffect(int misc_reg); + MiscReg readMiscRegOperand(const StaticInst *si, int idx); + MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx); + + /** Returns the result value instruction. */ + uint64_t readIntResult(int idx) { return instResult[idx].val.integer; } + float readFloatResult(int idx) { return instResult[idx].val.fp; } + double readDoubleResult(int idx) { return instResult[idx].val.dbl; } + Tick readResultTime(int idx) { return instResult[idx].tick; } + + uint64_t* getIntResultPtr(int idx) { return &instResult[idx].val.integer; } + + /** This is the interface that an instruction will use to write + * it's destination register. + */ + void setIntRegOperand(const StaticInst *si, int idx, IntReg val); + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, + int width = TheISA::SingleWidth); + void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val, + int width = TheISA::SingleWidth); + void setMiscReg(int misc_reg, const MiscReg &val); + void setMiscRegNoEffect(int misc_reg, const MiscReg &val); + void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val); + void setMiscRegOperandNoEffect(const StaticInst *si, int idx, const MiscReg &val); + + virtual uint64_t readRegOtherThread(unsigned idx, int tid = -1); + virtual void setRegOtherThread(unsigned idx, const uint64_t &val, int tid = -1); + + ////////////////////////////////////////////////////////////// + // + // INSTRUCTION STATUS FLAGS (READ/SET) + // + ////////////////////////////////////////////////////////////// + /** Sets this instruction as entered on the CPU Reg Dep Map */ + void setRegDepEntry() { status.set(RegDepMapEntry); } + + /** Returns whether or not the entry is on the CPU Reg Dep Map */ + bool isRegDepEntry() const { return status[RegDepMapEntry]; } + + /** Sets this instruction as completed. */ + void setCompleted() { status.set(Completed); } + + /** Returns whether or not this instruction is completed. */ + bool isCompleted() const { return status[Completed]; } + + /** Marks the result as ready. */ + void setResultReady() { status.set(ResultReady); } + + /** Returns whether or not the result is ready. */ + bool isResultReady() const { return status[ResultReady]; } + + /** Sets this instruction as ready to issue. */ + void setCanIssue() { status.set(CanIssue); } + + /** Returns whether or not this instruction is ready to issue. */ + bool readyToIssue() const { return status[CanIssue]; } + + /** Sets this instruction as issued from the IQ. */ + void setIssued() { status.set(Issued); } + + /** Returns whether or not this instruction has issued. */ + bool isIssued() const { return status[Issued]; } + + /** Sets this instruction as executed. */ + void setExecuted() { status.set(Executed); } + + /** Returns whether or not this instruction has executed. */ + bool isExecuted() const { return status[Executed]; } + + /** Sets this instruction as ready to commit. */ + void setCanCommit() { status.set(CanCommit); } + + /** Clears this instruction as being ready to commit. */ + void clearCanCommit() { status.reset(CanCommit); } + + /** Returns whether or not this instruction is ready to commit. */ + bool readyToCommit() const { return status[CanCommit]; } + + void setAtCommit() { status.set(AtCommit); } + + bool isAtCommit() { return status[AtCommit]; } + + /** Sets this instruction as committed. */ + void setCommitted() { status.set(Committed); } + + /** Returns whether or not this instruction is committed. */ + bool isCommitted() const { return status[Committed]; } + + /** Sets this instruction as squashed. */ + void setSquashed() { status.set(Squashed); } + + /** Returns whether or not this instruction is squashed. */ + bool isSquashed() const { return status[Squashed]; } + + /** Temporarily sets this instruction as a serialize before instruction. */ + void setSerializeBefore() { status.set(SerializeBefore); } + + /** Clears the serializeBefore part of this instruction. */ + void clearSerializeBefore() { status.reset(SerializeBefore); } + + /** Checks if this serializeBefore is only temporarily set. */ + bool isTempSerializeBefore() { return status[SerializeBefore]; } + + /** Temporarily sets this instruction as a serialize after instruction. */ + void setSerializeAfter() { status.set(SerializeAfter); } + + /** Clears the serializeAfter part of this instruction.*/ + void clearSerializeAfter() { status.reset(SerializeAfter); } + + /** Checks if this serializeAfter is only temporarily set. */ + bool isTempSerializeAfter() { return status[SerializeAfter]; } + + /** Sets the serialization part of this instruction as handled. */ + void setSerializeHandled() { status.set(SerializeHandled); } + + /** 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 status[SerializeHandled]; } + + 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: + /** Whether or not the memory operation is done. */ + bool memOpDone; + + public: + /** Load queue index. */ + int16_t lqIdx; + + /** Store queue index. */ + int16_t sqIdx; + + /** 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; } + + /** Count of total number of dynamic instructions. */ + static int instcount; + + /** Dumps out contents of this BaseDynInst. */ + void dump(); + + /** Dumps out contents of this BaseDynInst into given string. */ + void dump(std::string &outstring); + + + //inline int curCount() { return curCount(); } +}; + + +#endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/cpu/inorder/inorder_trace.cc b/src/cpu/inorder/inorder_trace.cc new file mode 100644 index 000000000..f12a1b7a9 --- /dev/null +++ b/src/cpu/inorder/inorder_trace.cc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + */ + +#include <iomanip> + +#include "cpu/exetrace.hh" +#include "cpu/inorder/inorder_trace.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/thread_context.hh" +#include "params/InOrderTrace.hh" + +using namespace std; +using namespace TheISA; + +namespace Trace { + +inline void +Trace::InOrderTraceRecord::dumpTicks(std::ostream &outs) +{ + if (!stageTrace) { + ccprintf(outs, "%7d: ", when); + } else { + ccprintf(outs, ""); + for (int i=0; i < stageCycle.size(); i++) { + if (i < stageCycle.size() - 1) + outs << dec << stageCycle[i] << "-"; + else + outs << dec << stageCycle[i] << ":"; + } + } +} + +InOrderTraceRecord * +InOrderTrace::getInstRecord(unsigned num_stages, bool stage_tracing, + ThreadContext *tc) +{ + if (!IsOn(ExecEnable)) + return NULL; + + if (!Trace::enabled) + return NULL; + + return new InOrderTraceRecord(num_stages, stage_tracing, tc); +} + +InOrderTraceRecord * +InOrderTrace::getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst, MicroPC upc) +{ + return new InOrderTraceRecord(ThePipeline::NumStages, true, tc); +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::InOrderTrace * +InOrderTraceParams::create() +{ + return new Trace::InOrderTrace(this); +}; + diff --git a/src/cpu/inorder/inorder_trace.hh b/src/cpu/inorder/inorder_trace.hh new file mode 100644 index 000000000..4338b438c --- /dev/null +++ b/src/cpu/inorder/inorder_trace.hh @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + */ + +#ifndef __INORDERTRACE_HH__ +#define __INORDERTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" +#include "params/InOrderTrace.hh" +#include "cpu/exetrace.hh" + +class ThreadContext; + + +namespace Trace { + +class InOrderTraceRecord : public ExeTracerRecord +{ + public: + InOrderTraceRecord(unsigned num_stages, bool _stage_tracing, + ThreadContext *_thread, bool spec = false) + : ExeTracerRecord(0, _thread, NULL, 0, spec) + { + stageTrace = _stage_tracing; + stageCycle.resize(num_stages); + } + + // Trace stage-by-stage execution of instructions. + bool stageTrace; + std::vector<Tick> stageCycle; + + void dumpTicks(std::ostream &outs); + + void + setStageCycle(int num_stage, Tick cur_cycle) + { + if (stageTrace) { + stageCycle[num_stage] = cur_cycle; + } else { + when = cur_cycle; + } + } + + void + setStaticInst(const StaticInstPtr &_staticInst) + { + staticInst = _staticInst; + } + void setPC(Addr _pc) { PC = _pc; } +}; + +class InOrderTrace : public InstTracer +{ + public: + InOrderTrace(const InOrderTraceParams *p) : InstTracer(p) + {} + + InOrderTraceRecord * + getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc); + + virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0); +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/o3/params.hh b/src/cpu/inorder/params.hh index b487778c6..51b7409ad 100755..100644 --- a/src/cpu/o3/params.hh +++ b/src/cpu/inorder/params.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * 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 @@ -25,101 +25,45 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim + * Authors: Korey Sewell */ -#ifndef __CPU_O3_PARAMS_HH__ -#define __CPU_O3_PARAMS_HH__ +#ifndef __CPU_INORDER_PARAMS_HH__ +#define __CPU_INORDER_PARAMS_HH__ -#include "cpu/o3/cpu.hh" +#include "cpu/base.hh" //Forward declarations -class FUPool; +class FunctionalMemory; +class Process; +class MemObject; +class MemInterface; /** - * This file defines the parameters that will be used for the O3CPU. + * This file defines the parameters that will be used for the InOrderCPU. * 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 O3Params : public BaseO3CPU::Params + +class InOrderParams : public BaseCPU::Params { public: - unsigned activity; - // - // Pointers to key objects - // + // Workloads #if !FULL_SYSTEM std::vector<Process *> workload; Process *process; #endif // FULL_SYSTEM - BaseCPU *checker; - // - // Caches + // Memory System/Caches // - // MemInterface *icacheInterface; - // MemInterface *dcacheInterface; - unsigned cachePorts; + std::string fetchMemPort; + std::string dataMemPort; // - // 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 dispatchWidth; - unsigned issueWidth; - unsigned wbWidth; - unsigned wbDepth; - FUPool *fuPool; - - // - // Commit - // - unsigned iewToCommitDelay; - unsigned renameToROBDelay; - unsigned commitWidth; - unsigned squashWidth; - Tick trapLatency; - Tick fetchTrapLatency; - - // - // Timebuffer sizes - // - unsigned backComSize; - unsigned forwardComSize; - - // - // Branch predictor (BP, BTB, RAS) + // Branch predictor (BP & BTB) // std::string predType; unsigned localPredictorSize; @@ -131,50 +75,50 @@ class O3Params : public BaseO3CPU::Params unsigned globalHistoryBits; unsigned choicePredictorSize; unsigned choiceCtrBits; - unsigned BTBEntries; unsigned BTBTagSize; - unsigned RASSize; - // - // Load store queue - // - unsigned LQEntries; - unsigned SQEntries; + // Pipeline Parameters + unsigned stageWidth; + + // InOrderCPU Simulation Parameters + unsigned instShiftAmt; + unsigned activity; + unsigned deferRegistration; // - // Memory dependence + // Memory Parameters // - unsigned SSITSize; - unsigned LFSTSize; + unsigned memBlockSize; // - // Miscellaneous + // Multiply Divide Unit // - unsigned numPhysIntRegs; - unsigned numPhysFloatRegs; - unsigned numIQEntries; - unsigned numROBEntries; + // @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr, + // then MDU must be defined as its own SimObject so that an arbitrary # can + // be defined with different parameters + /** Latency & Repeat Rate for Multiply Insts */ + unsigned multLatency; + unsigned multRepeatRate; - //SMT Parameters - unsigned smtNumFetchingThreads; + /** Latency & Repeat Rate for 8-bit Divide Insts */ + unsigned div8Latency; + unsigned div8RepeatRate; - std::string smtFetchPolicy; + /** Latency & Repeat Rate for 16-bit Divide Insts */ + unsigned div16Latency; + unsigned div16RepeatRate; - std::string smtIQPolicy; - unsigned smtIQThreshold; + /** Latency & Repeat Rate for 24-bit Divide Insts */ + unsigned div24Latency; + unsigned div24RepeatRate; - std::string smtLSQPolicy; - unsigned smtLSQThreshold; + /** Latency & Repeat Rate for 32-bit Divide Insts */ + unsigned div32Latency; + unsigned div32RepeatRate; - std::string smtCommitPolicy; - std::string smtROBPolicy; - unsigned smtROBThreshold; - - // Probably can get this from somewhere. - unsigned instShiftAmt; }; -#endif // __CPU_O3_ALPHA_PARAMS_HH__ +#endif // _CPU_INORDER_PARAMS_HH__ diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc new file mode 100644 index 000000000..cb69464b0 --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.cc @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "base/str.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace ThePipeline; + +PipelineStage::PipelineStage(Params *params, unsigned stage_num) + : stageNum(stage_num), stageWidth(ThePipeline::StageWidth), + numThreads(ThePipeline::MaxThreads), _status(Inactive), + stageBufferMax(ThePipeline::interStageBuffSize[stage_num]), + prevStageValid(false), nextStageValid(false) +{ + init(params); +} + +void +PipelineStage::init(Params *params) +{ + for(int tid=0; tid < numThreads; tid++) { + stageStatus[tid] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); + + if (stageNum < BackEndStartStage) + lastStallingStage[tid] = BackEndStartStage - 1; + else + lastStallingStage[tid] = NumStages - 1; + } +} + + +std::string +PipelineStage::name() const +{ + return cpu->name() + ".stage-" + to_string(stageNum); +} + + +void +PipelineStage::regStats() +{ +/* stageIdleCycles + .name(name() + ".IdleCycles") + .desc("Number of cycles stage is idle") + .prereq(stageIdleCycles); + stageBlockedCycles + .name(name() + ".BlockedCycles") + .desc("Number of cycles stage is blocked") + .prereq(stageBlockedCycles); + stageRunCycles + .name(name() + ".RunCycles") + .desc("Number of cycles stage is running") + .prereq(stageRunCycles); + stageUnblockCycles + .name(name() + ".UnblockCycles") + .desc("Number of cycles stage is unblocking") + .prereq(stageUnblockCycles); + stageSquashCycles + .name(name() + ".SquashCycles") + .desc("Number of cycles stage is squashing") + .prereq(stageSquashCycles); + stageProcessedInsts + .name(name() + ".ProcessedInsts") + .desc("Number of instructions handled by stage") + .prereq(stageProcessedInsts); + stageSquashedInsts + .name(name() + ".SquashedInsts") + .desc("Number of squashed instructions handled by stage") + .prereq(stageSquashedInsts);*/ +} + + +void +PipelineStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + dummyBufferInst = new InOrderDynInst(cpu_ptr, NULL, 0, 0); + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); + + tracer = dynamic_cast<Trace::InOrderTrace *>(cpu->getTracer()); +} + + +void +PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(InOrderStage, "Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to write information back to fetch. + toPrevStages = timeBuffer->getWire(0); + + // Create wires to get information from proper places in time buffer. + fromNextStages = timeBuffer->getWire(-1); +} + + +void +PipelineStage::setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr) +{ + DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n"); + prevStageQueue = prev_stage_ptr; + + // Setup wire to read information from fetch queue. + prevStage = prevStageQueue->getWire(-1); + + prevStageValid = true; +} + + + +void +PipelineStage::setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr) +{ + DPRINTF(InOrderStage, "Setting next stage pointer.\n"); + nextStageQueue = next_stage_ptr; + + // Setup wire to write information to proper place in stage queue. + nextStage = nextStageQueue->getWire(0); + nextStage->size = 0; + nextStageValid = true; +} + + + +void +PipelineStage::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(InOrderStage, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +/*inline void +PipelineStage::switchToActive() +{ + if (_status == Inactive) { + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(stageNum); + + _status = Active; + } +}*/ + +void +PipelineStage::switchOut() +{ + // Stage can immediately switch out. + panic("Switching Out of Stages Unimplemented"); +} + + +void +PipelineStage::takeOverFrom() +{ + _status = Inactive; + + // Be sure to reset state and clear out any old instructions. + for (int i = 0; i < numThreads; ++i) { + stageStatus[i] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[i].stage[stNum] = false; + } + + stalls[i].resources.clear(); + + while (!insts[i].empty()) + insts[i].pop(); + + while (!skidBuffer[i].empty()) + skidBuffer[i].pop(); + } + wroteToTimeBuffer = false; +} + + + +bool +PipelineStage::checkStall(unsigned tid) const +{ + bool ret_val = false; + + // Only check pipeline stall from stage directly following this stage + if (nextStageValid && stalls[tid].stage[stageNum + 1]) { + DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n", + tid, stageNum + 1); + ret_val = true; + } + + if (!stalls[tid].resources.empty()) { + string stall_src; + + for (int i=0; i < stalls[tid].resources.size(); i++) { + stall_src += stalls[tid].resources[i]->res->name() + ":"; + } + + DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n", + tid, stall_src); + ret_val = true; + } + + return ret_val; +} + + +void +PipelineStage::removeStalls(unsigned tid) +{ + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); +} + +inline bool +PipelineStage::prevStageInstsValid() +{ + return prevStage->size > 0; +} + +bool +PipelineStage::isBlocked(unsigned tid) +{ + return stageStatus[tid] == Blocked; +} + +bool +PipelineStage::block(unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to previous stages.\n", tid); + + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + // skidInsert(tid); + + // If the stage status is blocked or unblocking then stage has not yet + // signalled fetch to unblock. In that case, there is no need to tell + // fetch to block. + if (stageStatus[tid] != Blocked) { + // Set the status to Blocked. + stageStatus[tid] = Blocked; + + if (stageStatus[tid] != Unblocking) { + if (prevStageValid) + toPrevStages->stageBlock[stageNum][tid] = true; + wroteToTimeBuffer = true; + } + + return true; + } + + + return false; +} + +void +PipelineStage::blockDueToBuffer(unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to next stage.\n", tid); + + if (stageStatus[tid] != Blocked) { + // Set the status to Blocked. + stageStatus[tid] = Blocked; + + if (stageStatus[tid] != Unblocking) { + wroteToTimeBuffer = true; + } + } +} + +bool +PipelineStage::unblock(unsigned tid) +{ + // Stage is done unblocking only if the skid buffer is empty. + if (skidBuffer[tid].empty()) { + DPRINTF(InOrderStage, "[tid:%u]: Done unblocking.\n", tid); + + if (prevStageValid) + toPrevStages->stageUnblock[stageNum][tid] = true; + + wroteToTimeBuffer = true; + + stageStatus[tid] = Running; + + return true; + } + + DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid); + return false; +} + +void +PipelineStage::squashDueToBranch(DynInstPtr &inst, unsigned tid) +{ + if (cpu->squashSeqNum[tid] < inst->seqNum && + cpu->lastSquashCycle[tid] == curTick){ + DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another stage's squash " + "signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]); + } else { + // Send back mispredict information. + toPrevStages->stageInfo[stageNum][tid].branchMispredict = true; + toPrevStages->stageInfo[stageNum][tid].predIncorrect = true; + toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum; + toPrevStages->stageInfo[stageNum][tid].squash = true; + toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg(); + toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextNPC() != + (inst->readNextPC() + sizeof(TheISA::MachInst)); + toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->bdelaySeqNum; + + DPRINTF(InOrderStage, "Target being re-set to %08p\n", inst->readPredTarg()); + InstSeqNum squash_seq_num = inst->bdelaySeqNum; + + DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], due to [sn:%i] " + "branch.\n", tid, squash_seq_num, inst->seqNum); + + // Save squash num for later stage use + cpu->squashSeqNum[tid] = squash_seq_num; + cpu->lastSquashCycle[tid] = curTick; + } +} + +void +PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, + unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from " + "incoming stage queue.\n", tid); + + for (int i=0; i < prevStage->size; i++) { + if (prevStage->insts[i]->threadNumber == tid && + prevStage->insts[i]->seqNum > squash_seq_num) { + DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, " + "[sn:%i] PC %08p.\n", + tid, + prevStage->insts[i]->seqNum, + prevStage->insts[i]->readPC()); + prevStage->insts[i]->setSquashed(); + } + } +} + +void +PipelineStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + stageStatus[tid] = Squashing; + + squashPrevStageInsts(squash_seq_num, tid); + + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage skidbuffer.\n", + tid); + while (!skidBuffer[tid].empty()) { + if (skidBuffer[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + skidBuffer[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, skidBuffer[tid].front()->seqNum, skidBuffer[tid].front()->PC); + skidBuffer[tid].pop(); + } + +} + +int +PipelineStage::stageBufferAvail() +{ + unsigned total = 0; + + for (int i=0; i < ThePipeline::MaxThreads; i++) { + total += skidBuffer[i].size(); + } + + int incoming_insts = (prevStageValid) ? + cpu->pipelineStage[stageNum]->prevStage->size : + 0; + + int avail = stageBufferMax - total -0;// incoming_insts; + + if (avail < 0) + fatal("stageNum %i:stageBufferAvail() < 0...stBMax=%i,total=%i,incoming=%i=>%i", + stageNum, stageBufferMax, total, incoming_insts, avail); + + return avail; +} + +bool +PipelineStage::canSendInstToStage(unsigned stage_num) +{ + bool buffer_avail = false; + + if (cpu->pipelineStage[stage_num]->prevStageValid) { + buffer_avail = cpu->pipelineStage[stage_num]->stageBufferAvail() >= 1; + } + + if (!buffer_avail && nextStageQueueValid(stage_num)) { + DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1); + } + + return buffer_avail; +} + +void +PipelineStage::skidInsert(unsigned tid) +{ + DynInstPtr inst = NULL; + + while (!insts[tid].empty()) { + inst = insts[tid].front(); + + insts[tid].pop(); + + assert(tid == inst->threadNumber); + + DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n", + tid, inst->seqNum, inst->readPC(), inst->threadNumber); + + skidBuffer[tid].push(inst); + } +} + + +int +PipelineStage::skidSize() +{ + int total = 0; + + for (int i=0; i < ThePipeline::MaxThreads; i++) { + total += skidBuffer[i].size(); + } + + return total; +} + +bool +PipelineStage::skidsEmpty() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; + } + + return true; +} + + + +void +PipelineStage::updateStatus() +{ + bool any_unblocking = false; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (stageStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } + } + + // Stage will have activity if it's unblocking. + if (any_unblocking) { + if (_status == Inactive) { + _status = Active; + + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(stageNum); + } + } else { + // If it's not unblocking, then stage will not have any internal + // activity. Switch it to inactive. + if (_status == Active) { + _status = Inactive; + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(stageNum); + } + } +} + + + +void +PipelineStage::sortInsts() +{ + if (prevStageValid) { + int insts_from_prev_stage = prevStage->size; + + DPRINTF(InOrderStage, "%i insts available from stage buffer %i.\n", + insts_from_prev_stage, prevStageQueue->id()); + + for (int i = 0; i < insts_from_prev_stage; ++i) { + + if (prevStage->insts[i]->isSquashed()) { + DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], not inserting " + "into stage buffer.\n", + prevStage->insts[i]->readTid(), + prevStage->insts[i]->seqNum); + + continue; + } + + DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage buffer.\n", + prevStage->insts[i]->readTid(), + prevStage->insts[i]->seqNum); + + int tid = prevStage->insts[i]->threadNumber; + + DynInstPtr inst = prevStage->insts[i]; + + skidBuffer[tid].push(prevStage->insts[i]); + + prevStage->insts[i] = dummyBufferInst; + + } + } +} + + + +void +PipelineStage::readStallSignals(unsigned tid) +{ + for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid]; + stage_idx++) { + + // Check for Stage Blocking Signal + if (fromNextStages->stageBlock[stage_idx][tid]) { + stalls[tid].stage[stage_idx] = true; + } + + // Check for Stage Unblocking Signal + if (fromNextStages->stageUnblock[stage_idx][tid]) { + //assert(fromNextStages->stageBlock[stage_idx][tid]); + stalls[tid].stage[stage_idx] = false; + } + } +} + + + +bool +PipelineStage::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 for squash from later pipeline stages + for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) { + if (fromNextStages->stageInfo[stage_idx][tid].squash) { + DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to squash " + "from stage %u.\n", tid, stage_idx); + InstSeqNum squash_seq_num = fromNextStages-> + stageInfo[stage_idx][tid].bdelayDoneSeqNum; + squash(squash_seq_num, tid); + break; //return true; + } + } + + if (checkStall(tid)) { + return block(tid); + } + + if (stageStatus[tid] == Blocked) { + DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to unblocking.\n", + tid); + + stageStatus[tid] = Unblocking; + + unblock(tid); + + return true; + } + + if (stageStatus[tid] == Squashing) { + if (!skidBuffer[tid].empty()) { + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to unblocking.\n", + tid); + + stageStatus[tid] = Unblocking; + } else { + // Switch status to running if stage isn't being told to block or + // squash this cycle. + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to running.\n", + tid); + + stageStatus[tid] = Running; + } + + return true; + } + + // If we've reached this point, we have not gotten any signals that + // cause stage to change its status. Stage remains the same as before.*/ + return false; +} + + + +void +PipelineStage::tick() +{ + wroteToTimeBuffer = false; + + bool status_change = false; + + if (nextStageValid) + nextStage->size = 0; + + toNextStageIndex = 0; + + sortInsts(); + + processStage(status_change); + + if (status_change) { + updateStatus(); + } + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + } + + DPRINTF(InOrderStage, "\n\n"); +} + +void +PipelineStage::setResStall(ResReqPtr res_req, unsigned tid) +{ + DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name()); + stalls[tid].resources.push_back(res_req); +} + +void +PipelineStage::unsetResStall(ResReqPtr res_req, unsigned tid) +{ + // Search through stalls to find stalling request and then + // remove it + vector<ResReqPtr>::iterator req_it = stalls[tid].resources.begin(); + vector<ResReqPtr>::iterator req_end = stalls[tid].resources.end(); + + while (req_it != req_end) { + if( (*req_it)->res == res_req->res && // Same Resource + (*req_it)->inst == res_req->inst && // Same Instruction + (*req_it)->getSlot() == res_req->getSlot()) { + DPRINTF(InOrderStage, "[tid:%u]: Clearing stall by %s.\n", + tid, res_req->res->name()); + stalls[tid].resources.erase(req_it); + break; + } + + req_it++; + } + + if (stalls[tid].resources.size() == 0) { + DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource stalls.\n", + tid); + } +} + +// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be handled +// one at a time, but instead first come first serve by instruction? +// Questions are how should a pipeline stage handle thread-specific stalls & +// pipeline squashes +void +PipelineStage::processStage(bool &status_change) +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid); + status_change = checkSignalsAndUpdate(tid) || status_change; + + processThread(status_change, tid); + } + + if (nextStageValid) { + DPRINTF(InOrderStage, "%i insts now available for stage %i.\n", + nextStage->size, stageNum + 1); + } + + DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(), + stageNum); + + DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", stageBufferAvail(), + stageNum); +} + +void +PipelineStage::processThread(bool &status_change, unsigned tid) +{ + // If status is Running or idle, + // call stageInsts() + // If status is Unblocking, + // buffer any instructions coming from fetch + // continue trying to empty skid buffer + // check if stall conditions have passed + + if (stageStatus[tid] == Blocked) { + ;//++stageBlockedCycles; + } else if (stageStatus[tid] == Squashing) { + ;//++stageSquashCycles; + } + + // Stage should try to stage as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + DPRINTF(InOrderStage, "[tid:%u]: Not blocked, so attempting to run " + "stage.\n",tid); + + processInsts(tid); + } else if (stageStatus[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. + processInsts(tid); + + if (prevStageValid && prevStageInstsValid()) { + // 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; + } +} + + +void +PipelineStage::processInsts(unsigned tid) +{ + // Instructions can come either from the skid buffer or the list of + // instructions coming from fetch, depending on stage's status. + int insts_available = skidBuffer[tid].size(); + + std::queue<DynInstPtr> &insts_to_stage = skidBuffer[tid]; + + if (insts_available == 0) { + DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out" + " early.\n",tid); + // Should I change the status to idle? + //++stageIdleCycles; + return; + } + + DynInstPtr inst; + bool last_req_completed = true; + + int insts_processed = 0; + + while (insts_available > 0 && + insts_processed < stageWidth && + (!nextStageValid || canSendInstToStage(stageNum+1)) && + last_req_completed) { + assert(!insts_to_stage.empty()); + + inst = insts_to_stage.front(); + + DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] with " + "PC %#x\n", + tid, inst->seqNum, inst->readPC()); + + if (inst->isSquashed()) { + DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %#x is " + "squashed, skipping.\n", + tid, inst->seqNum, inst->readPC()); + + //++stageSquashedInsts; + + insts_to_stage.pop(); + + --insts_available; + + continue; + } + + + last_req_completed = processInstSchedule(inst); + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + if (!last_req_completed) + continue; + + // Send to Next Stage or Break Loop + if (nextStageValid && !sendInstToNextStage(inst)) { + DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage %i.\n", + tid, inst->seqNum,inst->nextStage); + break; + } + + insts_processed++; + + insts_to_stage.pop(); + + //++stageProcessedInsts; + --insts_available; + } + + // 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_stage.empty()) { + blockDueToBuffer(tid); + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +bool +PipelineStage::processInstSchedule(DynInstPtr inst) +{ + bool last_req_completed = true; + int tid; + + tid = inst->readTid(); + + if (inst->nextResStage() == stageNum) { + int res_stage_num = inst->nextResStage(); + + while (res_stage_num == stageNum) { + int res_num = inst->nextResource(); + + + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + ResReqPtr req = cpu->resPool->request(res_num, inst); + + if (req->isCompleted()) { + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s completed.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + if (req->fault == NoFault) { + inst->popSchedEntry(); + } else { + panic("%i: encountered %s fault!\n", + curTick, req->fault->name()); + } + } else { + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + last_req_completed = false; + + break; + } + + res_stage_num = inst->nextResStage(); + } + } else { + DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %#x " + " needed no resources in stage %i.\n", + tid, inst->seqNum, inst->readPC(), stageNum); + } + + return last_req_completed; +} + +bool +PipelineStage::nextStageQueueValid(int stage_num) +{ + return cpu->pipelineStage[stage_num]->nextStageValid; +} + + +bool +PipelineStage::sendInstToNextStage(DynInstPtr inst) +{ + // Update Next Stage Variable in Instruction + // NOTE: Some Resources will update this nextStage var. to + // for bypassing, so can't always assume nextStage=stageNum+1 + if (inst->nextStage == stageNum) + inst->nextStage++; + + bool success = false; + int tid = inst->readTid(); + int next_stage = inst->nextStage; + int prev_stage = next_stage - 1; + + assert(next_stage >= 1); + assert(prev_stage >= 0); + + DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to stage %u.\n", tid, + stageNum+1); + + if (!canSendInstToStage(inst->nextStage)) { + DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to stage %u.\n", tid, + stageNum+1); + return false; + } + + + if (nextStageQueueValid(inst->nextStage - 1)) { + if (inst->seqNum > cpu->squashSeqNum[tid] && + curTick == cpu->lastSquashCycle[tid]) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion " + "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage); + } else { + if (nextStageValid) { + DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n", + tid, cpu->pipelineStage[next_stage]->stageBufferAvail()); + } + + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " + "index %i of stage buffer %i queue.\n", + tid, inst->seqNum, toNextStageIndex, + cpu->pipelineStage[prev_stage]->nextStageQueue->id()); + + int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size; + + // Place instructions in inter-stage communication struct for the next + // pipeline stage to read next cycle + cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] = inst; + + ++(cpu->pipelineStage[prev_stage]->nextStage->size); + + ++toNextStageIndex; + + success = true; + + // Take note of trace data for this inst & stage + if (inst->traceData) { + inst->traceData->setStageCycle(stageNum, curTick); + } + + } + } + + return success; +} + +void +PipelineStage::dumpInsts() +{ + cprintf("Insts in Stage %i skidbuffers\n",stageNum); + + for (int tid=0; tid < ThePipeline::MaxThreads; tid++) { + + std::queue<DynInstPtr> copy_buff(skidBuffer[tid]); + + while (!copy_buff.empty()) { + DynInstPtr inst = copy_buff.front(); + + cprintf("Inst. PC:%#x\n[tid:%i]\n[sn:%i]\n\n", + inst->readPC(), inst->threadNumber, inst->seqNum); + + copy_buff.pop(); + } + } + +} diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh new file mode 100644 index 000000000..b074639fb --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.hh @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_STAGE_HH__ +#define __CPU_INORDER_PIPELINE_STAGE_HH__ + +#include <queue> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class PipelineStage +{ + protected: + typedef ThePipeline::Params Params; + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + /** Overall stage status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum StageStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + StartSquash, + Squashing, + Blocked, + Unblocking, + MemWaitResponse, + MemWaitRetry, + MemAccessComplete + }; + + protected: + /** The Number of This Pipeline Stage */ + unsigned stageNum; + + /** The width of stage, in instructions. */ + unsigned stageWidth; + + /** Number of Threads*/ + unsigned numThreads; + + /** Stage status. */ + StageStatus _status; + + /** Per-thread status. */ + ThreadStatus stageStatus[ThePipeline::MaxThreads]; + + public: + PipelineStage(Params *params, unsigned stage_num); + + /** MUST use init() function if this constructor is used. */ + PipelineStage() { } + + virtual ~PipelineStage() { } + + /** PipelineStage initialization. */ + void init(Params *params); + + /** Returns the name of stage. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + virtual void setCPU(InOrderCPU *cpu_ptr); + + virtual void scheduleStageStart(int delay, int tid) { } + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Sets pointer to time buffer coming from fetch. */ + void setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + bool nextStageQueueValid(int stage_num); + + bool isBlocked(unsigned tid); + + /** 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(); + + /** Switches out the stage stage. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Ticks stage, processing all input signals and executing as many + * instructions as possible. + */ + virtual void tick(); + + /** Set a resource stall in the pipeline-stage */ + void setResStall(ResReqPtr res_req, unsigned tid); + + /** Unset a resource stall in the pipeline-stage */ + void unsetResStall(ResReqPtr res_req, unsigned tid); + + /** Remove all stall signals for a particular thread; */ + virtual void removeStalls(unsigned tid); + + /** Is there room in the stage buffer? */ + int stageBufferAvail(); + + protected: + /** Evaluate Stage Conditions and then process stage */ + virtual void processStage(bool &status_change); + + /** Determines what to do based on stage's current status. + * @param status_change stage() sets this variable if there was a status + * change (ie switching from from blocking to unblocking). + * @param tid Thread id to stage instructions from. + */ + virtual void processThread(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. + */ + virtual void processInsts(unsigned tid); + + /** Process all resources on an instruction's resource schedule */ + virtual bool processInstSchedule(DynInstPtr inst); + + /** Is there room in the next stage buffer for this instruction? */ + virtual bool canSendInstToStage(unsigned stage_num); + + /** Send an instruction to the next stage buffer */ + virtual bool sendInstToNextStage(DynInstPtr inst); + + /** Inserts a thread's instructions into the skid buffer, to be staged + * once stage unblocks. + */ + virtual void skidInsert(unsigned tid); + + /** Total size of all skid buffers */ + int skidSize(); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall stage status based on all of the threads' statuses. */ + virtual 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. */ + virtual void readStallSignals(unsigned tid); + + /** Checks all input signals and updates stage's status appropriately. */ + virtual bool checkSignalsAndUpdate(unsigned tid); + + /** Checks all stall signals, and returns if any are true. */ + virtual bool checkStall(unsigned tid) const; + + /** Returns if there any instructions from the previous stage + * on this cycle. + */ + inline bool prevStageInstsValid(); + + /** Switches stage to blocking, and signals back that stage has + * become blocked. + * @return Returns true if there is a status change. + */ + virtual bool block(unsigned tid); + + void blockDueToBuffer(unsigned tid); + + /** Switches stage to unblocking if the skid buffer is empty, and + * signals back that stage has unblocked. + * @return Returns true if there is a status change. + */ + virtual bool unblock(unsigned tid); + + + public: + /** Squashes if there is a PC-relative branch that was predicted + * incorrectly. Sends squash information back to fetch. + */ + virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid); + + /** Squash instructions from stage buffer */ + virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid); + + /** Squashes due to commit signalling a squash. Changes status to + * squashing and clears block/unblock signals as needed. + */ + virtual void squash(InstSeqNum squash_num, unsigned tid); + + void dumpInsts(); + + protected: + /** CPU interface. */ + InOrderCPU *cpu; + + Trace::InOrderTrace *tracer; + + /** List of active thread ids */ + std::list<unsigned> *activeThreads; + + /** Queue of all instructions coming from previous stage on this cycle. */ + std::queue<DynInstPtr> insts[ThePipeline::MaxThreads]; + + /** Queue of instructions that are finished processing and ready to go next stage. + * This is used to prevent from processing an instrution more than once on any + * stage. NOTE: It is up to the PROGRAMMER must manage this as a queue + */ + std::list<DynInstPtr> instsToNextStage; + + /** Skid buffer between previous stage and this one. */ + std::queue<DynInstPtr> skidBuffer[ThePipeline::MaxThreads]; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */ + Addr bdelayDoneSeqNum[ThePipeline::MaxThreads]; + + /** Instruction used for squashing branch (used for MIPS) */ + DynInstPtr squashInst[ThePipeline::MaxThreads]; + + /** Tells when their is a pending delay slot inst. to send + * to rename. If there is, then wait squash after the next + * instruction (used for MIPS). + */ + bool squashAfterDelaySlot[ThePipeline::MaxThreads]; + + /** Maximum size of the inter-stage buffer connecting the previous stage to + * this stage (which we call a skid buffer) */ + unsigned stageBufferMax; + + /** Variable that tracks if stage has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Index of instructions being sent to the next stage. */ + unsigned toNextStageIndex; + + /** The last stage that this particular stage should look for stalls */ + int lastStallingStage[ThePipeline::MaxThreads]; + + /** Time buffer interface. */ + TimeBuffer<TimeStruct> *timeBuffer; + + public: + /** Wire to get rename's output from backwards time buffer. */ + TimeBuffer<TimeStruct>::wire fromNextStages; + + /** Wire to get iew's information from backwards time buffer. */ + TimeBuffer<TimeStruct>::wire toPrevStages; + + /** Instruction queue linking previous stage */ + TimeBuffer<InterStageStruct> *prevStageQueue; + + /** Wire to get the previous stage's. */ + TimeBuffer<InterStageStruct>::wire prevStage; + + /** Instruction queue linking next stage */ + TimeBuffer<InterStageStruct> *nextStageQueue; + + /** Wire to write to the next stage */ + TimeBuffer<InterStageStruct>::wire nextStage; + + /** Is Previous Stage Valid? */ + bool prevStageValid; + + /** Is Next Stage Valid? */ + bool nextStageValid; + + /** Source of possible stalls. */ + struct Stalls { + bool stage[ThePipeline::NumStages]; + std::vector<ResReqPtr> resources; + }; + + /** Tracks which stages are telling decode to stall. */ + Stalls stalls[ThePipeline::MaxThreads]; + + //@TODO: Use Stats for the pipeline stages + /** Stat for total number of idle cycles. */ + //Stats::Scalar stageIdleCycles; + /** Stat for total number of blocked cycles. */ + //Stats::Scalar stageBlockedCycles; + /** Stat for total number of normal running cycles. */ + //Stats::Scalar stageRunCycles; + /** Stat for total number of unblocking cycles. */ + //Stats::Scalar stageUnblockCycles; + /** Stat for total number of squashing cycles. */ + //Stats::Scalar stageSquashCycles; + /** Stat for total number of staged instructions. */ + //Stats::Scalar stageProcessedInsts; + /** Stat for total number of squashed instructions. */ + //Stats::Scalar stageSquashedInsts; +}; + +#endif diff --git a/src/cpu/inorder/pipeline_traits.5stage.cc b/src/cpu/inorder/pipeline_traits.5stage.cc new file mode 100644 index 000000000..50c30af1e --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.5stage.cc @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // IF - Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::AssignNextPC)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, ITLB, TLBUnit::FetchLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::InitiateFetch)); + + // + // DE - Stage 1 + // --------------------------------------- + stNum++; stPri = 0; + inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::CompleteFetch)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, Decode, DecodeUnit::DecodeInst)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, BPred, BranchPredictor::PredictBranch)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // EX - Stage 2 + // --------------------------------------- + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, AGEN, AGENUnit::GenerateAddr)); + if ( inst->isLoad() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateReadData)); + } + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst)); + } + + // + // MEM - Stage 3 + // --------------------------------------- + stPri = 0; stNum++; + if ( inst->isStore() ) { // for store, need src reg at this point + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, 1)); + } + if ( inst->isLoad() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteReadData)); + } else if ( inst->isStore() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateWriteData)); + } + + // + // WB - Stage 4 + // --------------------------------------- + stPri = 0; stNum++; + if (inst->isNonSpeculative()) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst)); + } + } + + if ( inst->isStore() ) + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteWriteData)); + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::WriteDestReg, idx)); + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri++, Grad, GraduationUnit::GraduateInst)); + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.5stage.hh b/src/cpu/inorder/pipeline_traits.5stage.hh new file mode 100644 index 000000000..aea6eff37 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.5stage.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 5; + const unsigned MaxThreads = 3; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 2; + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + // Expand this as necessary for your inter stage buffer sizes + static const unsigned interStageBuffSize[] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + StageWidth, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.9stage.cc b/src/cpu/inorder/pipeline_traits.9stage.cc new file mode 100644 index 000000000..d686bb3bc --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.cc @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 1 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + stPri++; + + if (inst->readTid() == 0) + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff, InstBuffer::ScheduleOrBypass)); + else //if (inst->readTid() == 1) + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff2, InstBuffer::ScheduleOrBypass)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 2 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + std::string name = inst->staticInst->getName(); + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 3 + // --------------------------------------- + // Set When Source Registers Should be read - Stage 4 + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 4 + // --------------------------------------- + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr)); + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 5 + // --------------------------------------- + // Execution Unit + if (!inst->isNonSpeculative() && !inst->isMemRef()) { + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + } + } + stPri++; + + // DCache Initiate Access + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup)); + stPri++; + + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 6 + // --------------------------------------- + // DCache Complete Access + if (inst->isMemRef()) { + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 7 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 8 + // --------------------------------------- + // NonSpeculative Execution + if (inst->isNonSpeculative() ) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + stPri++; + } + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx)); + stPri++; + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst)); + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.9stage.hh b/src/cpu/inorder/pipeline_traits.9stage.hh new file mode 100644 index 000000000..91e537366 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.hh @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> +#include <map> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 9; + const unsigned MaxThreads = 3; + const unsigned StageWidth = 2; + const unsigned BackEndStartStage = 3; + + // Use this to over-ride default stage widths + static std::map<unsigned, unsigned> stageBufferSizes; + + //static unsigned interStageBuffSize[NumStages]; + + static const unsigned interStageBuffSize[NumStages] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + 4, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + +//void initPipelineTraits(); + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.cc b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc new file mode 100644 index 000000000..9d2ed8e61 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 1 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + stPri++; + + int fetch_buff_num = FetchBuff + inst->readTid(); + + inst_sched->push(new ScheduleEntry(stNum, stPri, fetch_buff_num, InstBuffer::ScheduleOrBypass)); + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 2 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + std::string name = inst->staticInst->getName(); + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 3 + // --------------------------------------- + // Set When Source Registers Should be read - Stage 4 + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 4 + // --------------------------------------- + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr)); + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 5 + // --------------------------------------- + // Execution Unit + if (!inst->isNonSpeculative() && !inst->isMemRef()) { + //if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + //inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + //} else { + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + //} + } + stPri++; + + // DCache Initiate Access + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup)); + stPri++; + + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 6 + // --------------------------------------- + // DCache Complete Access + if (inst->isMemRef()) { + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 7 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 8 + // --------------------------------------- + // NonSpeculative Execution + if (inst->isNonSpeculative() ) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + stPri++; + } + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx)); + stPri++; + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst)); + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.hh b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh new file mode 100644 index 000000000..22da4ea0f --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> +#include <map> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 9; + const unsigned MaxThreads = 2; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 3; + + // Use this to over-ride default stage widths + static std::map<unsigned, unsigned> stageBufferSizes; + + //static unsigned interStageBuffSize[NumStages]; + + static const unsigned interStageBuffSize[NumStages] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + MaxThreads * 4, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + MaxThreads * 4, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + MaxThreads /* Stage 8 - 9 */ + }; + + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff, + FetchBuff2 + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + +//void initPipelineTraits(); + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc new file mode 100644 index 000000000..eb899452a --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + InstStage *I = inst->addStage(); + InstStage *E = inst->addStage(); + + I->needs(FetchSeq, FetchSeqUnit::AssignNextPC); + I->needs(ITLB, TLBUnit::FetchLookup); + I->needs(ICache, CacheUnit::InitiateFetch); + + E->needs(ICache, CacheUnit::CompleteFetch); + E->needs(Decode, DecodeUnit::DecodeInst); + E->needs(BPred, BranchPredictor::PredictBranch); + E->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + InstStage *E = inst->currentStage(); + InstStage *M = inst->addStage(); + InstStage *A = inst->addStage(); + InstStage *W = inst->addStage(); + + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) { + E->needs(RegManager, UseDefUnit::ReadSrcReg, idx); + } + } + + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if ( inst->isMemRef() ) { + E->needs(AGEN, AGENUnit::GenerateAddr); + if ( inst->isLoad() ) { + E->needs(DTLB, TLBUnit::DataLookup); + E->needs(DCache, CacheUnit::InitiateReadData); + } + } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + E->needs(MDU, MultDivUnit::StartMultDiv); + + // ZERO-LATENCY Multiply: + // E->needs(MDU, MultDivUnit::MultDiv); + } else { + E->needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + M->needs(MDU, MultDivUnit::EndMultDiv); + } + + if ( inst->isLoad() ) { + M->needs(DCache, CacheUnit::CompleteReadData); + } else if ( inst->isStore() ) { + M->needs(RegManager, UseDefUnit::ReadSrcReg, 1); + M->needs(DTLB, TLBUnit::DataLookup); + M->needs(DCache, CacheUnit::InitiateWriteData); + } + + if ( inst->isStore() ) { + A->needs(DCache, CacheUnit::CompleteWriteData); + } + + if ( inst->isNonSpeculative() ) { + if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); + W->needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + for (int idx=0; idx < inst->numDestRegs(); idx++) { + W->needs(RegManager, UseDefUnit::WriteDestReg, idx); + } + + W->needs(Grad, GraduationUnit::GraduateInst); + + return true; +} + +InstStage::InstStage(DynInstPtr inst, int stage_num) +{ + stageNum = stage_num; + nextTaskPriority = 0; + instSched = &inst->resSched; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh new file mode 100644 index 000000000..3c49143bc --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.hh @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/base.hh" + +#include "params/InOrderCPU.hh" + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 5; + const unsigned MaxThreads = 8; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 2; + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + MDU, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + // Expand this as necessary for your inter stage buffer sizes + static const unsigned interStageBuffSize[] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + StageWidth, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); + + class InstStage { + private: + int nextTaskPriority; + int stageNum; + ResSchedule *instSched; + + public: + InstStage(DynInstPtr inst, int stage_num); + + void needs(int unit, int request) { + instSched->push( new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request + )); + } + + void needs(int unit, int request, int param) { + instSched->push( new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request, param + )); + } + + }; +}; + + + + +#endif diff --git a/src/cpu/inorder/reg_dep_map.cc b/src/cpu/inorder/reg_dep_map.cc new file mode 100644 index 000000000..a405b1fb9 --- /dev/null +++ b/src/cpu/inorder/reg_dep_map.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +RegDepMap::RegDepMap(int size) +{ + regMap.resize(size); +} + +string +RegDepMap::name() +{ + return cpu->name() + ".RegDepMap"; +} + +void +RegDepMap::setCPU(InOrderCPU *_cpu) +{ + cpu = _cpu; +} + +void +RegDepMap::clear() +{ + regMap.clear(); +} + +void +RegDepMap::insert(DynInstPtr inst) +{ + int dest_regs = inst->numDestRegs(); + + DPRINTF(RegDepMap, "Setting Output Dependencies for [sn:%i] " + ", %s (dest. regs = %i).\n", + inst->seqNum, + inst->staticInst->getName(), + dest_regs); + + for (int i = 0; i < dest_regs; i++) { + int idx = inst->destRegIdx(i); + + //if (inst->numFPDestRegs()) + // idx += TheISA::FP_Base_DepTag; + + insert(idx, inst); + } +} + + +void +RegDepMap::insert(unsigned idx, DynInstPtr inst) +{ + DPRINTF(RegDepMap, "Inserting [sn:%i] onto dep. list for reg. idx %i.\n", + inst->seqNum, idx); + + regMap[idx].push_back(inst); + + inst->setRegDepEntry(); +} + +void +RegDepMap::remove(DynInstPtr inst) +{ + if (inst->isRegDepEntry()) { + DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map.\n", + inst->seqNum); + + int dest_regs = inst->numDestRegs(); + + for (int i = 0; i < dest_regs; i++) { + int idx = inst->destRegIdx(i); + remove(idx, inst); + } + } +} + +void +RegDepMap::remove(unsigned idx, DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + std::list<DynInstPtr>::iterator list_end = regMap[idx].end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + regMap[idx].erase(list_it); + break; + } + + list_it++; + } +} + +void +RegDepMap::removeFront(unsigned idx, DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on phys. reg." + "%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum); + + assert(list_it != regMap[idx].end()); + + assert(inst == (*list_it)); + + regMap[idx].erase(list_it); +} + +bool +RegDepMap::canRead(unsigned idx, DynInstPtr inst) +{ + if (regMap[idx].size() == 0) + return true; + + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + if (inst->seqNum <= (*list_it)->seqNum) { + return true; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't read from RegFile, [sn:%i] has not written" + " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum); + return false; + } +} + +ThePipeline::DynInstPtr +RegDepMap::canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = regMap[reg_idx].begin(); + std::list<DynInstPtr>::iterator list_end = regMap[reg_idx].end(); + + DynInstPtr forward_inst = NULL; + + // Look for first, oldest instruction + while (list_it != list_end && + (*list_it)->seqNum < inst->seqNum) { + forward_inst = (*list_it); + list_it++; + } + + if (forward_inst) { + if (forward_inst->isExecuted() && + forward_inst->readResultTime(src_idx) < curTick) { + return forward_inst; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't get value through forwarding, " + " [sn:%i] has not been executed yet.\n", + inst->seqNum, forward_inst->seqNum); + return NULL; + } + } else { + DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n", + inst->seqNum); + return NULL; + } +} + +bool +RegDepMap::canWrite(unsigned idx, DynInstPtr inst) +{ + if (regMap[idx].size() == 0) + return true; + + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + if (inst->seqNum <= (*list_it)->seqNum) { + return true; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't write from RegFile: [sn:%i] has not written" + " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum); + } + + return false; +} + +int +RegDepMap::depSize(unsigned idx) +{ + return regMap[idx].size(); +} + +ThePipeline::DynInstPtr +RegDepMap::findBypassInst(unsigned idx) +{ + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + if (depSize(idx) == 1) + return NULL; + + list_it++; + + while (list_it != regMap[idx].end()) { + if((*list_it)->isExecuted()) { + return *list_it; + break; + } + } + + return NULL; +} diff --git a/src/cpu/inorder/reg_dep_map.hh b/src/cpu/inorder/reg_dep_map.hh new file mode 100644 index 000000000..ba2a8c8a3 --- /dev/null +++ b/src/cpu/inorder/reg_dep_map.hh @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef CPU_INORDER_REG_DEP_MAP_HH +#define CPU_INORDER_REG_DEP_MAP_HH + +#include <list> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class RegDepMap +{ + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + RegDepMap(int size = TheISA::TotalNumRegs); + + ~RegDepMap() { } + + std::string name(); + + void setCPU(InOrderCPU *_cpu); + + /** Clear the Entire Map */ + void clear(); + + /** Insert all of a instruction's destination registers into map*/ + void insert(DynInstPtr inst); + + /** Insert an instruction into a specific destination register index onto map */ + void insert(unsigned idx, DynInstPtr inst); + + /** Remove all of a instruction's destination registers into map*/ + void remove(DynInstPtr inst); + + /** Remove a specific instruction and destination register index from map */ + void remove(unsigned idx, DynInstPtr inst); + + /** Remove Front instruction from a destination register */ + void removeFront(unsigned idx, DynInstPtr inst); + + /** Is the current instruction able to read from this destination register? */ + bool canRead(unsigned idx, DynInstPtr inst); + + /** Is the current instruction able to get a forwarded value from another instruction + * for this destination register? */ + DynInstPtr canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst); + + /** find an instruction to forward/bypass a value from */ + DynInstPtr findBypassInst(unsigned idx); + + /** Is the current instruction able to write to this destination register? */ + bool canWrite(unsigned idx, DynInstPtr inst); + + /** Size of Dependency of Map */ + int depSize(unsigned idx); + + protected: + // Eventually make this a map of lists for + // efficiency sake! + std::vector<std::list<DynInstPtr> > regMap; + + InOrderCPU *cpu; +}; + +#endif + + + + + + + diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc new file mode 100644 index 000000000..3106628f0 --- /dev/null +++ b/src/cpu/inorder/resource.cc @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/cpu.hh" +using namespace std; + +Resource::Resource(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : resName(res_name), id(res_id), + width(res_width), latency(res_latency), cpu(_cpu) +{ + // Use to deny a instruction a resource. + deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0); +} + +void +Resource::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new ResourceEvent[width]; + + initSlots(); +} + +void +Resource::initSlots() +{ + // Add available slot numbers for resource + for (int slot_idx = 0; slot_idx < width; slot_idx++) { + availSlots.push_back(slot_idx); + resourceEvent[slot_idx].init(this, slot_idx); + } +} + +std::string +Resource::name() +{ + return cpu->name() + "." + resName; +} + +void +Resource::regStats() +{ + instReqsProcessed + .name(name() + ".instReqsProcessed") + .desc("Number of Instructions Requests that completed in this resource."); +} + +int +Resource::slotsAvail() +{ + return availSlots.size(); +} + +int +Resource::slotsInUse() +{ + return width - availSlots.size(); +} + +void +Resource::freeSlot(int slot_idx) +{ + DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + slot_idx); + + // Put slot number on this resource's free list + availSlots.push_back(slot_idx); + + // Erase Request Pointer From Request Map + std::map<int, ResReqPtr>::iterator req_it = reqMap.find(slot_idx); + + assert(req_it != reqMap.end()); + reqMap.erase(req_it); + +} + +// TODO: More efficiently search for instruction's slot within +// resource. +int +Resource::findSlot(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + int slot_num = -1; + + while (map_it != map_end) { + if ((*map_it).second->getInst()->seqNum == + inst->seqNum) { + slot_num = (*map_it).second->getSlot(); + } + map_it++; + } + + return slot_num; +} + +int +Resource::getSlot(DynInstPtr inst) +{ + int slot_num; + + if (slotsAvail() != 0) { + slot_num = availSlots[0]; + + vector<int>::iterator vect_it = availSlots.begin(); + + assert(slot_num == *vect_it); + + availSlots.erase(vect_it); + } else { + DPRINTF(Resource, "[tid:%i]: No slots in resource " + "available to service [sn:%i].\n", inst->readTid(), + inst->seqNum); + slot_num = -1; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second) { + DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n", + (*map_it).second->getInst()->readTid(), + (*map_it).second->getInst()->seqNum); + } + map_it++; + } + } + + return slot_num; +} + +ResReqPtr +Resource::request(DynInstPtr inst) +{ + // See if the resource is already serving this instruction. + // If so, use that request; + bool try_request = false; + int slot_num; + int stage_num; + ResReqPtr inst_req = findRequest(inst); + + if (inst_req) { + // If some preprocessing has to be done on instruction + // that has already requested once, then handle it here. + // update the 'try_request' variable if we should + // re-execute the request. + requestAgain(inst, try_request); + + slot_num = inst_req->getSlot(); + stage_num = inst_req->getStageNum(); + } else { + // Get new slot # for instruction + slot_num = getSlot(inst); + + if (slot_num != -1) { + // Get Stage # from Schedule Entry + stage_num = inst->resSched.top()->stageNum; + unsigned cmd = inst->resSched.top()->cmd; + + // Generate Resource Request + inst_req = getRequest(inst, stage_num, id, slot_num, cmd); + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n", + inst->readTid()); + } + + reqMap[slot_num] = inst_req; + + try_request = true; + } + } + + if (try_request) { + // Schedule execution of resource + scheduleExecution(slot_num); + } else { + inst_req = deniedReq; + rejectRequest(inst); + } + + return inst_req; +} + +void +Resource::requestAgain(DynInstPtr inst, bool &do_request) +{ + do_request = true; + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n", + inst->readTid()); + } +} + +ResReqPtr +Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new ResourceRequest(this, inst, stage_num, id, slot_num, + cmd); +} + +ResReqPtr +Resource::findRequest(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second && + (*map_it).second->getInst() == inst) { + return (*map_it).second; + } + map_it++; + } + + return NULL; +} + +void +Resource::rejectRequest(DynInstPtr inst) +{ + DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n", + inst->readTid(), inst->seqNum); +} + +void +Resource::execute(int slot_idx) +{ + DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n", + reqMap[slot_idx]->getTid(), name()); + reqMap[slot_idx]->setCompleted(true); + reqMap[slot_idx]->fault = NoFault; + reqMap[slot_idx]->done(); +} + +void +Resource::deactivateThread(unsigned tid) +{ + // In the most basic case, deactivation means squashing everything + // from a particular thread + DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid); + squash(dummy_inst, 0, 0, tid); +} + +void +Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + std::vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + int req_slot_num = req_ptr->getSlot(); + + unscheduleEvent(req_slot_num); + + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } +} + + +Tick +Resource::ticks(int num_cycles) +{ + return cpu->ticks(num_cycles); +} + + +void +Resource::scheduleExecution(int slot_num) +{ + int res_latency = getLatency(slot_num); + + if (res_latency >= 1) { + scheduleEvent(slot_num, res_latency); + } else { + execute(slot_num); + } +} + +void +Resource::scheduleEvent(int slot_idx, int delay) +{ + DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + cpu->ticks(delay) + curTick); + resourceEvent[slot_idx].scheduleEvent(delay); +} + +bool +Resource::scheduleEvent(DynInstPtr inst, int delay) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].scheduleEvent(delay); + + return slot_idx; +} + +void +Resource::unscheduleEvent(int slot_idx) +{ + resourceEvent[slot_idx].unscheduleEvent(); +} + +bool +Resource::unscheduleEvent(DynInstPtr inst) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].unscheduleEvent(); + + return slot_idx; +} + +int ResourceRequest::resReqID = 0; + +int ResourceRequest::resReqCount = 0; + +void +ResourceRequest::done(bool completed) +{ + DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n", + res->name(), inst->seqNum, inst->readTid()); + + setCompleted(completed); + + // Add to remove list + res->cpu->reqRemoveList.push(res->reqMap[slotNum]); + + // Free Slot So Another Instruction Can Use This Resource + res->freeSlot(slotNum); + + res->instReqsProcessed++; +} + +ResourceEvent::ResourceEvent() + : Event((Event::Priority)Resource_Event_Pri) +{ } + +ResourceEvent::ResourceEvent(Resource *res, int slot_idx) + : Event((Event::Priority)Resource_Event_Pri), resource(res), + slotIdx(slot_idx) +{ } + +void +ResourceEvent::init(Resource *res, int slot_idx) +{ + resource = res; + slotIdx = slot_idx; +} + +void +ResourceEvent::process() +{ + resource->execute(slotIdx); +} + +const char * +ResourceEvent::description() +{ + string desc = resource->name() + " event"; + + return desc.c_str(); +} diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh new file mode 100644 index 000000000..b857e59ed --- /dev/null +++ b/src/cpu/inorder/resource.hh @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_RESOURCE_HH__ +#define __CPU_INORDER_RESOURCE_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inst_seq.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Event; +class InOrderCPU; +class ResourceEvent; +class ResourceRequest; + +typedef ResourceRequest ResReq; +typedef ResourceRequest* ResReqPtr; + +class Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + friend class ResourceEvent; + friend class ResourceRequest; + + public: + Resource(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~Resource() {} + + /** Return name of this resource */ + virtual std::string name(); + + /** Define this function if resource, has a port to connect to an outside + * simulation object. + */ + virtual Port* getPort(const std::string &if_name, int idx) { return NULL; } + + /** Return ID for this resource */ + int getId() { return id; } + + /** Any extra initiliazation stuff can be set up using this function that + * should get called before the simulation starts (tick 0) + */ + virtual void init(); + virtual void initSlots(); + + /** Register Stats for this resource */ + virtual void regStats(); + + /** Resources that care about thread activation override this. */ + virtual void activateThread(unsigned tid) { } + + /** Deactivate Thread. Default action is to squash all instructions + * from deactivated thread. + */ + virtual void deactivateThread(unsigned tid); + + /** Resources that care when an instruction has been graduated + * can override this + */ + virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { } + + /** Request usage of this resource. Returns a ResourceRequest object + * with all the necessary resource information + */ + virtual ResourceRequest* request(DynInstPtr inst); + + /** Get the next available slot in this resource. Instruction is passed + * so that resources can check the instruction before allocating a slot + * if necessary. + */ + virtual int getSlot(DynInstPtr inst); + + /** Find the slot that this instruction is using in a resource */ + virtual int findSlot(DynInstPtr inst); + + /** Free a resource slot */ + virtual void freeSlot(int slot_idx); + + /** Request usage of a resource for this instruction. If this instruction already + * has made this request to this resource, and that request is uncompleted + * this function will just return that request + */ + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + /** Schedule Execution of This Resource For A Given Slot*/ + virtual void scheduleExecution(int slot_idx); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + virtual void execute(int slot_idx); + + /** Fetch on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to fetch. Needs to be defined for derived units. + */ + virtual Fault doFetchAccess(DynInstPtr inst) + { panic("doFetchAccess undefined for %s", name()); return NoFault; } + + /** Read/Write on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to do access.Needs to be defined for derived units. + */ + virtual Fault doDataAccess(DynInstPtr inst) + { panic("doDataAccess undefined for %s", name()); return NoFault; } + + /** Squash All Requests After This Seq Num */ + virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + /** The number of instructions available that this resource can + * can still process + */ + int slotsAvail(); + + /** The number of instructions using this resource */ + int slotsInUse(); + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(int slot_idx, int delay); + + /** Find instruction in list, Schedule resource event, regardless of its current state. */ + bool scheduleEvent(DynInstPtr inst, int delay); + + /** Unschedule resource event, regardless of its current state. */ + void unscheduleEvent(int slot_idx); + + /** Unschedule resource event, regardless of its current state. */ + bool unscheduleEvent(DynInstPtr inst); + + /** Return the number of cycles in 'Tick' format */ + Tick ticks(int numCycles); + + /** Find the request that corresponds to this instruction */ + virtual ResReqPtr findRequest(DynInstPtr inst); + + /** */ + virtual void rejectRequest(DynInstPtr inst); + + /** Request a Resource again. Some resources have to special process this + * in subsequent accesses. + */ + virtual void requestAgain(DynInstPtr inst, bool &try_request); + + /** Return Latency of Resource */ + /* Can be overridden for complex cases */ + virtual int getLatency(int slot_num) { return latency; } + + protected: + /** The name of this resource */ + std::string resName; + + /** ID of the resource. The Resource Pool uses this # to identify this + * resource. + */ + int id; + + /** The number of instructions the resource can simultaneously + * process. + */ + int width; + + /** Constant latency for this resource. + * Note: Dynamic latency resources set this to 0 and + * manage the latency themselves + */ + const int latency; + + public: + /** Mapping of slot-numbers to the resource-request pointers */ + std::map<int, ResReqPtr> reqMap; + + /** A list of all the available execution slots for this resource. + * This correlates with the actual resource event idx. + */ + std::vector<int> availSlots; + + /** The CPU(s) that this resource interacts with */ + InOrderCPU *cpu; + + protected: + /** The resource event used for scheduling resource slots on the + * event queue + */ + ResourceEvent *resourceEvent; + + /** Default denied resource request pointer*/ + ResReqPtr deniedReq; + + public: + ///////////////////////////////////////////////////////////////// + // + // DEFAULT RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar instReqsProcessed; +}; + +class ResourceEvent : public Event +{ + public: + /** Pointer to the CPU. */ + Resource *resource; + + + /// Resource events that come before other associated CPU events + /// (for InOrderCPU model). + /// check src/sim/eventq.hh for more event priorities. + enum InOrderPriority { + Resource_Event_Pri = 45, + }; + + /** The Resource Slot that this event is servicing */ + int slotIdx; + + /** Constructs a resource event. */ + ResourceEvent(); + ResourceEvent(Resource *res, int slot_idx); + virtual ~ResourceEvent() { } + + /** Initialize data for this resource event. */ + virtual void init(Resource *res, int slot_idx); + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Set slot idx for event */ + void setSlot(int slot) { slotIdx = slot; } + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(int delay) + { + if (squashed()) + mainEventQueue.reschedule(this, curTick + resource->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this, curTick + resource->ticks(delay)); + } + + /** Unschedule resource event, regardless of its current state. */ + void unscheduleEvent() + { + if (scheduled()) + squash(); + } + +}; + +class ResourceRequest +{ + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + static int resReqID; + + static int resReqCount; + + public: + ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, unsigned _cmd) + : res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num), + resIdx(res_idx), slotNum(slot_num), completed(false), + squashed(false), processing(false), waiting(false) + { + reqID = resReqID++; + resReqCount++; + DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount); + + if (resReqCount > 100) { + fatal("Too many undeleted resource requests. Memory leak?\n"); + } + } + + virtual ~ResourceRequest() + { + resReqCount--; + DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount); + } + + int reqID; + + /** Acknowledge that this is a request is done and remove + * from resource. + */ + void done(bool completed = true); + + ///////////////////////////////////////////// + // + // GET RESOURCE REQUEST IDENTIFICATION / INFO + // + ///////////////////////////////////////////// + /** Get Resource Index */ + int getResIdx() { return resIdx; } + + /** Get Slot Number */ + int getSlot() { return slotNum; } + + /** Get Stage Number */ + int getStageNum() { return stageNum; } + + /** Set/Get Thread Ids */ + void setTid(unsigned _tid) { tid = _tid; } + int getTid() { return tid; } + + /** Instruction this request is for */ + DynInstPtr getInst() { return inst; } + + /** Data from this request. Overridden by Resource-Specific Request + * Objects + */ + virtual PacketDataPtr getData() { return NULL; } + + /** Pointer to Resource that is being used */ + Resource *res; + + /** Instruction being used */ + DynInstPtr inst; + + /** Fault Associated With This Resource Request */ + Fault fault; + + /** Command For This Resource */ + unsigned cmd; + + //////////////////////////////////////// + // + // GET RESOURCE REQUEST STATUS FROM VARIABLES + // + //////////////////////////////////////// + /** Get/Set Completed variables */ + bool isCompleted() { return completed; } + void setCompleted(bool cond = true) { completed = cond; } + + /** Get/Set Squashed variables */ + bool isSquashed() { return squashed; } + void setSquashed() { squashed = true; } + + /** Get/Set IsProcessing variables */ + bool isProcessing() { return processing; } + void setProcessing() { processing = true; } + + /** Get/Set IsWaiting variables */ + bool isWaiting() { return waiting; } + void setWaiting() { waiting = true; } + + protected: + /** Resource Identification */ + int tid; + int stageNum; + int resIdx; + int slotNum; + + /** Resource Status */ + bool completed; + bool squashed; + bool processing; + bool waiting; +}; + +#endif //__CPU_INORDER_RESOURCE_HH__ diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc new file mode 100644 index 000000000..4a0258e71 --- /dev/null +++ b/src/cpu/inorder/resource_pool.9stage.cc @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/resources/resource_list.hh" + +#include <vector> +#include <list> + +using namespace std; +using namespace ThePipeline; + +ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params) + : cpu(_cpu) +{ + //@todo: use this function to instantiate the resources in resource pool. This will help in the + //auto-generation of this pipeline model. + //ThePipeline::addResources(resources, memObjects); + + // Declare Resource Objects + // name - id - bandwidth - latency - CPU - Parameters + // -------------------------------------------------- + resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); + + resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(ICache); + resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); + + resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); + + for (int i = 0; i < params->numberOfThreads; i++) { + char fbuff_name[20]; + sprintf(fbuff_name, "Fetch-Buffer-T%i", i); + resources.push_back(new InstBuffer(fbuff_name, FetchBuff + i, 4, 0, _cpu, params)); + } + + resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); + + resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); + + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); + + resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(DCache); + resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); +} + +void +ResourcePool::init() +{ + for (int i=0; i < resources.size(); i++) { + resources[i]->init(); + } +} + +string +ResourcePool::name() +{ + return cpu->name() + ".ResourcePool"; +} + + +void +ResourcePool::regStats() +{ + DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->regStats(); + } +} + +Port * +ResourcePool::getPort(const std::string &if_name, int idx) +{ + for (int i = 0; i < memObjects.size(); i++) { + int obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(if_name, idx); + if (port != NULL) { + return port; + } + } + + return NULL; +} + +unsigned +ResourcePool::getPortIdx(const std::string &port_name) +{ + for (int i = 0; i < memObjects.size(); i++) { + unsigned obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(port_name, obj_idx); + if (port != NULL) { + return obj_idx; + } + } + + return 0; +} + +ResReqPtr +ResourcePool::request(int res_idx, DynInstPtr inst) +{ + //Make Sure This is a valid resource ID + assert(res_idx >= 0 && res_idx < resources.size()); + + return resources[res_idx]->request(inst); +} + +void +ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) +{ + resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); +} + +int +ResourcePool::slotsAvail(int res_idx) +{ + return resources[res_idx]->slotsAvail(); +} + +int +ResourcePool::slotsInUse(int res_idx) +{ + return resources[res_idx]->slotsInUse(); +} + +void +ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, + int delay, int res_idx, int tid) +{ + assert(delay >= 0); + + ResPoolEvent *res_pool_event = new ResPoolEvent(this); + + switch (e_type) + { + case InOrderCPU::ActivateThread: + { + DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + { + DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + tid); + + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case ResourcePool::InstGraduated: + { + DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case ResourcePool::SquashAll: + { + DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + default: + DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); + ; // If Resource Pool doesnt recognize event, we ignore it. + } +} + +void +ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) +{ + resources[res_idx]->unscheduleEvent(inst); +} + +void +ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", + stage_num, tid, done_seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->squash(inst, stage_num, done_seq_num, tid); + } +} + +void +ResourcePool::activateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->activateThread(tid); + } +} + +void +ResourcePool::deactivateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->deactivateThread(tid); + } +} + +void +ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", + tid, seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->instGraduated(seq_num, tid); + } +} + +ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) + : Event(&mainEventQueue, CPU_Tick_Pri), + resPool(_resPool) +{ eventType = (InOrderCPU::CPUEventType) Default; } + +void +ResourcePool::ResPoolEvent::process() +{ + switch (eventType) + { + case InOrderCPU::ActivateThread: + resPool->activateAll(tid); + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + resPool->deactivateAll(tid); + break; + + case ResourcePool::InstGraduated: + resPool->instGraduated(seqNum, tid); + break; + + case ResourcePool::SquashAll: + resPool->squashAll(inst, stageNum, seqNum, tid); + break; + + default: + fatal("Unrecognized Event Type"); + } + + resPool->cpu->cpuEventRemoveList.push(this); +} + + +const char * +ResourcePool::ResPoolEvent::description() +{ + return "Resource Pool event"; +} + +/** Schedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::scheduleEvent(int delay) +{ + if (squashed()) + reschedule(curTick + resPool->cpu->cycles(delay)); + else if (!scheduled()) + schedule(curTick + resPool->cpu->cycles(delay)); +} + +/** Unschedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc new file mode 100644 index 000000000..94af68c7a --- /dev/null +++ b/src/cpu/inorder/resource_pool.cc @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/resources/resource_list.hh" + +#include <vector> +#include <list> + +using namespace std; +using namespace ThePipeline; + +ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) + : cpu(_cpu) +{ + //@todo: use this function to instantiate the resources in resource pool. This will help in the + //auto-generation of this pipeline model. + //ThePipeline::addResources(resources, memObjects); + + // Declare Resource Objects + // name - id - bandwidth - latency - CPU - Parameters + // -------------------------------------------------- + resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); + + resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(ICache); + resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); + + resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); + + resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params)); + + resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); + + resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); + + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); + + resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(DCache); + resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params)); +} + +void +ResourcePool::init() +{ + for (int i=0; i < resources.size(); i++) { + DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name()); + + resources[i]->init(); + } +} + +string +ResourcePool::name() +{ + return cpu->name() + ".ResourcePool"; +} + + +void +ResourcePool::regStats() +{ + DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->regStats(); + } +} + +Port * +ResourcePool::getPort(const std::string &if_name, int idx) +{ + DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name); + + for (int i = 0; i < memObjects.size(); i++) { + int obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(if_name, idx); + if (port != NULL) { + DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name, + resources[obj_idx]->name(), obj_idx); + return port; + } + } + + return NULL; +} + +unsigned +ResourcePool::getPortIdx(const std::string &port_name) +{ + DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name); + + for (int i = 0; i < memObjects.size(); i++) { + unsigned obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(port_name, obj_idx); + if (port != NULL) { + DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name); + return obj_idx; + } + } + + return 0; +} + +ResReqPtr +ResourcePool::request(int res_idx, DynInstPtr inst) +{ + //Make Sure This is a valid resource ID + assert(res_idx >= 0 && res_idx < resources.size()); + + return resources[res_idx]->request(inst); +} + +void +ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) +{ + resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); +} + +int +ResourcePool::slotsAvail(int res_idx) +{ + return resources[res_idx]->slotsAvail(); +} + +int +ResourcePool::slotsInUse(int res_idx) +{ + return resources[res_idx]->slotsInUse(); +} + +void +ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, + int delay, int res_idx, int tid) +{ + assert(delay >= 0); + + ResPoolEvent *res_pool_event = new ResPoolEvent(this); + + switch (e_type) + { + case InOrderCPU::ActivateThread: + { + DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + { + DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + tid); + + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case ResourcePool::InstGraduated: + { + DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case ResourcePool::SquashAll: + { + DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + default: + DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); + ; // If Resource Pool doesnt recognize event, we ignore it. + } +} + +void +ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) +{ + resources[res_idx]->unscheduleEvent(inst); +} + +void +ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", + stage_num, tid, done_seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->squash(inst, stage_num, done_seq_num, tid); + } +} + +void +ResourcePool::activateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->activateThread(tid); + } +} + +void +ResourcePool::deactivateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->deactivateThread(tid); + } +} + +void +ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", + tid, seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->instGraduated(seq_num, tid); + } +} + +ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) + : Event(CPU_Tick_Pri), + resPool(_resPool) +{ eventType = (InOrderCPU::CPUEventType) Default; } + +void +ResourcePool::ResPoolEvent::process() +{ + switch (eventType) + { + case InOrderCPU::ActivateThread: + resPool->activateAll(tid); + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + resPool->deactivateAll(tid); + break; + + case ResourcePool::InstGraduated: + resPool->instGraduated(seqNum, tid); + break; + + case ResourcePool::SquashAll: + resPool->squashAll(inst, stageNum, seqNum, tid); + break; + + default: + fatal("Unrecognized Event Type"); + } + + resPool->cpu->cpuEventRemoveList.push(this); +} + + +const char * +ResourcePool::ResPoolEvent::description() +{ + return "Resource Pool event"; +} + +/** Schedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::scheduleEvent(int delay) +{ + if (squashed()) + mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay)); +} + +/** Unschedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh new file mode 100644 index 000000000..35fce7db7 --- /dev/null +++ b/src/cpu/inorder/resource_pool.hh @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_RESOURCE_POOL_HH__ +#define __CPU_INORDER_RESOURCE_POOL_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inst_seq.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/params.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/cpu.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Event; +class InOrderCPU; +class Resource; +class ResourceEvent; + +class ResourcePool { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + // List of Resource Pool Events that extends + // the list started by the CPU + // NOTE(1): Resource Pool also uses event list + // CPUEventType defined in inorder/cpu.hh + enum ResPoolEventType { + InstGraduated = InOrderCPU::NumCPUEvents, + SquashAll, + Default + }; + + class ResPoolEvent : public Event + { + protected: + /** Resource Pool */ + ResourcePool *resPool; + + public: + InOrderCPU::CPUEventType eventType; + + DynInstPtr inst; + + InstSeqNum seqNum; + + int stageNum; + + unsigned tid; + + public: + /** Constructs a resource event. */ + ResPoolEvent(ResourcePool *_resPool); + + /** Set Type of Event To Be Scheduled */ + void setEvent(InOrderCPU::CPUEventType e_type, + DynInstPtr _inst, + int stage_num, + InstSeqNum seq_num, + unsigned _tid) + { + eventType = e_type; + inst = _inst; + seqNum = seq_num; + stageNum = stage_num; + tid = _tid; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + public: + ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~ResourcePool() {} + + std::string name(); + + std::string name(int res_idx) { return resources[res_idx]->name(); } + + void init(); + + /** Register Statistics in All Resources */ + void regStats(); + + /** Returns a specific port. */ + Port* getPort(const std::string &if_name, int idx); + + /** Returns a specific port. */ + unsigned getPortIdx(const std::string &if_name); + + Resource* getResource(int res_idx) { return resources[res_idx]; } + + /** Request usage of this resource. Returns -1 if not granted and + * a positive request tag if granted. + */ + ResReqPtr request(int res_idx, DynInstPtr inst); + + /** Squash The Resource */ + void squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid); + + /** Squash All Resources in Pool after Done Seq. Num */ + void squashAll(DynInstPtr inst, int stage_num, + InstSeqNum done_seq_num, unsigned tid); + + /** Activate Thread in all resources */ + void activateAll(unsigned tid); + + /** De-Activate Thread in all resources */ + void deactivateAll(unsigned tid); + + /** Broadcast graduation to all resources */ + void instGraduated(InstSeqNum seq_num,unsigned tid); + + /** The number of instructions available that a resource can + * can still process. + */ + int slotsAvail(int res_idx); + + /** The number of instructions using a resource */ + int slotsInUse(int res_idx); + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst = NULL, + int delay = 0, int res_idx = 0, int tid = 0); + + /** UnSchedule resource event, regardless of its current state. */ + void unscheduleEvent(int res_idx, DynInstPtr inst); + + /** Tasks to perform when simulation starts */ + virtual void startup() { } + + /** The CPU(s) that this resource interacts with */ + InOrderCPU *cpu; + + DynInstPtr dummyInst[ThePipeline::MaxThreads]; + + private: + std::vector<Resource *> resources; + + std::vector<int> memObjects; + +}; + +#endif //__CPU_INORDER_RESOURCE_HH__ diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc new file mode 100644 index 000000000..f462b12ea --- /dev/null +++ b/src/cpu/inorder/resources/agen_unit.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/agen_unit.hh" + +AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +AGENUnit::execute(int slot_num) +{ + ResourceRequest* agen_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid; + int seq_num = inst->seqNum; + + tid = inst->readTid(); + agen_req->fault = NoFault; + + switch (agen_req->cmd) + { + case GenerateAddr: + { + // Load/Store Instruction + if (inst->isMemRef()) { + DPRINTF(InOrderAGEN, "[tid:%i] Generating Address for [sn:%i] (%s).\n", + tid, inst->seqNum, inst->staticInst->getName()); + + + // We are not handdling Prefetches quite yet + if (inst->isDataPrefetch() || inst->isInstPrefetch()) { + panic("Prefetches arent handled yet.\n"); + } else { + if (inst->isLoad()) { + fault = inst->calcEA(); + inst->setMemAddr(inst->getEA()); + //inst->setExecuted(); + + DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: " + "%#x.\n", tid, inst->seqNum, inst->getEA()); + } else if (inst->isStore()) { + fault = inst->calcEA(); + inst->setMemAddr(inst->getEA()); + + DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: " + "%#x.\n", tid, inst->seqNum, inst->getEA()); + } else { + panic("Unexpected memory type!\n"); + } + + if (fault == NoFault) { + agen_req->done(); + } else { + fatal("%s encountered @ [sn:%i]",fault->name(), seq_num); + } + } + } else { + DPRINTF(InOrderAGEN, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num); + agen_req->done(); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} diff --git a/src/cpu/o3/mips/params.hh b/src/cpu/inorder/resources/agen_unit.hh index 2688d3fb3..2010c9fa6 100644 --- a/src/cpu/o3/mips/params.hh +++ b/src/cpu/inorder/resources/agen_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,40 +25,40 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim - * Korey Sewell + * Authors: Korey Sewell + * */ -#ifndef __CPU_O3_MIPS_PARAMS_HH__ -#define __CPU_O3_MIPS_PARAMS_HH__ +#ifndef __CPU_INORDER_AGEN_UNIT_HH__ +#define __CPU_INORDER_AGEN_UNIT_HH__ -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" +#include <vector> +#include <list> +#include <string> -//Forward declarations -namespace MipsISA -{ - class MipsDTB; - class MipsITB; -} -class MemObject; -class Process; -class System; +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/params.hh" -/** - * This file defines the parameters that will be used for the MipsO3CPU. - * 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 AGENUnit : public Resource { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; -class MipsSimpleParams : public O3Params -{ public: - MipsSimpleParams() {} + AGENUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~AGENUnit() {} + + enum Command { + GenerateAddr + }; + + virtual void execute(int slot_num); - //Full System Paramater Objects place here - MipsISA::ITB *itb; - MipsISA::DTB *dtb; + protected: + /** @todo: Add Resource Stats Here */ }; -#endif // __CPU_O3_MIPS_PARAMS_HH__ +#endif //__CPU_INORDER_DECODE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/bpred_unit.cc b/src/cpu/inorder/resources/bpred_unit.cc new file mode 100644 index 000000000..66d0779a2 --- /dev/null +++ b/src/cpu/inorder/resources/bpred_unit.cc @@ -0,0 +1,426 @@ +/* + * 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. + * + * Authors: Kevin Lim + */ + +#include <list> +#include <vector> + +#include "base/trace.hh" +#include "base/traceflags.hh" +#include "cpu/inorder/resources/bpred_unit.hh" + +using namespace std; +using namespace ThePipeline; + +BPredUnit::BPredUnit(ThePipeline::Params *params) + : BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) +{ + // Setup the selected predictor. + if (params->predType == "local") { + localBP = new LocalBP(params->localPredictorSize, + params->localCtrBits, + params->instShiftAmt); + predictor = Local; + } else if (params->predType == "tournament") { + tournamentBP = new TournamentBP(params->localPredictorSize, + params->localCtrBits, + params->localHistoryTableSize, + params->localHistoryBits, + params->globalPredictorSize, + params->globalHistoryBits, + params->globalCtrBits, + params->choicePredictorSize, + params->choiceCtrBits, + params->instShiftAmt); + predictor = Tournament; + } else { + fatal("Invalid BP selected!"); + } + + for (int i=0; i < ThePipeline::MaxThreads; i++) + RAS[i].init(params->RASSize); +} + + +void +BPredUnit::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.") + ; +} + + +void +BPredUnit::switchOut() +{ + // Clear any state upon switch out. + for (int i = 0; i < ThePipeline::MaxThreads; ++i) { + squash(0, i); + } +} + + +void +BPredUnit::takeOverFrom() +{ + // Can reset all predictor state, but it's not necessarily better + // than leaving it be. +/* + for (int i = 0; i < ThePipeline::MaxThreads; ++i) + RAS[i].reset(); + + BP.reset(); + BTB.reset(); +*/ +} + + +bool +BPredUnit::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. + // 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; + + void *bp_history = NULL; + + if (inst->isUncondCtrl()) { + DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid); + pred_taken = true; + // Tell the BP there was an unconditional branch. + BPUncond(bp_history); + + if (inst->isReturn() && RAS[tid].empty()) { + DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting " + "false.\n", tid); + pred_taken = false; + } + } else { + ++condPredicted; + + pred_taken = BPLookup(PC, bp_history); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i " + "for PC %#x\n", + tid, pred_taken, inst->readPC()); + } + + PredictorHistory predict_record(inst->seqNum, PC, pred_taken, + bp_history, 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(Resource, "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(Resource, "BranchPred: [tid:%i] Instruction %#x was a call" + ", adding %#x to the RAS.\n", + tid, inst->readPC(), PC + sizeof(MachInst)); + } + + if (inst->isCall() && + inst->isUncondCtrl() && + inst->isDirectCtrl()) { + target = inst->branchTarget(); + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted" + " target to %#x.\n", + tid, inst->readPC(), target); + } else if (BTB.valid(PC, tid)) { + ++BTBHits; + + // If it's not a return, use the BTB to get the target addr. + target = BTB.lookup(PC, tid); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted" + " target is %#x.\n", + tid, inst->readPC(), target); + } else { + DPRINTF(Resource, "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(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size()); + + inst->setBranchPred(pred_taken); + + return pred_taken; +} + + +void +BPredUnit::update(const InstSeqNum &done_sn, unsigned tid) +{ + DPRINTF(Resource, "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. + BPUpdate(predHist[tid].back().PC, + predHist[tid].back().predTaken, + predHist[tid].back().bpHistory); + + predHist[tid].pop_back(); + } +} + + +void +BPredUnit::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(Resource, "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(Resource, "BranchPred: [tid:%i]: Removing speculative entry " + "added to the RAS.\n",tid); + + RAS[tid].pop(); + } + + // This call should delete the bpHistory. + BPSquash(pred_hist.front().bpHistory); + + pred_hist.pop_front(); + } + +} + + +void +BPredUnit::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(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, " + "setting target to %#x.\n", + tid, squashed_sn, corr_target); + + squash(squashed_sn, tid); + + // 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()) { + assert(pred_hist.front().seqNum == squashed_sn); + if (pred_hist.front().usedRAS) { + ++RASIncorrect; + } + + BPUpdate(pred_hist.front().PC, actually_taken, + pred_hist.front().bpHistory); + + BTB.update(pred_hist.front().PC, corr_target, tid); + pred_hist.pop_front(); + } +} + + +void +BPredUnit::BPUncond(void * &bp_history) +{ + // Only the tournament predictor cares about unconditional branches. + if (predictor == Tournament) { + tournamentBP->uncondBr(bp_history); + } +} + + +void +BPredUnit::BPSquash(void *bp_history) +{ + if (predictor == Local) { + localBP->squash(bp_history); + } else if (predictor == Tournament) { + tournamentBP->squash(bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +bool +BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history) +{ + if (predictor == Local) { + return localBP->lookup(inst_PC, bp_history); + } else if (predictor == Tournament) { + return tournamentBP->lookup(inst_PC, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +void +BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history) +{ + if (predictor == Local) { + localBP->update(inst_PC, taken, bp_history); + } else if (predictor == Tournament) { + tournamentBP->update(inst_PC, taken, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +void +BPredUnit::dump() +{ + /*typename History::iterator pred_hist_it; + + for (int i = 0; i < ThePipeline::MaxThreads; ++i) { + if (!predHist[i].empty()) { + pred_hist_it = predHist[i].begin(); + + cprintf("predHist[%i].size(): %i\n", i, predHist[i].size()); + + while (pred_hist_it != predHist[i].end()) { + cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, " + "bpHistory:%#x\n", + (*pred_hist_it).seqNum, (*pred_hist_it).PC, + (*pred_hist_it).tid, (*pred_hist_it).predTaken, + (*pred_hist_it).bpHistory); + pred_hist_it++; + } + + cprintf("\n"); + } + }*/ +} diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh new file mode 100644 index 000000000..bd68459d1 --- /dev/null +++ b/src/cpu/inorder/resources/bpred_unit.hh @@ -0,0 +1,258 @@ +/* + * 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. + * + * Authors: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_INORDER_BPRED_UNIT_HH__ +#define __CPU_INORDER_BPRED_UNIT_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "cpu/inst_seq.hh" + +//#include "cpu/inorder/params.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 "params/InOrderCPU.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" + +#include <list> + +/** + * Basically a wrapper class to hold both the branch predictor + * and the BTB. + */ +class BPredUnit +{ + private: + + enum PredType { + Local, + Tournament + }; + + PredType predictor; + + public: + + /** + * @param params The params object, that has the size of the BP and BTB. + */ + BPredUnit(ThePipeline::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(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid); + + // @todo: Rename this function. + void BPUncond(void * &bp_history); + + /** + * 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); + + /** + * @param bp_history Pointer to the history object. The predictor + * will need to update any state and delete the object. + */ + void BPSquash(void *bp_history); + + /** + * 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. + * @param bp_history Pointer that will be set to an object that + * has the branch predictor state associated with the lookup. + * @return Whether the branch is taken or not taken. + */ + bool BPLookup(Addr &inst_PC, void * &bp_history); + + /** + * 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. + * @param bp_history Pointer to the branch predictor state that is + * associated with the branch lookup that is being updated. + * @todo Make this update flexible enough to handle a global predictor. + */ + void BPUpdate(Addr &inst_PC, bool taken, void *bp_history); + + /** + * 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); } + + void dump(); + + private: + struct PredictorHistory { + /** + * Makes a predictor history struct that contains any + * information needed to update the predictor, BTB, and RAS. + */ + PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC, + const bool pred_taken, void *bp_history, + const unsigned _tid) + : seqNum(seq_num), PC(inst_PC), RASTarget(0), + RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), + wasCall(0), bpHistory(bp_history) + { } + + /** 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 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; + + /** Pointer to the history object passed back from the branch + * predictor. It is used to update or restore state of the + * branch predictor. + */ + void *bpHistory; + }; + + 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[ThePipeline::MaxThreads]; + + /** The local branch predictor. */ + LocalBP *localBP; + + /** The tournament branch predictor. */ + TournamentBP *tournamentBP; + + /** The BTB. */ + DefaultBTB BTB; + + /** The per-thread return address stack. */ + ReturnAddrStack RAS[ThePipeline::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_INORDER_BPRED_UNIT_HH__ diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc new file mode 100644 index 000000000..511a0ac82 --- /dev/null +++ b/src/cpu/inorder/resources/branch_predictor.cc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/branch_predictor.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + branchPred(params) +{ + instSize = sizeof(MachInst); +} + +void +BranchPredictor::regStats() +{ + predictedTaken + .name(name() + ".predictedTaken") + .desc("Number of Branches Predicted As Taken (True)."); + + predictedNotTaken + .name(name() + ".predictedNotTaken") + .desc("Number of Branches Predicted As Not Taken (False)."); + + Resource::regStats(); +} + +void +BranchPredictor::execute(int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + ResourceRequest* bpred_req = reqMap[slot_num]; + + DynInstPtr inst = bpred_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + //int stage_num = bpred_req->getStageNum(); + + bpred_req->fault = NoFault; + + switch (bpred_req->cmd) + { + case PredictBranch: + { + Addr pred_PC = inst->readNextPC(); + + if (inst->isControl()) { + // If predicted, the pred_PC will be updated to new target value + // If not, the pred_PC be updated to pc+8 + bool predict_taken = branchPred.predict(inst, pred_PC, tid); + + if (predict_taken) { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n", + tid, seq_num); + + inst->setPredTarg(pred_PC); + + predictedTaken++; + } else { + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted false.\n", + tid, seq_num); + + if (inst->isCondDelaySlot()) + { + inst->setPredTarg(inst->readPC() + (2 * instSize)); + } else { + inst->setPredTarg(pred_PC); + } + + predictedNotTaken++; + } + + inst->setBranchPred(predict_taken); + + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n", + tid, seq_num, pred_PC); + + } else { + DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't " + "a control instruction.\n", tid, seq_num); + } + + bpred_req->done(); + } + break; + + case UpdatePredictor: + { + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n", + tid, seq_num); + + + branchPred.update(seq_num, tid); + + bpred_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +void +BranchPredictor::squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderBPred, "Squashing...\n"); + branchPred.squash(squash_seq_num, tid); +} + +void +BranchPredictor::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + branchPred.update(seq_num, tid); +} diff --git a/src/cpu/o3/sparc/thread_context.hh b/src/cpu/inorder/resources/branch_predictor.hh index 7497959e4..47053910d 100644 --- a/src/cpu/o3/sparc/thread_context.hh +++ b/src/cpu/inorder/resources/branch_predictor.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,54 +25,62 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black + * Authors: Korey Sewell + * */ -#include "arch/sparc/types.hh" -#include "cpu/o3/thread_context.hh" +#ifndef __CPU_INORDER_BRANCH_PREDICTOR_HH__ +#define __CPU_INORDER_BRANCH_PREDICTOR_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/bpred_unit.hh" +#include "cpu/inorder/cpu.hh" + +class BranchPredictor : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + enum Command { + PredictBranch, + UpdatePredictor + }; -template <class Impl> -class SparcTC : public O3ThreadContext<Impl> -{ public: -#if FULL_SYSTEM - /** Returns pointer to the quiesce event. */ - virtual EndQuiesceEvent *getQuiesceEvent() - { - return this->thread->quiesceEvent; - } -#endif + BranchPredictor(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); - virtual uint64_t readNextNPC() - { - return this->cpu->readNextNPC(this->thread->readTid()); - } + virtual void regStats(); - virtual void setNextNPC(uint64_t val) - { - this->cpu->setNextNPC(val, this->thread->readTid()); - } + virtual void execute(int slot_num); - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - //XXX Ignore this for now. This -really- needs to get fixed. - } + virtual void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + virtual void instGraduated(InstSeqNum seq_num,unsigned tid); - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. + protected: + /** List of instructions this resource is currently + * processing. */ - virtual int exit() - { - this->deallocate(); + BPredUnit branchPred; + + int instSize; + + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + Stats::Scalar predictedTaken; + Stats::Scalar predictedNotTaken; - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } }; + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc new file mode 100644 index 000000000..57bcb10ef --- /dev/null +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "arch/mips/locked_mem.hh" +#include "arch/utility.hh" +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "mem/request.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +Tick +CacheUnit::CachePort::recvAtomic(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvAtomic callback!"); + return curTick; +} + +void +CacheUnit::CachePort::recvFunctional(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvFunctional callback!"); +} + +void +CacheUnit::CachePort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("DefaultFetch doesn't expect recvStatusChange callback!"); +} + +bool +CacheUnit::CachePort::recvTiming(Packet *pkt) +{ + cachePortUnit->processCacheCompletion(pkt); + return true; +} + +void +CacheUnit::CachePort::recvRetry() +{ + cachePortUnit->recvRetry(); +} + +CacheUnit::CacheUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + retryPkt(NULL), retrySlot(-1), cacheBlocked(false) +{ + cachePort = new CachePort(this); +} + +Port * +CacheUnit::getPort(const string &if_name, int idx) +{ + if (if_name == resName) + return cachePort; + else + return NULL; +} + +int +CacheUnit::getSlot(DynInstPtr inst) +{ + if (!inst->validMemAddr()) { + panic("Mem. Addr. must be set before requesting cache access\n"); + } + + Addr req_addr = inst->getMemAddr(); + + if (resName == "icache_port" || + find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) { + + int new_slot = Resource::getSlot(inst); + + if (new_slot == -1) + return -1; + + inst->memTime = curTick; + addrList.push_back(req_addr); + addrMap[req_addr] = inst->seqNum; + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n", + inst->readTid(), inst->seqNum, req_addr); + return new_slot; + } else { + DPRINTF(InOrderCachePort, + "Denying request because there is an outstanding" + " request to/for addr. %08p. by [sn:%i] @ tick %i\n", + req_addr, addrMap[req_addr], inst->memTime); + return -1; + } +} + +void +CacheUnit::freeSlot(int slot_num) +{ + vector<Addr>::iterator vect_it = find(addrList.begin(), addrList.end(), + reqMap[slot_num]->inst->getMemAddr()); + assert(vect_it != addrList.end()); + + DPRINTF(InOrderCachePort, + "[tid:%i]: Address %08p removed from dependency list\n", + reqMap[slot_num]->inst->readTid(), (*vect_it)); + + addrList.erase(vect_it); + + Resource::freeSlot(slot_num); +} + +ResReqPtr +CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + ScheduleEntry* sched_entry = inst->resSched.top(); + + if (!inst->validMemAddr()) { + panic("Mem. Addr. must be set before requesting cache access\n"); + } + + int req_size = 0; + MemCmd::Command pkt_cmd; + + if (sched_entry->cmd == InitiateReadData) { + pkt_cmd = MemCmd::ReadReq; + req_size = inst->getMemAccSize(); + + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else if (sched_entry->cmd == InitiateWriteData) { + pkt_cmd = MemCmd::WriteReq; + req_size = inst->getMemAccSize(); + + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else if (sched_entry->cmd == InitiateFetch){ + pkt_cmd = MemCmd::ReadReq; + req_size = sizeof(MachInst); //@TODO: mips16e + + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else { + panic("%i: Unexpected request type (%i) to %s", curTick, + sched_entry->cmd, name()); + } + + return new CacheRequest(this, inst, stage_num, id, slot_num, + sched_entry->cmd, req_size, pkt_cmd, + 0/*flags*/, this->cpu->readCpuId()); +} + +void +CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) +{ + //service_request = false; + + CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst)); + assert(cache_req); + + // Check to see if this instruction is requesting the same command + // or a different one + if (cache_req->cmd != inst->resSched.top()->cmd) { + // If different, then update command in the request + cache_req->cmd = inst->resSched.top()->cmd; + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: the command for this instruction\n", + inst->readTid(), inst->seqNum); + + service_request = true; + } else { + // If same command, just check to see if memory access was completed + // but dont try to re-execute + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: requesting this resource again\n", + inst->readTid(), inst->seqNum); + + service_request = true; + } +} + +void +CacheUnit::execute(int slot_num) +{ + if (cacheBlocked) { + DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access\n"); + return; + } + + CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]); + assert(cache_req); + + DynInstPtr inst = cache_req->inst; + int tid; + tid = inst->readTid(); + int seq_num; + seq_num = inst->seqNum; + //int stage_num = cache_req->getStageNum(); + + cache_req->fault = NoFault; + + switch (cache_req->cmd) + { + case InitiateFetch: + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating fetch access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + DPRINTF(InOrderCachePort, + "[tid:%u]: Fetching new cache block from addr: %08p\n", + tid, cache_req->memReq->getVaddr()); + + inst->setCurResSlot(slot_num); + doDataAccess(inst); + break; + + case CompleteFetch: + if (cache_req->isMemAccComplete()) { + DPRINTF(InOrderCachePort, + "[tid:%i]: Completing Fetch Access for [sn:%i]\n", + tid, inst->seqNum); + + MachInst mach_inst = cache_req->dataPkt->get<MachInst>(); + + /** + * @TODO: May Need This Function for Endianness-Compatibility + * mach_inst = + * gtoh(*reinterpret_cast<MachInst *>(&cacheData[tid][offset])); + */ + + DPRINTF(InOrderCachePort, + "[tid:%i]: Fetched instruction is %08p\n", + tid, mach_inst); + + // ExtMachInst ext_inst = makeExtMI(mach_inst, cpu->tcBase(tid)); + + inst->setMachInst(mach_inst); + inst->setASID(tid); + inst->setThreadState(cpu->thread[tid]); + + DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n", + tid, seq_num, inst->staticInst->disassemble(inst->PC)); + + // Set Up More TraceData info + if (inst->traceData) { + inst->traceData->setStaticInst(inst->staticInst); + inst->traceData->setPC(inst->readPC()); + } + + cache_req->done(); + } else { + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n", + tid, inst->seqNum); + DPRINTF(InOrderStall, + "STALL: [tid:%i]: Fetch miss from %08p\n", + tid, cache_req->inst->readPC()); + cache_req->setCompleted(false); + } + break; + + case InitiateReadData: + case InitiateWriteData: + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating data access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + inst->setCurResSlot(slot_num); + //inst->memAccess(); + inst->initiateAcc(); + break; + + case CompleteReadData: + case CompleteWriteData: + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n", + tid, inst->seqNum); + if (cache_req->isMemAccComplete()) { + cache_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", + tid, cache_req->inst->getMemAddr()); + cache_req->setCompleted(false); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +Fault +CacheUnit::doDataAccess(DynInstPtr inst) +{ + Fault fault = NoFault; + int tid = 0; + + tid = inst->readTid(); + + CacheReqPtr cache_req + = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]); + assert(cache_req); + + cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd, + Packet::Broadcast); + + if (cache_req->dataPkt->isRead()) { + cache_req->dataPkt->dataStatic(cache_req->reqData); + } else if (cache_req->dataPkt->isWrite()) { + cache_req->dataPkt->dataStatic(&cache_req->inst->storeData); + + } + + cache_req->dataPkt->time = curTick; + + bool do_access = true; // flag to suppress cache access + + Request *memReq = cache_req->dataPkt->req; + + if (cache_req->dataPkt->isWrite() && memReq->isLocked()) { + assert(cache_req->inst->isStoreConditional()); + DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n"); + do_access = TheISA::handleLockedWrite(cpu, memReq); + } + + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] attempting to access cache\n", + tid, inst->seqNum); + + //@TODO: If you want to ignore failed store conditional accesses, then + // enable this. However, this might skew memory stats because + // the failed store conditional access will get ignored. + // - Remove optionality here ... + if (1/*do_access*/) { + if (!cachePort->sendTiming(cache_req->dataPkt)) { + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] is waiting to retry request\n", + tid, inst->seqNum); + + retrySlot = cache_req->getSlot(); + retryReq = cache_req; + retryPkt = cache_req->dataPkt; + + cacheStatus = cacheWaitRetry; + + //cacheBlocked = true; + + DPRINTF(InOrderStall, "STALL: \n"); + + cache_req->setCompleted(false); + } else { + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] is now waiting for cache response\n", + tid, inst->seqNum); + cache_req->setCompleted(); + cache_req->setMemAccPending(); + cacheStatus = cacheWaitResponse; + cacheBlocked = false; + } + } else if (!do_access && memReq->isLocked()){ + // Store-Conditional instructions complete even if they "failed" + assert(cache_req->inst->isStoreConditional()); + cache_req->setCompleted(true); + + DPRINTF(LLSC, + "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n", + tid, tid); + + cache_req->dataPkt->req->setExtraData(0); + + processCacheCompletion(cache_req->dataPkt); + + // Automatically set these since we ignored the memory access + //cache_req->setMemAccPending(false); + //cache_req->setMemAccCompleted(); + } else { + // Make cache request again since access due to + // inability to access + DPRINTF(InOrderStall, "STALL: \n"); + cache_req->setCompleted(false); + } + + return fault; +} + +void +CacheUnit::processCacheCompletion(PacketPtr pkt) +{ + // Cast to correct packet type + CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt); + assert(cache_pkt); + + if (cache_pkt->cacheReq->isSquashed()) { + DPRINTF(InOrderCachePort, + "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum); + + cache_pkt->cacheReq->done(); + return; + } + + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum, + cache_pkt->cacheReq->getInst()->getMemAddr()); + + // Cast to correct request type + CacheRequest *cache_req = dynamic_cast<CacheReqPtr>( + findRequest(cache_pkt->cacheReq->getInst())); + assert(cache_req); + + + // Get resource request info + // @todo: SMT needs to figure out where to get thread # from. + unsigned tid = 0; + unsigned stage_num = cache_req->getStageNum(); + DynInstPtr inst = cache_req->inst; + + if (!cache_req->isSquashed()) { + if (inst->resSched.top()->cmd == CompleteFetch) { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Processing fetch access\n", + tid, inst->seqNum); + } else if (inst->staticInst && inst->isMemRef()) { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Processing cache access\n", + tid, inst->seqNum); + + inst->completeAcc(pkt); + + if (inst->isLoad()) { + assert(cache_pkt->isRead()); + + if (cache_pkt->req->isLocked()) { + DPRINTF(InOrderCachePort, + "[tid:%u]: Handling Load-Linked for [sn:%u]\n", + tid, inst->seqNum); + TheISA::handleLockedRead(cpu, cache_pkt->req); + } + + // @TODO: Hardcoded to for load instructions. Assumes that + // the dest. idx 0 is always where the data is loaded to. + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Data loaded was: %08p\n", + tid, inst->seqNum, inst->readIntResult(0)); + } else if(inst->isStore()) { + assert(cache_pkt->isWrite()); + + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Data stored was: %08p\n", + tid, inst->seqNum, + getMemData(cache_pkt)); + + } + } + + cache_req->setMemAccPending(false); + cache_req->setMemAccCompleted(); + + // Wake up the CPU (if it went to sleep and was waiting on this + // completion event). + cpu->wakeCPU(); + + DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n", + tid, cpu->pipelineStage[stage_num]->name()); + + cpu->switchToActive(stage_num); + } else { + DPRINTF(InOrderCachePort, + "[tid:%u] Miss on block @ %08p completed, but squashed\n", + tid, cache_req->inst->readPC()); + cache_req->setMemAccCompleted(); + } + + inst->unsetMemAddr(); +} + +void +CacheUnit::recvRetry() +{ + DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i]\n", + retryReq->inst->readTid(), retryReq->inst->seqNum); + + assert(retryPkt != NULL); + assert(cacheBlocked); + assert(cacheStatus == cacheWaitRetry); + + if (cachePort->sendTiming(retryPkt)) { + cacheStatus = cacheWaitResponse; + retryPkt = NULL; + cacheBlocked = false; + } else { + DPRINTF(InOrderCachePort, + "Retry Request for [tid:%i] [sn:%i] failed\n", + retryReq->inst->readTid(), retryReq->inst->seqNum); + } +} + +void +CacheUnit::squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid) +{ + vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(InOrderCachePort, + "[tid:%i] Squashing request from [sn:%i]\n", + req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); + + req_ptr->setSquashed(); + + req_ptr->getInst()->setSquashed(); + + CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr); + assert(cache_req); + + if (!cache_req->isMemAccPending()) { + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) + freeSlot(slot_remove_list[i]); +} + +uint64_t +CacheUnit::getMemData(Packet *packet) +{ + switch (packet->getSize()) + { + case 8: + return packet->get<uint8_t>(); + + case 16: + return packet->get<uint16_t>(); + + case 32: + return packet->get<uint32_t>(); + + case 864: + return packet->get<uint64_t>(); + + default: + panic("bad store data size = %d\n", packet->getSize()); + } +} + diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh new file mode 100644 index 000000000..8cd2b89cb --- /dev/null +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_CACHE_UNIT_HH__ +#define __CPU_INORDER_CACHE_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +//#include "cpu/inorder/params.hh" + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" +#include "mem/port.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "sim/sim_object.hh" + +#include "params/InOrderCPU.hh" + +class CacheRequest; +typedef CacheRequest* CacheReqPtr; + +class CacheReqPacket; +typedef CacheReqPacket* CacheReqPktPtr; + +class CacheUnit : public Resource +{ + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + CacheUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~CacheUnit() {} + + enum Command { + InitiateFetch, + CompleteFetch, + InitiateReadData, + CompleteReadData, + InitiateWriteData, + CompleteWriteData, + Fetch, + ReadData, + WriteData + }; + + public: + /** CachePort class for the Cache Unit. Handles doing the + * communication with the cache/memory. + */ + class CachePort : public Port + { + protected: + /** Pointer to cache port unit */ + CacheUnit *cachePortUnit; + + public: + /** Default constructor. */ + CachePort(CacheUnit *_cachePortUnit) + : Port(_cachePortUnit->name() + "-cache-port", + (MemObject*)_cachePortUnit->cpu), + cachePortUnit(_cachePortUnit) + { } + + bool snoopRangeSent; + + protected: + /** Atomic version of receive. Panics. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** Functional version of receive. Panics. */ + virtual void recvFunctional(PacketPtr pkt); + + /** Receives status change. Other than range changing, panics. */ + virtual void recvStatusChange(Status status); + + /** Returns the address ranges of this device. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + /** Timing version of receive. Handles setting fetch to the + * proper status to start fetching. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of a failed fetch. */ + virtual void recvRetry(); + }; + + enum CachePortStatus { + cacheWaitResponse, + cacheWaitRetry, + cacheAccessComplete + }; + + ///virtual void init(); + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + void requestAgain(DynInstPtr inst, bool &try_request); + + int getSlot(DynInstPtr inst); + + void freeSlot(int slot_num); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + void execute(int slot_num); + + void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + + /** Processes cache completion event. */ + void processCacheCompletion(PacketPtr pkt); + + void recvRetry(); + + /** Align a PC to the start of an I-cache block. */ + Addr cacheBlockAlignPC(Addr addr) + { + //addr = TheISA::realPCToFetchPC(addr); + return (addr & ~(cacheBlkMask)); + } + + /** Returns a specific port. */ + Port *getPort(const std::string &if_name, int idx); + + /** Fetch on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to fetch. + */ + //Fault doFetchAccess(DynInstPtr inst); + + /** Read/Write on behalf of an instruction. + * curResSlot needs to be a valid value in instruction. + */ + Fault doDataAccess(DynInstPtr inst); + + uint64_t getMemData(Packet *packet); + + protected: + /** Cache interface. */ + CachePort *cachePort; + + CachePortStatus cacheStatus; + + CacheReqPtr retryReq; + + PacketPtr retryPkt; + + int retrySlot; + + bool cacheBlocked; + + std::vector<Addr> addrList; + + std::map<Addr, InstSeqNum> addrMap; + + public: + int cacheBlkSize; + + int cacheBlkMask; + + /** Align a PC to the start of the Cache block. */ + Addr cacheBlockAlign(Addr addr) + { + return (addr & ~(cacheBlkMask)); + } + + /** THINGS USED FOR FETCH */ + // NO LONGER USED BY COMMENT OUT UNTIL FULL VERIFICATION + /** The mem line being fetched. */ + //uint8_t *cacheData[ThePipeline::MaxThreads]; + + /** The Addr of the cacheline that has been loaded. */ + //Addr cacheBlockAddr[ThePipeline::MaxThreads]; + + //unsigned fetchOffset[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ +}; + +struct CacheSchedEntry : public ThePipeline::ScheduleEntry +{ + enum EntryType { + FetchAccess, + DataAccess + }; + + CacheSchedEntry(int stage_num, int _priority, int res_num, + MemCmd::Command pkt_cmd, EntryType _type = FetchAccess) + : ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd), + type(_type) + { } + + MemCmd::Command pktCmd; + EntryType type; +}; + +class CacheRequest : public ResourceRequest +{ + public: + CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd, int req_size, + MemCmd::Command pkt_cmd, unsigned flags, int cpu_id) + : ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd), + pktCmd(pkt_cmd), memAccComplete(false), memAccPending(false) + { + memReq = inst->memReq; + + reqData = new uint8_t[req_size]; + retryPkt = NULL; + } + + virtual ~CacheRequest() + { +#if 0 + delete reqData; + + // Can get rid of packet and packet request now + if (*dataPkt) { + if (*dataPkt->req) { + delete dataPkt->req; + } + delete dataPkt; + } + + // Can get rid of packet and packet request now + if (retryPkt) { + if (retryPkt->req) { + delete retryPkt->req; + } + delete retryPkt; + } +#endif + + if (memReq) + delete memReq; + } + + virtual PacketDataPtr getData() + { return reqData; } + + void + setMemAccCompleted(bool completed = true) + { + memAccComplete = completed; + } + + bool isMemAccComplete() { return memAccComplete; } + + void setMemAccPending(bool pending = true) { memAccPending = pending; } + bool isMemAccPending() { return memAccPending; } + + //Make this data private/protected! + MemCmd::Command pktCmd; + RequestPtr memReq; + PacketDataPtr reqData; + PacketPtr dataPkt; + PacketPtr retryPkt; + + bool memAccComplete; + bool memAccPending; +}; + +class CacheReqPacket : public Packet +{ + public: + CacheReqPacket(CacheRequest *_req, + Command _cmd, short _dest) + : Packet(_req->memReq, _cmd, _dest), cacheReq(_req) + { + + } + + CacheRequest *cacheReq; +}; + +#endif //__CPU_CACHE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc new file mode 100644 index 000000000..d95b1d4bb --- /dev/null +++ b/src/cpu/inorder/resources/decode_unit.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/decode_unit.hh" + +using namespace TheISA; +using namespace ThePipeline; +using namespace std; + +DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ + for (int tid = 0; tid < MaxThreads; tid++) { + regDepMap[tid] = &cpu->archRegDepMap[tid]; + } +} + +void +DecodeUnit::execute(int slot_num) +{ + ResourceRequest* decode_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid, seq_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + decode_req->fault = NoFault; + + switch (decode_req->cmd) + { + case DecodeInst: + { + bool done_sked = ThePipeline::createBackEndSchedule(inst); + + if (done_sked) { + DPRINTF(InOrderDecode, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", + tid, seq_num); + regDepMap[tid]->insert(inst); + decode_req->done(); + } else { + DPRINTF(Resource,"[tid:%i] Static Inst not available to decode. Unable to create " + "schedule for instruction [sn:%i] \n", tid, inst->seqNum); + DPRINTF(InOrderStall, "STALL: \n"); + decode_req->done(false); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + + +void +DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderDecode, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n", + tid, stage_num, squash_seq_num); + + //cpu->removeInstsUntil(squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/decode_unit.hh b/src/cpu/inorder/resources/decode_unit.hh new file mode 100644 index 000000000..3813de6c4 --- /dev/null +++ b/src/cpu/inorder/resources/decode_unit.hh @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_DECODE_UNIT_HH__ +#define __CPU_INORDER_DECODE_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/reg_dep_map.hh" + +class DecodeUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + DecodeUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~DecodeUnit() {} + + enum Command { + DecodeInst + }; + + virtual void execute(int slot_num); + + void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + RegDepMap *regDepMap[ThePipeline::MaxThreads]; + + protected: + /** @todo: Add Resource Stats Here */ +}; + +#endif //__CPU_INORDER_DECODE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc new file mode 100644 index 000000000..843adb5b0 --- /dev/null +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "cpu/inorder/resources/execution_unit.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace ThePipeline; + +ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +ExecutionUnit::regStats() +{ + predictedTakenIncorrect + .name(name() + ".predictedTakenIncorrect") + .desc("Number of Branches Incorrectly Predicted As Taken."); + + predictedNotTakenIncorrect + .name(name() + ".predictedNotTakenIncorrect") + .desc("Number of Branches Incorrectly Predicted As Not Taken)."); + + Resource::regStats(); +} + +void +ExecutionUnit::execute(int slot_num) +{ + ResourceRequest* exec_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + + exec_req->fault = NoFault; + + DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n", + tid, seq_num, inst->readPC()); + + switch (exec_req->cmd) + { + case ExecuteInst: + { + if (inst->isMemRef()) { + fatal("%s not configured to handle memory ops.\n", resName); + } else if (inst->isControl()) { + // Evaluate Branch + fault = inst->execute(); + + inst->setExecuted(); + + if (fault == NoFault) { + // If branch is mispredicted, then signal squash + // throughout all stages behind the pipeline stage + // that got squashed. + if (inst->mispredicted()) { + int stage_num = exec_req->getStageNum(); + int tid = inst->readTid(); + + // If it's a branch ... + if (inst->isDirectCtrl()) { + assert(!inst->isIndirectCtrl()); + + if (inst->predTaken() && inst->isCondDelaySlot()) { + inst->bdelaySeqNum = seq_num; + inst->setPredTarg(inst->nextPC); + + DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst" + "[sn:%i] PC %#x mispredicted as taken.\n", tid, + seq_num, inst->PC); + } else if (!inst->predTaken() && inst->isCondDelaySlot()) { + inst->bdelaySeqNum = seq_num; + inst->setPredTarg(inst->nextPC); + inst->procDelaySlotOnMispred = true; + + DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst." + "[sn:%i] PC %#x mispredicted as not taken.\n", tid, + seq_num, inst->PC); + } else { + inst->bdelaySeqNum = seq_num + 1; + + DPRINTF(InOrderExecute, "[tid:%i]: Misprediction detected at " + "[sn:%i] PC %#x,\n\t squashing after delay slot " + "instruction [sn:%i].\n", + tid, seq_num, inst->PC, inst->bdelaySeqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch " + "misprediction at %#x\n", tid, inst->PC); + inst->setPredTarg(inst->nextNPC); + } + + DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid, + inst->readPredTarg()); + + } else if(inst->isIndirectCtrl()){ + inst->setPredTarg(inst->nextNPC); + inst->bdelaySeqNum = seq_num + 1; + DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid, + inst->readPredTarg()); + } else { + panic("Non-control instruction (%s) mispredicting?!!", + inst->staticInst->getName()); + } + + DPRINTF(InOrderExecute, "[tid:%i] Squashing will start from stage %i.\n", + tid, stage_num); + + cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + + inst->squashingStage = stage_num; + + // Squash throughout other resources + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, + inst, 0, 0, tid); + + if (inst->predTaken()) { + predictedTakenIncorrect++; + } else { + predictedNotTakenIncorrect++; + } + } + exec_req->done(); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + } + } else { + // Regular ALU instruction + fault = inst->execute(); + + if (fault == NoFault) { + inst->setExecuted(); + exec_req->done(); + + DPRINTF(InOrderExecute, "[tid:%i]: The result of execution is 0x%x.\n", + inst->readTid(), inst->readIntResult(0)); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + cpu->trap(fault, tid); + } + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + + diff --git a/src/cpu/o3/mips/thread_context.hh b/src/cpu/inorder/resources/execution_unit.hh index 26b1e2e7f..46691bbf2 100644 --- a/src/cpu/o3/mips/thread_context.hh +++ b/src/cpu/inorder/resources/execution_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,44 +25,53 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim - * Korey Sewell + * Authors: Korey Sewell + * */ -#include "arch/mips/types.hh" -#include "cpu/o3/thread_context.hh" +#ifndef __CPU_INORDER_EXECUTION_UNIT_HH__ +#define __CPU_INORDER_EXECUTION_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> -template <class Impl> -class MipsTC : public O3ThreadContext<Impl> -{ +#include "cpu/func_unit.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" + +class ExecutionUnit : public Resource { public: - virtual uint64_t readNextNPC() - { - return this->cpu->readNextNPC(this->thread->readTid()); - } + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + ExecuteInst + }; - virtual void setNextNPC(uint64_t val) - { - this->cpu->setNextNPC(val, this->thread->readTid()); - } + public: + ExecutionUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~ExecutionUnit() {} - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Mips!"); } + public: + virtual void regStats(); - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. */ - virtual int exit() - { - this->deallocate(); + virtual void execute(int slot_num); - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } + protected: + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + Stats::Scalar predictedTakenIncorrect; + Stats::Scalar predictedNotTakenIncorrect; }; + + +#endif //__CPU_INORDER_EXCUTION_UNIT_HH__ diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc new file mode 100644 index 000000000..444252e1b --- /dev/null +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/fetch_seq_unit.hh" +#include "cpu/inorder/resource_pool.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + instSize(sizeof(MachInst)) +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + pcValid[tid] = false; + pcBlockStage[tid] = 0; + + squashSeqNum[tid] = (InstSeqNum)-1; + lastSquashCycle[tid] = 0; + } +} + +void +FetchSeqUnit::init() +{ + resourceEvent = new FetchSeqEvent[width]; + + initSlots(); +} + +void +FetchSeqUnit::execute(int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + ResourceRequest* fs_req = reqMap[slot_num]; + DynInstPtr inst = fs_req->inst; + int tid = inst->readTid(); + int stage_num = fs_req->getStageNum(); + int seq_num = inst->seqNum; + + fs_req->fault = NoFault; + + switch (fs_req->cmd) + { + case AssignNextPC: + { + if (pcValid[tid]) { + + if (delaySlotInfo[tid].targetReady && + delaySlotInfo[tid].numInsts == 0) { + // Set PC to target + PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC + nextPC[tid] = PC[tid] + instSize; //next_NPC + nextNPC[tid] = PC[tid] + (2 * instSize); + + delaySlotInfo[tid].targetReady = false; + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to delay slot target\n",tid); + } + + inst->setPC(PC[tid]); + inst->setNextPC(PC[tid] + instSize); + inst->setNextNPC(PC[tid] + (instSize * 2)); + + inst->setPredTarg(inst->readNextNPC()); + + inst->setMemAddr(PC[tid]); + inst->setSeqNum(cpu->getAndIncrementInstSeq(tid)); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid, + inst->seqNum, inst->readPC()); + + if (delaySlotInfo[tid].numInsts > 0) { + --delaySlotInfo[tid].numInsts; + + // It's OK to set PC to target of branch + if (delaySlotInfo[tid].numInsts == 0) { + delaySlotInfo[tid].targetReady = true; + } + + DPRINTF(InOrderFetchSeq, "[tid:%i]: %i delay slot inst(s) left to" + " process.\n", tid, delaySlotInfo[tid].numInsts); + } + + PC[tid] = nextPC[tid]; + nextPC[tid] = nextNPC[tid]; + nextNPC[tid] += instSize; + + fs_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid); + fs_req->setCompleted(false); + } + } + break; + + case UpdateTargetPC: + { + if (inst->isControl()) { + // If it's a return, then we must wait for resolved address. + if (inst->isReturn() && !inst->predTaken()) { + cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true; + pcValid[tid] = false; + pcBlockStage[tid] = stage_num; + } else if (inst->isCondDelaySlot() && !inst->predTaken()) { + // Not-Taken AND Conditional Control + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. " + "Delay inst. Skipping delay slot and Updating PC to %08p\n", + tid, inst->seqNum, inst->readPC(), inst->readPredTarg()); + + DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + tid, stage_num, seq_num); + + inst->bdelaySeqNum = seq_num; + inst->squashingStage = stage_num; + + squashAfterInst(inst, stage_num, tid); + } else if (!inst->isCondDelaySlot() && !inst->predTaken()) { + // Not-Taken Control + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control " + "inst. updating PC to %08p\n", tid, inst->seqNum, + inst->readNextPC()); + + ++delaySlotInfo[tid].numInsts; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = inst->readNextNPC(); + + } else if (inst->predTaken()) { + // Taken Control + ++delaySlotInfo[tid].numInsts; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = inst->readPredTarg(); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i] Updating delay slot target " + "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg()); + + // Set-Up Squash Through-Out Pipeline + DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + tid, stage_num, seq_num + 1); + inst->bdelaySeqNum = seq_num + 1; + inst->squashingStage = stage_num; + + // Do Squashing + squashAfterInst(inst, stage_num, tid); + } + } else { + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch target update " + "since then is not a control instruction.\n", tid, inst->seqNum); + } + + fs_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +inline void +FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid) +{ + // Squash In Pipeline Stage + cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + + // Squash inside current resource, so if there needs to be fetching on same cycle + // the fetch information will be correct. + // squash(inst, stage_num, inst->bdelaySeqNum, tid); + + // Schedule Squash Through-out Resource Pool + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0); +} +void +FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from stage %i.\n", + tid, squash_stage); + + InstSeqNum done_seq_num = inst->bdelaySeqNum; + Addr new_PC = inst->readPredTarg(); + + if (squashSeqNum[tid] <= done_seq_num && + lastSquashCycle[tid] == curTick) { + DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, since" + "there is an outstanding squash that is older.\n", + tid, squash_stage); + } else { + squashSeqNum[tid] = done_seq_num; + lastSquashCycle[tid] = curTick; + + // If The very next instruction number is the done seq. num, + // then we haven't seen the delay slot yet ... if it isn't + // the last done_seq_num then this is the delay slot inst. + if (cpu->nextInstSeqNum(tid) != done_seq_num && + !inst->procDelaySlotOnMispred) { + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + // Reset PC + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + nextNPC[tid] = new_PC + (2 * instSize); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %08p.\n", + tid, PC[tid]); + } else { + delaySlotInfo[tid].numInsts = 1; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ? inst->branchTarget() : new_PC; + + // Reset PC to Delay Slot Instruction + if (inst->procDelaySlotOnMispred) { + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + nextNPC[tid] = new_PC + (2 * instSize); + } + + } + + // Unblock Any Stages Waiting for this information to be updated ... + if (!pcValid[tid]) { + cpu->pipelineStage[pcBlockStage[tid]]->toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true; + } + + pcValid[tid] = true; + } + + Resource::squash(inst, squash_stage, squash_seq_num, tid); +} + +FetchSeqUnit::FetchSeqEvent::FetchSeqEvent() + : ResourceEvent() +{ } + +void +FetchSeqUnit::FetchSeqEvent::process() +{ + FetchSeqUnit* fs_res = dynamic_cast<FetchSeqUnit*>(resource); + assert(fs_res); + + for (int i=0; i < MaxThreads; i++) { + fs_res->PC[i] = fs_res->cpu->readPC(i); + fs_res->nextPC[i] = fs_res->cpu->readNextPC(i); + fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i); + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n", + fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]); + + fs_res->pcValid[i] = true; + } + + //cpu->fetchPriorityList.push_back(tid); +} + + +void +FetchSeqUnit::activateThread(unsigned tid) +{ + pcValid[tid] = true; + + PC[tid] = cpu->readPC(tid); + nextPC[tid] = cpu->readNextPC(tid); + nextNPC[tid] = cpu->readNextNPC(tid); + + cpu->fetchPriorityList.push_back(tid); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n", + tid, PC[tid], nextPC[tid], nextNPC[tid]); +} + +void +FetchSeqUnit::deactivateThread(unsigned tid) +{ + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + pcValid[tid] = false; + pcBlockStage[tid] = 0; + + squashSeqNum[tid] = (InstSeqNum)-1; + lastSquashCycle[tid] = 0; + + std::list<unsigned>::iterator thread_it = find(cpu->fetchPriorityList.begin(), + cpu->fetchPriorityList.end(), + tid); + + if (thread_it != cpu->fetchPriorityList.end()) + cpu->fetchPriorityList.erase(thread_it); +} diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh new file mode 100644 index 000000000..1885d1f11 --- /dev/null +++ b/src/cpu/inorder/resources/fetch_seq_unit.hh @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_FETCH_SEQ_UNIT_HH__ +#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class FetchSeqUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + AssignNextPC, + UpdateTargetPC + }; + + public: + FetchSeqUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~FetchSeqUnit() {} + + virtual void init(); + virtual void activateThread(unsigned tid); + virtual void deactivateThread(unsigned tid); + virtual void execute(int slot_num); + + /** Override default Resource squash sequence. This actually, + * looks in the global communication buffer to get squash + * info + */ + virtual void squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid); + + + inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid); + + protected: + unsigned instSize; + + bool pcValid[ThePipeline::MaxThreads]; + int pcBlockStage[ThePipeline::MaxThreads]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** Tracks delay slot information for threads in ISAs which use + * delay slots; + */ + struct DelaySlotInfo { + InstSeqNum delaySlotSeqNum; + InstSeqNum branchSeqNum; + int numInsts; + Addr targetAddr; + bool targetReady; + }; + + DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads]; + + /** Squash Seq. Nums*/ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Squash Seq. Nums*/ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ + + public: + class FetchSeqEvent : public ResourceEvent { + public: + /** Constructs a resource event. */ + FetchSeqEvent(); + virtual ~FetchSeqEvent() {} + + /** Processes a resource event. */ + virtual void process(); + }; + +}; + +#endif diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc new file mode 100644 index 000000000..569401e4f --- /dev/null +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/graduation_unit.hh" + +using namespace ThePipeline; + +GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + lastCycleGrad(0), numCycleGrad(0) + +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; + nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; + } +} + +void +GraduationUnit::execute(int slot_num) +{ + ResourceRequest* grad_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid, seq_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + int stage_num = inst->resSched.top()->stageNum; + + grad_req->fault = NoFault; + + switch (grad_req->cmd) + { + case GraduateInst: + { + // @TODO: Instructions should never really get to this point since this should be handled + // through the request interface. Check to make sure this happens and delete this + // code. + if (lastCycleGrad != curTick) { + lastCycleGrad = curTick; + numCycleGrad = 0; + } else if (numCycleGrad > width) { + DPRINTF(InOrderGraduation, "Graduation bandwidth reached for this cycle.\n"); + return; + } + + // Make sure this is the last thing on the resource schedule + assert(inst->resSched.size() == 1); + + DPRINTF(InOrderGraduation, "[tid:%i] Graduating instruction [sn:%i].\n", + tid, seq_num); + + DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/); + + // Release Non-Speculative "Block" on instructions that could not execute + // because there was a non-speculative inst. active. + // @TODO: Fix this functionality. Probably too conservative. + if (inst->isNonSpeculative()) { + *nonSpecInstActive[tid] = false; + DPRINTF(InOrderGraduation, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n", + tid, seq_num); + } + + if (inst->traceData) { + inst->traceData->setStageCycle(stage_num, curTick); + } + + // Tell CPU that instruction is finished processing + cpu->instDone(inst, tid); + + //cpu->pipelineStage[stage_num]->toPrevStages-> + //stageInfo[stage_num][tid].doneSeqNum = inst->seqNum; + + grad_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + +} diff --git a/src/cpu/o3/alpha/params.hh b/src/cpu/inorder/resources/graduation_unit.hh index 164c25312..ad222b119 100644 --- a/src/cpu/o3/alpha/params.hh +++ b/src/cpu/inorder/resources/graduation_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,37 +25,46 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim + * Authors: Korey Sewell + * */ -#ifndef __CPU_O3_ALPHA_PARAMS_HH__ -#define __CPU_O3_ALPHA_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace AlphaISA -{ - class DTB; - class ITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaO3CPU. - * 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. - */ +#ifndef __CPU_INORDER_GRAD_UNIT_HH__ +#define __CPU_INORDER_GRAD_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> -class AlphaSimpleParams : public O3Params -{ +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class GraduationUnit : public Resource { public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + GraduateInst + }; + + public: + GraduationUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~GraduationUnit() {} + + virtual void execute(int slot_num); + + protected: + Tick lastCycleGrad; + int numCycleGrad; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; - AlphaISA::ITB *itb; - AlphaISA::DTB *dtb; + /** @todo: Add Resource Stats Here */ }; -#endif // __CPU_O3_ALPHA_PARAMS_HH__ +#endif //__CPU_INORDER_GRAD_UNIT_HH__ diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc new file mode 100644 index 000000000..fafff1fa7 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InstBuffer::InstBuffer(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +InstBuffer::regStats() +{ + instsBypassed + .name(name() + ".instsBypassed") + .desc("Number of Instructions Bypassed."); + + Resource::regStats(); +} + +void +InstBuffer::execute(int slot_idx) +{ + ResReqPtr ib_req = reqMap[slot_idx]; + DynInstPtr inst = ib_req->inst; + int tid, seq_num, stage_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + stage_num = ib_req->getStageNum(); + ib_req->fault = NoFault; + + switch (ib_req->cmd) + { + case ScheduleOrBypass: + { + int next_stage = stage_num + 1; + int bypass_stage = stage_num + 2; + bool do_bypass = true; + + if (!instList.empty()) { + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n", + inst->seqNum, next_stage); + do_bypass = false; + } else if(cpu->pipelineStage[bypass_stage]->isBlocked(tid)) { + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n", + inst->seqNum, next_stage); + do_bypass = false; + } else if(cpu->pipelineStage[bypass_stage]->stageBufferAvail() <= 0) { + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because there is no room in " + "stage %i incoming stage buffer.\n", inst->seqNum, next_stage); + do_bypass = false; + } + + if (!do_bypass) { // SCHEDULE USAGE OF BUFFER + DPRINTF(InOrderInstBuffer, "Scheduling [sn:%i] for buffer insertion in stage %i\n", + inst->seqNum, next_stage); + + // Add to schedule: Insert into buffer in next stage + int stage_pri = ThePipeline::getNextPriority(inst, next_stage); + + inst->resSched.push(new ScheduleEntry(next_stage, stage_pri, id, + InstBuffer::InsertInst)); + + // Add to schedule: Remove from buffer in next next (bypass) stage + stage_pri = ThePipeline::getNextPriority(inst, bypass_stage); + + inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id, + InstBuffer::RemoveInst)); + } else { // BYPASS BUFFER & NEXT STAGE + DPRINTF(InOrderInstBuffer, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n", + inst->seqNum, next_stage, bypass_stage); + inst->setNextStage(bypass_stage); + instsBypassed++; + } + + ib_req->done(); + } + break; + + case InsertInst: + { + bool inserted = false; + + if (instList.size() < width) { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + tid, seq_num); + insert(inst); + inserted = true; + } else { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Denying [sn:%i] request because " + "buffer is full.\n", tid, seq_num); + + + std::list<DynInstPtr>::iterator list_it = instList.begin(); + std::list<DynInstPtr>::iterator list_end = instList.end(); + + while (list_it != list_end) { + DPRINTF(Resource,"Serving [tid:%i] [sn:%i].\n", (*list_it)->readTid(), (*list_it)->seqNum); + list_it++; + } + } + + ib_req->done(inserted); + } + break; + + case RemoveInst: + { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing [sn:%i] from buffer.\n", + tid, seq_num); + remove(inst); + ib_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + + DPRINTF(InOrderInstBuffer, "Buffer now contains %i insts.\n", instList.size()); +} + +void +InstBuffer::insert(DynInstPtr inst) +{ + instList.push_back(inst); +} + +void +InstBuffer::remove(DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = instList.begin(); + std::list<DynInstPtr>::iterator list_end = instList.end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + instList.erase(list_it); + break; + } + list_it++; + } +} + +void +InstBuffer::pop(unsigned tid) +{ + instList.pop_front(); +} + +ThePipeline::DynInstPtr +InstBuffer::top(unsigned tid) +{ + return instList.front(); +} + +void +InstBuffer::squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid) +{ + queue<list<DynInstPtr>::iterator> remove_list; + list<DynInstPtr>::iterator list_it = instList.begin(); + list<DynInstPtr>::iterator list_end = instList.end(); + + // Collect All Instructions to be Removed in Remove List + while (list_it != list_end) { + if((*list_it)->readTid() == tid && + (*list_it)->seqNum > squash_seq_num) { + (*list_it)->setSquashed(); + remove_list.push(list_it); + } + + list_it++; + } + + // Removed Instructions from InstList & Clear Remove List + while (!remove_list.empty()) { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n", + tid, (*remove_list.front())->seqNum); + instList.erase(remove_list.front()); + remove_list.pop(); + } + + Resource::squash(inst, stage_num, squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh new file mode 100644 index 000000000..baadd42ff --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer.hh @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ +#define __CPU_INORDER_INST_BUFF_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class InstBuffer : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + enum Command { + InsertInst, + InsertAddr, + RemoveInst, + RemoveAddr, + ScheduleOrBypass + }; + + public: + InstBuffer(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~InstBuffer() {} + + virtual void regStats(); + + virtual void execute(int slot_num); + + virtual void insert(DynInstPtr inst); + + virtual void remove(DynInstPtr inst); + + virtual void pop(unsigned tid); + + virtual DynInstPtr top(unsigned tid); + + virtual void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list<DynInstPtr> instList; + + public: + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar instsBypassed; + +}; + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc new file mode 100644 index 000000000..7e2c98837 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer_new.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InstBuffer::InstBuffer(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +ResReqPtr +InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top()); + assert(ib_entry); + + return new InstBufferRequest(this, inst, stage_num, id, slot_num, + ib_entry->cmd); +} + +void +InstBuffer::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]); + assert(ib_req); + + DynInstPtr inst = ib_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + ib_req->fault = NoFault; + + switch (ib_req->cmd) + { + case InsertInst: + { + DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + tid, seq_num); + insert(inst); + ib_req->done(); + } + break; + + case RemoveInst: + { + DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", + tid, seq_num); + remove(inst); + ib_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + + DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); +} + +void +InstBuffer::insert(DynInstPtr inst) +{ + instList.push_back(inst); +} + +void +InstBuffer::remove(DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = instList.begin(); + std::list<DynInstPtr>::iterator list_end = instList.end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + instList.erase(list_it); + break; + } + list_it++; + } +} + +void +InstBuffer::pop() +{ instList.pop_front(); } + +ThePipeline::DynInstPtr +InstBuffer::top() +{ return instList.front(); } + +void +InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + list<DynInstPtr>::iterator list_it = instList.begin(); + list<DynInstPtr>::iterator list_end = instList.end(); + queue<list<DynInstPtr>::iterator> remove_list; + + // Collect All Instructions to be Removed in Remove List + while (list_it != list_end) { + if((*list_it)->seqNum > squash_seq_num) { + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n", + tid, (*list_it)->seqNum); + (*list_it)->setSquashed(); + remove_list.push(list_it); + } + + list_it++; + } + + // Removed Instructions from InstList & Clear Remove List + while (!remove_list.empty()) { + instList.erase(remove_list.front()); + remove_list.pop(); + } + + Resource::squash(squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh new file mode 100644 index 000000000..e374fa109 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer_new.hh @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ +#define __CPU_INORDER_INST_BUFF_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class InstBuffer : public Resource { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + enum Command { + InsertInst, + InsertAddr, + RemoveInst, + RemoveAddr + }; + + public: + InstBuffer(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~InstBuffer() {} + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num); + + virtual void execute(int slot_num); + + virtual void insert(DynInstPtr inst); + + virtual void remove(DynInstPtr inst); + + virtual void pop(); + + virtual DynInstPtr top(); + + virtual void squash(InstSeqNum squash_seq_num, unsigned tid); + + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list<DynInstPtr> instList; + + /** @todo: Add Resource Stats Here */ + +}; + +struct InstBufferEntry : public ThePipeline::ScheduleEntry { + InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) : + ScheduleEntry(stage_num, res_num), cmd(_cmd) + { } + + InstBuffer::Command cmd; +}; + +class InstBufferRequest : public ResourceRequest { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, + InstBuffer::Command _cmd) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num), + cmd(_cmd) + { } + + InstBuffer::Command cmd; +}; + + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/o3/sparc/params.hh b/src/cpu/inorder/resources/mem_dep_unit.hh index 09f523818..0bd850c5c 100644 --- a/src/cpu/o3/sparc/params.hh +++ b/src/cpu/inorder/resources/mem_dep_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,37 +25,42 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black + * Authors: Korey Sewell + * */ -#ifndef __CPU_O3_SPARC_PARAMS_HH__ -#define __CPU_O3_SPARC_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace SparcISA -{ - class DTB; - class ITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaO3CPU. - * 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. - */ +#ifndef __CPU_INORDER_GRAD_UNIT_HH__ +#define __CPU_INORDER_GRAD_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class MemDepUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; -class SparcSimpleParams : public O3Params -{ public: + MemDepUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~MemDepUnit() {} + + virtual void execute(int slot_num); + + protected: + Tick lastCycleGrad; + int numCycleGrad; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; - SparcISA::ITB *itb; - SparcISA::DTB *dtb; + /** @todo: Add Resource Stats Here */ }; -#endif // __CPU_O3_SPARC_PARAMS_HH__ +#endif //__CPU_INORDER_GRAD_UNIT_HH__ diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc new file mode 100644 index 000000000..b31d60ad5 --- /dev/null +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "cpu/inorder/resources/mult_div_unit.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/op_class.hh" + +using namespace std; +using namespace ThePipeline; + +MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + multRepeatRate(params->multRepeatRate), multLatency(params->multLatency), + div8RepeatRate(params->div8RepeatRate), div8Latency(params->div8Latency), + div16RepeatRate(params->div16RepeatRate), div16Latency(params->div16Latency), + div24RepeatRate(params->div24RepeatRate), div24Latency(params->div24Latency), + div32RepeatRate(params->div32RepeatRate), div32Latency(params->div32Latency), + lastMDUCycle(0) +{ } + +void +MultDivUnit::regStats() +{ + multInstReqsProcessed + .name(name() + ".multInstReqsProcessed") + .desc("Number of Multiply Requests Processed."); + + divInstReqsProcessed + .name(name() + ".divInstReqsProcessed") + .desc("Number of Divide Requests Processed."); + + Resource::regStats(); +} + +void +MultDivUnit::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new MDUEvent[width]; + + initSlots(); +} + +int +MultDivUnit::findSlot(DynInstPtr inst) +{ + DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n", + inst->seqNum, slotsAvail(), slotsInUse()); + + return Resource::findSlot(inst); +} + +void +MultDivUnit::freeSlot(int slot_idx) +{ + DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n", + reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse()); + + Resource::freeSlot(slot_idx); +} + + +int +MultDivUnit::getSlot(DynInstPtr inst) +{ + // If MDU already has instruction, return current slot. + int slot_num = findSlot(inst); + + // If we have this instruction's request already then return + if (slot_num != -1 && + inst->resSched.top()->cmd == reqMap[slot_num]->cmd) + return slot_num; + + unsigned repeat_rate = 0; + + /** Enforce MDU dependencies after a multiply is seen last */ + if (lastOpType == IntMultOp) { + repeat_rate = multRepeatRate; + } + + /** Enforce dependencies after a divide is seen last */ + if (lastOpType == IntDivOp) { + switch (lastDivSize) { + case 8: + repeat_rate = div8RepeatRate; + break; + + case 16: + repeat_rate = div16RepeatRate; + break; + + case 24: + repeat_rate = div24RepeatRate; + break; + + case 32: + repeat_rate = div32RepeatRate; + break; + } + } + + if (lastMDUCycle + repeat_rate > curTick) { + DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n", + lastMDUCycle + repeat_rate); + return -1; + } else { + int rval = Resource::getSlot(inst); + DPRINTF(InOrderMDU, "MDU request should pass: %i.\n", + rval); + + if (rval != -1) { + lastMDUCycle = curTick; + lastOpType = inst->opClass(); + lastInstName = inst->staticInst->getName(); + } + + return rval; + } +} + +int +MultDivUnit::getDivOpSize(DynInstPtr inst) +{ + // Get RT Register from instruction (index #1) + uint32_t div_op = inst->readIntSrc(1); + + if (div_op <= 0xFF) { + return 8; + } else if (div_op <= 0xFFFF) { + return 16; + } else if (div_op <= 0xFFFFFF) { + return 24; + } else { + return 32; + } +} + +void +MultDivUnit::execute(int slot_num) +{ + ResourceRequest* mult_div_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + + //int tid = inst->readTid(); + //int seq_num = inst->seqNum; + + switch (mult_div_req->cmd) + { + case StartMultDiv: + DPRINTF(InOrderMDU, "Start MDU called ...\n"); + + if (inst->opClass() == IntMultOp) { + scheduleEvent(slot_num, multLatency); + multInstReqsProcessed++; + } else if (inst->opClass() == IntDivOp) { + int op_size = getDivOpSize(inst); + + switch (op_size) + { + case 8: + scheduleEvent(slot_num, div8Latency); + break; + + case 16: + scheduleEvent(slot_num, div16Latency); + break; + + case 24: + scheduleEvent(slot_num, div24Latency); + break; + + case 32: + scheduleEvent(slot_num, div32Latency); + break; + } + + lastDivSize = op_size; + + divInstReqsProcessed++; + } + + // Allow to pass through to next stage while + // event processes + mult_div_req->setCompleted(); + break; + + case MultDiv: + DPRINTF(InOrderMDU, "Execute MDU called ...\n"); + exeMulDiv(slot_num); + mult_div_req->done(); + break; + + + case EndMultDiv: + //@TODO: Why not allow high-latency requests to sleep + // within stage until event wakes up???? + // Seems wasteful to continually check to see if + // this is done when we have a event in parallel + // counting down the time + { + DPRINTF(InOrderMDU, "End MDU called ...\n"); + if (mult_div_req->getInst()->isExecuted()) + mult_div_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +void +MultDivUnit::exeMulDiv(int slot_num) +{ + ResourceRequest* mult_div_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + + fault = inst->execute(); + + if (fault == NoFault) { + inst->setExecuted(); + mult_div_req->setCompleted(); + + DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n", + inst->readTid(), inst->readIntResult(0)); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + cpu->trap(fault, tid); + } +} + + +MDUEvent::MDUEvent() + : ResourceEvent() +{ } + +void +MDUEvent::process() +{ + MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource); + + mdu_res->exeMulDiv(slotIdx); + + ResourceRequest* mult_div_req = resource->reqMap[slotIdx]; + + mult_div_req->done(); +} + + diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh new file mode 100644 index 000000000..76180714c --- /dev/null +++ b/src/cpu/inorder/resources/mult_div_unit.hh @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_MULT_DIV_UNIT_HH__ +#define __CPU_INORDER_MULT_DIV_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/func_unit.hh" +#include "cpu/op_class.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" + +class MDUEvent; + +class MultDivUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + StartMultDiv, + EndMultDiv, + MultDiv + }; + + public: + MultDivUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~MultDivUnit() {} + + public: + /** Override default Resource getSlot(). Will only getSlot if + * valid mult/div sequence is being maintained + */ + virtual int getSlot(DynInstPtr inst); + + virtual int findSlot(DynInstPtr inst); + + virtual void freeSlot(int slot_idx); + + virtual void init(); + + /** Get Operand Size For A Division Operation */ + int getDivOpSize(DynInstPtr inst); + + /** Override default Resource execute */ + virtual void execute(int slot_num); + + void exeMulDiv(int slot_num); + + /** Register extra resource stats */ + virtual void regStats(); + + protected: + /** Latency & Repeat Rate for Multiply Insts */ + unsigned multRepeatRate; + unsigned multLatency; + + /** Latency & Repeat Rate for 8-bit Divide Insts */ + unsigned div8RepeatRate; + unsigned div8Latency; + + /** Latency & Repeat Rate for 16-bit Divide Insts */ + unsigned div16RepeatRate; + unsigned div16Latency; + + /** Latency & Repeat Rate for 24-bit Divide Insts */ + unsigned div24RepeatRate; + unsigned div24Latency; + + /** Latency & Repeat Rate for 32-bit Divide Insts */ + unsigned div32RepeatRate; + unsigned div32Latency; + + /** Last cycle that MDU was used */ + Tick lastMDUCycle; + + /** Last type of instruction MDU started processing */ + OpClass lastOpType; + + /** Last Division Operand of instruction MDU was processing */ + uint32_t lastDivSize; + + /** Last instruction name the MDU used */ + std::string lastInstName; + + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar multInstReqsProcessed; + + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar divInstReqsProcessed; + + MDUEvent *mduEvent; +}; + +class MDUEvent : public ResourceEvent +{ + public: + MDUEvent(); + virtual ~MDUEvent() { } + + + virtual void process(); +}; + + +#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__ diff --git a/src/cpu/o3/sparc/thread_context.cc b/src/cpu/inorder/resources/resource_list.hh index d85aff502..cbe2ad8c3 100755..100644 --- a/src/cpu/o3/sparc/thread_context.cc +++ b/src/cpu/inorder/resources/resource_list.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,11 +25,23 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black + * Authors: Korey Sewell + * */ -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" +#ifndef CPU_INORDER_RESOURCE_LIST_HH +#define CPU_INORDER_RESOURCE_LIST_HH -template class O3ThreadContext<SparcSimpleImpl>; +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/resources/execution_unit.hh" +#include "cpu/inorder/resources/use_def.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/resources/decode_unit.hh" +#include "cpu/inorder/resources/graduation_unit.hh" +#include "cpu/inorder/resources/tlb_unit.hh" +#include "cpu/inorder/resources/fetch_seq_unit.hh" +#include "cpu/inorder/resources/branch_predictor.hh" +#include "cpu/inorder/resources/agen_unit.hh" +#include "cpu/inorder/resources/mult_div_unit.hh" +#endif diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc new file mode 100644 index 000000000..8f8ba144e --- /dev/null +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/tlb_unit.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +TLBUnit::TLBUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : InstBuffer(res_name, res_id, res_width, res_latency, _cpu, params) +{ + for (int i=0; i < MaxThreads; i++) { + tlbBlocked[i] = false; + } +} + +void +TLBUnit::init() +{ + resourceEvent = new TLBUnitEvent[width]; + + initSlots(); +} + +int +TLBUnit::getSlot(DynInstPtr inst) +{ + if (tlbBlocked[inst->threadNumber]) { + return -1; + } else { + return Resource::getSlot(inst); + } +} + +ResourceRequest* +TLBUnit::getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd) +{ + return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num, + cmd); +} + +void +TLBUnit::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + TLBUnitRequest* tlb_req = dynamic_cast<TLBUnitRequest*>(reqMap[slot_idx]); + assert(tlb_req); + + DynInstPtr inst = tlb_req->inst; + int tid, seq_num, stage_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + stage_num = tlb_req->getStageNum(); + + tlb_req->fault = NoFault; + + switch (tlb_req->cmd) + { + case FetchLookup: + { + tlb_req->fault = + this->cpu->itb->translateAtomic(tlb_req->memReq, + cpu->thread[tid]->getTC()); + + if (tlb_req->fault != NoFault) { + DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), + tlb_req->memReq->getVaddr(), seq_num); + //insert(inst); + cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid); + tlbBlocked[tid] = true; + scheduleEvent(slot_idx, 1); + + // @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault + // Let CPU handle the fault + cpu->trap(tlb_req->fault, tid); + } else { + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " + "to phys. addr:%08p.\n", tid, seq_num, + tlb_req->memReq->getVaddr(), + tlb_req->memReq->getPaddr()); + tlb_req->done(); + } + } + break; + + case DataLookup: + { + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n", + tid, seq_num, tlb_req->memReq->getVaddr()); + + tlb_req->fault = + this->cpu->itb->translateAtomic(tlb_req->memReq, + cpu->thread[tid]->getTC()); + + if (tlb_req->fault != NoFault) { + DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), + tlb_req->memReq->getVaddr(), seq_num); + //insert(inst); + cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid); + tlbBlocked[tid] = true; + scheduleEvent(slot_idx, 1); + + // Let CPU handle the fault + cpu->trap(tlb_req->fault, tid); + } else { + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " + "to phys. addr:%08p.\n", tid, seq_num, + tlb_req->memReq->getVaddr(), + tlb_req->memReq->getPaddr()); + tlb_req->done(); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +TLBUnitEvent::TLBUnitEvent() + : ResourceEvent() +{ } + +void +TLBUnitEvent::process() +{ + DynInstPtr inst = resource->reqMap[slotIdx]->inst; + int stage_num = resource->reqMap[slotIdx]->getStageNum(); + int tid = inst->threadNumber; + + DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n", + inst->seqNum); + + TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource); + assert(tlb_res); + + tlb_res->tlbBlocked[tid] = false; + + tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid); + + // Effectively NOP the instruction but still allow it + // to commit + //while (!inst->resSched.empty() && + // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) { + //inst->resSched.pop(); + //} +} diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh new file mode 100644 index 000000000..c7fee6030 --- /dev/null +++ b/src/cpu/inorder/resources/tlb_unit.hh @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_TLB_UNIT_HH__ +#define __CPU_INORDER_TLB_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class TLBUnit : public InstBuffer { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum TLBCommand { + FetchLookup, + DataLookup + }; + + public: + TLBUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~TLBUnit() {} + + void init(); + + int getSlot(DynInstPtr inst); + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + virtual void execute(int slot_num); + + bool tlbBlocked[ThePipeline::MaxThreads]; + + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list<DynInstPtr> instList; + + /** @todo: Add Resource Stats Here */ + +}; + +class TLBUnitEvent : public ResourceEvent { + public: + /** Constructs a resource event. */ + TLBUnitEvent(); + virtual ~TLBUnitEvent() {} + + /** Processes a resource event. */ + virtual void process(); +}; + +class TLBUnitRequest : public ResourceRequest { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, + unsigned _cmd) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd) + { + Addr aligned_addr; + int req_size; + unsigned flags; + + if (_cmd == TLBUnit::FetchLookup) { + aligned_addr = inst->getMemAddr(); + req_size = sizeof(MachInst); + flags = 0; + } else { + aligned_addr = inst->getMemAddr();; + req_size = inst->getMemAccSize(); + flags = inst->getMemFlags(); + } + + // @TODO: Add Vaddr & Paddr functions + inst->memReq = new Request(inst->readTid(), aligned_addr, req_size, + flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid()); + + memReq = inst->memReq; + } + + RequestPtr memReq; +}; + + +#endif //__CPU_INORDER_TLB_UNIT_HH__ diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc new file mode 100644 index 000000000..a9281a18c --- /dev/null +++ b/src/cpu/inorder/resources/use_def.cc @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/use_def.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + maxSeqNum((InstSeqNum)-1) +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; + nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; + + outReadSeqNum[tid] = maxSeqNum; + outWriteSeqNum[tid] = maxSeqNum; + + regDepMap[tid] = &cpu->archRegDepMap[tid]; + } +} + +ResReqPtr +UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd, + inst->resSched.top()->idx); +} + + +ResReqPtr +UseDefUnit::findRequest(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>((*map_it).second); + assert(ud_req); + + if (ud_req && + ud_req->getInst() == inst && + ud_req->cmd == inst->resSched.top()->cmd && + ud_req->useDefIdx == inst->resSched.top()->idx) { + return ud_req; + } + map_it++; + } + + return NULL; +} + +void +UseDefUnit::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqMap[slot_idx]); + assert(ud_req); + + DynInstPtr inst = ud_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + int ud_idx = ud_req->useDefIdx; + + // If there is a non-speculative instruction + // in the pipeline then stall instructions here + if (*nonSpecInstActive[tid] == true && + seq_num > *nonSpecSeqNum[tid]) { + DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] cannot execute because there is " + "non-speculative instruction [sn:%i] has not graduated.\n", + tid, seq_num, *nonSpecSeqNum[tid]); + return; + } else if (inst->isNonSpeculative()) { + *nonSpecInstActive[tid] = true; + *nonSpecSeqNum[tid] = seq_num; + } + + switch (ud_req->cmd) + { + case ReadSrcReg: + { + int reg_idx = inst->_srcRegIdx[ud_idx]; + + DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to read source register idx %i.\n", + tid, ud_idx); + + // Ask register dependency map if it is OK to read from Arch. Reg. File + if (regDepMap[tid]->canRead(reg_idx, inst)) { + // Read From Register File + if (inst->seqNum <= outReadSeqNum[tid]) { + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Int Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, + cpu->readIntReg(reg_idx,inst->readTid())); + } else if (reg_idx <= Ctrl_Base_DepTag) { + reg_idx -= FP_Base_DepTag; + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Float Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now + cpu->readFloatRegBits(reg_idx, inst->readTid())); + } else { + reg_idx -= Ctrl_Base_DepTag; + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Misc Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, + cpu->readMiscReg(reg_idx, inst->readTid())); + } + + outReadSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum[tid]); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n", + tid, outReadSeqNum[tid]); + } + + } else { + DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx, ud_idx, inst); + + if (forward_inst) { + + if (inst->seqNum <= outReadSeqNum[tid]) { + int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx); + + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readIntResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); + } else if (reg_idx <= Ctrl_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readFloatResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx)); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readIntResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); + } + + outReadSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum[tid]); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n", + tid, outReadSeqNum[tid]); + } + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Source register idx: %i is not ready to read.\n", + tid, reg_idx); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n", + tid, reg_idx); + outReadSeqNum[tid] = inst->seqNum; + } + } + } + break; + + case WriteDestReg: + { + int reg_idx = inst->_destRegIdx[ud_idx]; + + if (regDepMap[tid]->canWrite(reg_idx, inst)) { + DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to write to Register File.\n", + tid); + + if (inst->seqNum <= outReadSeqNum[tid]) { + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Writing 0x%x to register idx %i.\n", + tid, inst->readIntResult(ud_idx), reg_idx); + + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + cpu->setIntReg(reg_idx, + inst->readIntResult(ud_idx), + inst->readTid()); + } else if(reg_idx <= Ctrl_Base_DepTag) { + + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + reg_idx -= FP_Base_DepTag; + + cpu->setFloatReg(reg_idx, // Check for FloatRegBits Here + inst->readFloatResult(ud_idx), + inst->readTid()); + } else { + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + reg_idx -= Ctrl_Base_DepTag; + cpu->setMiscReg(reg_idx, + inst->readIntResult(ud_idx), + inst->readTid()); + } + + outWriteSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n", + tid, outReadSeqNum); + } + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Dest. register idx: %i is not ready to write.\n", + tid, reg_idx); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n", + tid, reg_idx); + outWriteSeqNum[tid] = inst->seqNum; + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + +} + +void +UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderUseDef, "[tid:%i]: Updating Due To Squash After [sn:%i].\n", + tid, squash_seq_num); + + std::vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(InOrderUseDef, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + regDepMap[tid]->remove(req_ptr->getInst()); + + int req_slot_num = req_ptr->getSlot(); + + if (latency > 0) + unscheduleEvent(req_slot_num); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } + + if (outReadSeqNum[tid] >= squash_seq_num) { + DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid); + outReadSeqNum[tid] = maxSeqNum; + } else if (outReadSeqNum[tid] != maxSeqNum) { + DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n", + tid, outReadSeqNum[tid]); + } + + if (outWriteSeqNum[tid] >= squash_seq_num) { + DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid); + outWriteSeqNum[tid] = maxSeqNum; + } else if (outWriteSeqNum[tid] != maxSeqNum) { + DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n", + tid, outWriteSeqNum[tid]); + } +} diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh new file mode 100644 index 000000000..238591117 --- /dev/null +++ b/src/cpu/inorder/resources/use_def.hh @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_USE_DEF_UNIT_HH__ +#define __CPU_INORDER_USE_DEF_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/func_unit.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/reg_dep_map.hh" + +class UseDefUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + ReadSrcReg, + WriteDestReg + }; + + public: + UseDefUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~UseDefUnit() {} + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + virtual ResReqPtr findRequest(DynInstPtr inst); + + virtual void execute(int slot_num); + + virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + const InstSeqNum maxSeqNum; + + protected: + RegDepMap *regDepMap[ThePipeline::MaxThreads]; + + /** Outstanding Seq. Num. Trying to Read from Register File */ + InstSeqNum outReadSeqNum[ThePipeline::MaxThreads]; + + InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads]; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ + + public: + class UseDefRequest : public ResourceRequest { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd, int use_def_idx) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd), + useDefIdx(use_def_idx) + { } + + int useDefIdx; + }; +}; + +#endif //__CPU_INORDER_USE_DEF_UNIT_HH__ diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc new file mode 100644 index 000000000..13f8ecdad --- /dev/null +++ b/src/cpu/inorder/thread_context.cc @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#include "arch/isa_traits.hh" +#include "cpu/exetrace.hh" +#include "cpu/inorder/thread_context.hh" + +using namespace TheISA; + +void +InOrderThreadContext::takeOverFrom(ThreadContext *old_context) +{ + // some things should already be set up + assert(getProcessPtr() == old_context->getProcessPtr()); + + // copy over functional state + setStatus(old_context->status()); + copyArchRegs(old_context); + + thread->funcExeInst = old_context->readFuncExeInst(); + old_context->setStatus(ThreadContext::Unallocated); + thread->inSyscall = false; + thread->trapPending = false; +} + +void +InOrderThreadContext::activate(int delay) +{ + DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Active) + return; + + thread->setStatus(ThreadContext::Active); + + cpu->activateContext(thread->readTid(), delay); +} + + +void +InOrderThreadContext::suspend(int delay) +{ + DPRINTF(InOrderCPU, "Calling suspend on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Suspended) + return; + + thread->setStatus(ThreadContext::Suspended); + cpu->suspendContext(thread->readTid(), delay); +} + +void +InOrderThreadContext::deallocate(int delay) +{ + DPRINTF(InOrderCPU, "Calling deallocate on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Unallocated) + return; + + thread->setStatus(ThreadContext::Unallocated); + cpu->deallocateContext(thread->readTid(), delay); +} + +void +InOrderThreadContext::halt(int delay) +{ + DPRINTF(InOrderCPU, "Calling halt on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Halted) + return; + + thread->setStatus(ThreadContext::Halted); + cpu->haltContext(thread->readTid(), delay); +} + + +void +InOrderThreadContext::regStats(const std::string &name) +{ +#if FULL_SYSTEM + thread->kernelStats = new Kernel::Statistics(cpu->system); + thread->kernelStats->regStats(name + ".kern"); +#endif + ; +} + + +void +InOrderThreadContext::serialize(std::ostream &os) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->serialize(os); +#endif + ; +} + + +void +InOrderThreadContext::unserialize(Checkpoint *cp, const std::string §ion) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->unserialize(cp, section); +#endif + ; +} + +TheISA::MachInst +InOrderThreadContext:: getInst() +{ + return thread->getInst(); +} + + +void +InOrderThreadContext::copyArchRegs(ThreadContext *src_tc) +{ + TheISA::copyRegs(src_tc, this); +} + + +void +InOrderThreadContext::clearArchRegs() +{} + + +uint64_t +InOrderThreadContext::readIntReg(int reg_idx) +{ + return cpu->readIntReg(reg_idx, thread->readTid()); +} + +FloatReg +InOrderThreadContext::readFloatReg(int reg_idx, int width) +{ + return cpu->readFloatReg(reg_idx, thread->readTid(), width); +} + +FloatReg +InOrderThreadContext::readFloatReg(int reg_idx) +{ + return cpu->readFloatReg(reg_idx, thread->readTid()); +} + +FloatRegBits +InOrderThreadContext::readFloatRegBits(int reg_idx, int width) +{ + return cpu->readFloatRegBits(reg_idx, thread->readTid(), width); +} + +FloatRegBits +InOrderThreadContext::readFloatRegBits(int reg_idx) +{ + return cpu->readFloatRegBits(reg_idx, thread->readTid()); +} + +uint64_t +InOrderThreadContext::readRegOtherThread(int reg_idx, unsigned tid) +{ + return cpu->readRegOtherThread(reg_idx, tid); +} + +void +InOrderThreadContext::setIntReg(int reg_idx, uint64_t val) +{ + cpu->setIntReg(reg_idx, val, thread->readTid()); +} + +void +InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width) +{ + cpu->setFloatReg(reg_idx, val, thread->readTid(), width); +} + +void +InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val) +{ + cpu->setFloatReg(reg_idx, val, thread->readTid()); +} + +void +InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val, + int width) +{ + cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width); +} + +void +InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + cpu->setFloatRegBits(reg_idx, val, thread->readTid()); +} + +void +InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid) +{ + cpu->setRegOtherThread(misc_reg, val, tid); +} + +void +InOrderThreadContext::setPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting PC to %08p\n", val); + cpu->setPC(val, thread->readTid()); +} + +void +InOrderThreadContext::setNextPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val); + cpu->setNextPC(val, thread->readTid()); +} + +void +InOrderThreadContext::setNextNPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val); + cpu->setNextNPC(val, thread->readTid()); +} + +void +InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val) +{ + cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); +} + +void +InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val) +{ + cpu->setMiscReg(misc_reg, val, thread->readTid()); +} diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh new file mode 100644 index 000000000..2fb2ed85f --- /dev/null +++ b/src/cpu/inorder/thread_context.hh @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_THREAD_CONTEXT_HH__ +#define __CPU_INORDER_THREAD_CONTEXT_HH__ + +#include "cpu/exetrace.hh" +#include "cpu/thread_context.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/cpu.hh" + +class TranslatingPort; + +/** + * Derived ThreadContext class for use with the InOrderCPU. It + * provides the interface for any external objects to access a + * single thread's state and some general CPU state. Any time + * external objects try to update state through this interface, + * the CPU will create an event to squash all in-flight + * instructions in order to ensure state is maintained correctly. + * It must be defined specifically for the InOrderCPU because + * not all architectural state is located within the O3ThreadState + * (such as the commit PC, and registers), and specific actions + * must be taken when using this interface (such as squashing all + * in-flight instructions when doing a write to this interface). + */ +class InOrderThreadContext : public ThreadContext +{ + public: + InOrderThreadContext() { } + + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + /** Pointer to the thread state that this TC corrseponds to. */ + InOrderThreadState *thread; + + + /** Returns a pointer to the ITB. */ + TheISA::ITB *getITBPtr() { return cpu->itb; } + + /** Returns a pointer to the DTB. */ + TheISA::DTB *getDTBPtr() { return cpu->dtb; } + + System *getSystemPtr() { return cpu->system; } + + /** Returns a pointer to this CPU. */ + virtual BaseCPU *getCpuPtr() { return cpu; } + + /** Returns a pointer to this CPU. */ + virtual std::string getCpuName() { return cpu->name(); } + + /** Reads this CPU's ID. */ + virtual int cpuId() { return cpu->cpuId(); } + + virtual int contextId() { return thread->contextId(); } + + virtual void setContextId(int id) { thread->setContextId(id); } + + /** Returns this thread's ID number. */ + virtual int threadId() { return thread->threadId(); } + virtual void setThreadId(int id) { return thread->setThreadId(id); } + + virtual uint64_t readMicroPC() + { return 0; } + + virtual void setMicroPC(uint64_t val) { }; + + virtual uint64_t readNextMicroPC() + { return 0; } + + virtual void setNextMicroPC(uint64_t val) { }; + + virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } + + /** Returns a pointer to this thread's process. */ + virtual Process *getProcessPtr() { return thread->getProcessPtr(); } + + /** Returns this thread's status. */ + virtual Status status() const { return thread->status(); } + + /** Sets this thread's 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(int delay = 0); + + /** Set the status to Unallocated. */ + virtual void deallocate(int delay = 1); + + /** Set the status to Halted. */ + virtual void halt(int delay = 0); + + /** Takes over execution of a thread from another CPU. */ + virtual void takeOverFrom(ThreadContext *old_context); + + /** Registers statistics associated with this TC. */ + virtual void regStats(const std::string &name); + + /** Serializes state. */ + virtual void serialize(std::ostream &os); + + /** Unserializes state. */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** Returns this thread's ID number. */ + virtual int getThreadNum() { return thread->readTid(); } + + /** Returns the instruction this thread is currently committing. + * Only used when an instruction faults. + */ + virtual TheISA::MachInst getInst(); + + /** Copies the architectural registers from another TC into this TC. */ + virtual void copyArchRegs(ThreadContext *src_tc); + + /** Resets all architectural registers to 0. */ + virtual void clearArchRegs(); + + /** Reads an integer register. */ + virtual uint64_t readIntReg(int reg_idx); + + virtual FloatReg readFloatReg(int reg_idx, int width); + + virtual FloatReg readFloatReg(int reg_idx); + + virtual FloatRegBits readFloatRegBits(int reg_idx, int width); + + virtual FloatRegBits readFloatRegBits(int reg_idx); + + virtual uint64_t readRegOtherThread(int misc_reg, unsigned tid); + + /** Sets an integer register to a value. */ + virtual void setIntReg(int reg_idx, uint64_t val); + + virtual void setFloatReg(int reg_idx, FloatReg val, int width); + + virtual void setFloatReg(int reg_idx, FloatReg val); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val); + + virtual void setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid); + + /** Reads this thread's PC. */ + virtual uint64_t readPC() + { return cpu->readPC(thread->readTid()); } + + /** Sets this thread's PC. */ + virtual void setPC(uint64_t val); + + /** Reads this thread's next PC. */ + virtual uint64_t readNextPC() + { return cpu->readNextPC(thread->readTid()); } + + /** Sets this thread's next PC. */ + virtual void setNextPC(uint64_t val); + + virtual uint64_t readNextNPC() + { return cpu->readNextNPC(thread->readTid()); } + + virtual void setNextNPC(uint64_t val); + + /** Reads a miscellaneous register. */ + virtual MiscReg readMiscRegNoEffect(int misc_reg) + { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); } + + /** Reads a misc. register, including any side-effects the + * read might have as defined by the architecture. */ + virtual MiscReg readMiscReg(int misc_reg) + { return cpu->readMiscReg(misc_reg, thread->readTid()); } + + /** Sets a misc. register. */ + virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val); + + /** Sets a misc. register, including any side-effects the + * write might have as defined by the architecture. */ + virtual void setMiscReg(int misc_reg, const MiscReg &val); + + virtual void activateContext(int delay) + { cpu->activateContext(thread->readTid(), delay); } + + virtual void deallocateContext() + { cpu->deallocateContext(thread->readTid()); } + + /** Returns the number of consecutive store conditional failures. */ + // @todo: Figure out where these store cond failures should go. + virtual unsigned readStCondFailures() + { return thread->storeCondFailures; } + + /** Sets the number of consecutive store conditional failures. */ + virtual void setStCondFailures(unsigned sc_failures) + { thread->storeCondFailures = sc_failures; } + + // 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. + /** Checks if the thread is misspeculating. Because it is + * very difficult to determine if the thread is + * misspeculating, this is set as false. */ + virtual bool misspeculating() { return false; } + + /** Executes a syscall in SE mode. */ + virtual void syscall(int64_t callnum) + { return cpu->syscall(callnum, thread->readTid()); } + + /** Reads the funcExeInst counter. */ + virtual Counter readFuncExeInst() { return thread->funcExeInst; } + + virtual void changeRegFileContext(unsigned param, + unsigned val) + { panic("Not supported!"); } + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system (for now + // this single cpu) + if (this->cpu->numActiveThreads() - 1 > 0) + return 0; // don't exit simulation + else + return 1; // exit simulation + } + + virtual void setThreadRescheduleCondition(uint64_t cond) + { + this->deallocate(); + + this->setStatus(ThreadContext::Suspended); + + activateContext(cond); + } +}; + +#endif diff --git a/src/cpu/inorder/thread_state.hh b/src/cpu/inorder/thread_state.hh new file mode 100644 index 000000000..eb4fe40b2 --- /dev/null +++ b/src/cpu/inorder/thread_state.hh @@ -0,0 +1,90 @@ +/* + * 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. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_INORDER_THREAD_STATE_HH__ +#define __CPU_INORDER_THREAD_STATE_HH__ + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" +#include "cpu/thread_state.hh" + +class Event; +class FunctionalMemory; +class Process; +class InOrderCPU; + +/** + * Class that has various thread state, such as the status, the + * current instruction being processed, whether or not the thread has + * a trap pending or is being externally updated, the ThreadContext + * pointer, etc. It also handles anything related to a specific + * thread's process, such as syscalls and checking valid addresses. + */ +class InOrderThreadState : public ThreadState { + typedef ThreadContext::Status Status; + + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Whether or not the thread is currently in syscall mode, and + * thus able to be externally updated without squashing. + */ + bool inSyscall; + + /** Whether or not the thread is currently waiting on a trap, and + * thus able to be externally updated without squashing. + */ + bool trapPending; + + + InOrderThreadState(InOrderCPU *_cpu, int _thread_num, Process *_process, int _asid) + : ThreadState(reinterpret_cast<BaseCPU*>(_cpu), 0/*_thread_num*/, _process, 0/*_asid*/), + cpu(_cpu), inSyscall(0), trapPending(0) + { } + + /** Handles the syscall. */ + void syscall(int64_t callnum) { process->syscall(callnum, tc); } + + /** Pointer to the ThreadContext of this thread. */ + ThreadContext *tc; + + /** Returns a pointer to the TC of this thread. */ + ThreadContext *getTC() { return tc; } + + int readTid() { return 0; } + + /** Pointer to the last graduated instruction in the thread */ + //DynInstPtr lastGradInst; +}; + +#endif // __CPU_INORDER_THREAD_STATE_HH__ diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh index 5d5bcda8e..e34658b58 100644 --- a/src/cpu/inteltrace.hh +++ b/src/cpu/inteltrace.hh @@ -47,8 +47,10 @@ class IntelTraceRecord : public InstRecord { public: IntelTraceRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } @@ -64,7 +66,8 @@ class IntelTrace : public InstTracer IntelTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (!IsOn(ExecEnable)) return NULL; @@ -76,7 +79,7 @@ class IntelTrace : public InstTracer return NULL; return new IntelTraceRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc index c3a11ad91..de7f9245e 100644 --- a/src/cpu/intr_control.cc +++ b/src/cpu/intr_control.cc @@ -50,7 +50,7 @@ IntrControl::post(int cpu_id, int int_num, int index) DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id); std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); - cpu->post_interrupt(int_num, index); + cpu->postInterrupt(int_num, index); } void @@ -59,7 +59,7 @@ IntrControl::clear(int cpu_id, int int_num, int index) DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id); std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); - cpu->clear_interrupt(int_num, index); + cpu->clearInterrupt(int_num, index); } IntrControl * diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh index 97193ff1a..9962063e4 100644 --- a/src/cpu/legiontrace.hh +++ b/src/cpu/legiontrace.hh @@ -46,8 +46,10 @@ class LegionTraceRecord : public InstRecord { public: LegionTraceRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } @@ -63,13 +65,14 @@ class LegionTrace : public InstTracer LegionTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (tc->misspeculating()) return NULL; return new LegionTraceRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc index 42889163a..3c57f85b7 100644 --- a/src/cpu/memtest/memtest.cc +++ b/src/cpu/memtest/memtest.cc @@ -152,7 +152,7 @@ MemTest::MemTest(const Params *p) // set up counters noResponseCycles = 0; numReads = 0; - tickEvent.schedule(0); + schedule(tickEvent, 0); id = TESTER_ALLOCATOR++; @@ -262,7 +262,7 @@ void MemTest::tick() { if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + ticks(1)); + schedule(tickEvent, curTick + ticks(1)); if (++noResponseCycles >= 500000) { cerr << name() << ": deadlocked at cycle " << curTick << endl; @@ -279,7 +279,7 @@ MemTest::tick() unsigned base = random() % 2; uint64_t data = random(); unsigned access_size = random() % 4; - unsigned cacheable = random() % 100; + bool uncacheable = (random() % 100) < percentUncacheable; //If we aren't doing copies, use id as offset, and do a false sharing //mem tester @@ -290,17 +290,16 @@ MemTest::tick() access_size = 0; Request *req = new Request(); - uint32_t flags = 0; + Request::Flags flags; Addr paddr; - if (cacheable < percentUncacheable) { - flags |= UNCACHEABLE; + if (uncacheable) { + flags.set(Request::UNCACHEABLE); paddr = uncacheAddr + offset; } else { paddr = ((base) ? baseAddr1 : baseAddr2) + offset; } - bool probe = (random() % 100 < percentFunctional) && !(flags & UNCACHEABLE); - //bool probe = false; + bool probe = (random() % 100 < percentFunctional) && !uncacheable; paddr &= ~((1 << access_size) - 1); req->setPhys(paddr, 1 << access_size, flags); diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index ac2d0a058..907659f69 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -35,6 +35,7 @@ #include <set> #include "base/statistics.hh" +#include "base/fast_alloc.hh" #include "params/MemTest.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" @@ -73,10 +74,10 @@ class MemTest : public MemObject { private: MemTest *cpu; + public: - TickEvent(MemTest *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {} - void process() {cpu->tick();} + TickEvent(MemTest *c) : Event(CPU_Tick_Pri), cpu(c) {} + void process() { cpu->tick(); } virtual const char *description() const { return "MemTest tick"; } }; @@ -116,7 +117,7 @@ class MemTest : public MemObject bool snoopRangeSent; - class MemTestSenderState : public Packet::SenderState + class MemTestSenderState : public Packet::SenderState, public FastAlloc { public: /** Constructor. */ @@ -132,10 +133,10 @@ class MemTest : public MemObject bool accessRetry; - unsigned size; // size of testing memory region + unsigned size; // size of testing memory region - unsigned percentReads; // target percentage of read accesses - unsigned percentFunctional; // target percentage of functional accesses + unsigned percentReads; // target percentage of read accesses + unsigned percentFunctional; // target percentage of functional accesses unsigned percentUncacheable; int id; @@ -153,12 +154,12 @@ class MemTest : public MemObject Addr traceBlockAddr; - Addr baseAddr1; // fix this to option - Addr baseAddr2; // fix this to option + 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 progressInterval; // frequency of progress reports + Tick nextProgressMessage; // access # for next progress report unsigned percentSourceUnaligned; unsigned percentDestUnaligned; @@ -170,9 +171,9 @@ class MemTest : public MemObject bool atomic; - Stats::Scalar<> numReadsStat; - Stats::Scalar<> numWritesStat; - Stats::Scalar<> numCopiesStat; + Stats::Scalar numReadsStat; + Stats::Scalar numWritesStat; + Stats::Scalar numCopiesStat; // called by MemCompleteEvent::process() void completeRequest(PacketPtr pkt); diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc index 7152602fe..c23a9e4ad 100644 --- a/src/cpu/nativetrace.cc +++ b/src/cpu/nativetrace.cc @@ -50,8 +50,12 @@ using namespace TheISA; namespace Trace { -NativeTrace::NativeTrace(const Params *p) : InstTracer(p) +NativeTrace::NativeTrace(const Params *p) + : InstTracer(p) { + if (ListenSocket::allDisabled()) + fatal("All listeners are disabled!"); + int port = 8000; while(!native_listener.listen(port, true)) { diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh index ab038c4c3..9e912d92f 100644 --- a/src/cpu/nativetrace.hh +++ b/src/cpu/nativetrace.hh @@ -54,8 +54,11 @@ class NativeTraceRecord : public InstRecord public: NativeTraceRecord(NativeTrace * _parent, Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc), + parent(_parent) { } @@ -192,13 +195,14 @@ class NativeTrace : public InstTracer NativeTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (tc->misspeculating()) return NULL; return new NativeTraceRecord(this, when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } void diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py index f0284b2cf..56e537ad2 100644 --- a/src/cpu/o3/O3CPU.py +++ b/src/cpu/o3/O3CPU.py @@ -38,10 +38,7 @@ if build_env['USE_CHECKER']: class DerivO3CPU(BaseCPU): type = 'DerivO3CPU' activity = Param.Unsigned(0, "Initial count") - numThreads = Param.Unsigned(1, "number of HW thread contexts") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") if build_env['USE_CHECKER']: if not build_env['FULL_SYSTEM']: checker = Param.BaseCPU(O3Checker(workload=Parent.workload, @@ -134,9 +131,6 @@ class DerivO3CPU(BaseCPU): instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - smtNumFetchingThreads = Param.Unsigned(1, "SMT Number of Fetching Threads") smtFetchPolicy = Param.String('SingleThread', "SMT Fetch policy") smtLSQPolicy = Param.String('Partitioned', "SMT LSQ Sharing Policy") diff --git a/src/cpu/o3/O3Checker.py b/src/cpu/o3/O3Checker.py index 43a71d67b..edc6dc9b6 100644 --- a/src/cpu/o3/O3Checker.py +++ b/src/cpu/o3/O3Checker.py @@ -39,5 +39,3 @@ class O3Checker(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript index 2de106d8b..f05986bf5 100755 --- a/src/cpu/o3/SConscript +++ b/src/cpu/o3/SConscript @@ -51,7 +51,9 @@ if 'O3CPU' in env['CPU_MODELS']: Source('bpred_unit.cc') Source('commit.cc') Source('cpu.cc') + Source('cpu_builder.cc') Source('decode.cc') + Source('dyn_inst.cc') Source('fetch.cc') Source('free_list.cc') Source('fu_pool.cc') @@ -65,6 +67,7 @@ if 'O3CPU' in env['CPU_MODELS']: Source('rob.cc') Source('scoreboard.cc') Source('store_set.cc') + Source('thread_context.cc') TraceFlag('FreeList') TraceFlag('LSQ') @@ -81,24 +84,6 @@ if 'O3CPU' in env['CPU_MODELS']: 'IQ', 'ROB', 'FreeList', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'O3CPU', 'Activity', 'Scoreboard', 'Writeback' ]) - if env['TARGET_ISA'] == 'alpha': - Source('alpha/cpu.cc') - Source('alpha/cpu_builder.cc') - Source('alpha/dyn_inst.cc') - Source('alpha/thread_context.cc') - elif env['TARGET_ISA'] == 'mips': - Source('mips/cpu.cc') - Source('mips/cpu_builder.cc') - Source('mips/dyn_inst.cc') - Source('mips/thread_context.cc') - elif env['TARGET_ISA'] == 'sparc': - Source('sparc/cpu.cc') - Source('sparc/cpu_builder.cc') - Source('sparc/dyn_inst.cc') - Source('sparc/thread_context.cc') - else: - sys.exit('O3 CPU does not support the \'%s\' ISA' % env['TARGET_ISA']) - if env['USE_CHECKER']: SimObject('O3Checker.py') Source('checker_builder.cc') diff --git a/src/cpu/o3/alpha/cpu.cc b/src/cpu/o3/alpha/cpu.cc deleted file mode 100644 index ed10b2fd1..000000000 --- a/src/cpu/o3/alpha/cpu.cc +++ /dev/null @@ -1,38 +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. - * - * Authors: Kevin Lim - */ - -#include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/alpha/cpu_impl.hh" -#include "cpu/o3/alpha/dyn_inst.hh" - -// Force instantiation of AlphaO3CPU 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 AlphaO3CPU<AlphaSimpleImpl>; diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh deleted file mode 100644 index ebc4e7b23..000000000 --- a/src/cpu/o3/alpha/cpu.hh +++ /dev/null @@ -1,149 +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. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_CPU_HH__ -#define __CPU_O3_ALPHA_CPU_HH__ - -#include "arch/regfile.hh" -#include "arch/types.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * AlphaO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template <class Impl> -class AlphaO3CPU : public FullO3CPU<Impl> -{ - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaO3CPU with the given parameters. */ - AlphaO3CPU(Params *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - -#if FULL_SYSTEM - /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - - bool simPalCheck(int palFunc, unsigned tid); - - /** Returns the Fault for any valid interrupt. */ - Fault getInterrupts(); - - /** Processes any an interrupt fault. */ - void processInterrupts(Fault interrupt); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_ALPHA_CPU_HH__ diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc deleted file mode 100644 index f569c048b..000000000 --- a/src/cpu/o3/alpha/cpu_builder.cc +++ /dev/null @@ -1,199 +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. - * - * Authors: Kevin Lim - */ - -#include <string> - -#include "config/use_checker.hh" -#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 "params/DerivO3CPU.hh" - -class DerivO3CPU : public AlphaO3CPU<AlphaSimpleImpl> -{ - public: - DerivO3CPU(AlphaSimpleParams *p) - : AlphaO3CPU<AlphaSimpleImpl>(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ - DerivO3CPU *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 >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - AlphaSimpleParams *params = new AlphaSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->itb = itb; - params->dtb = dtb; - - params->system = system; -#if FULL_SYSTEM - params->profile = profile; - - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else - params->workload = workload; -#endif // FULL_SYSTEM - -#if USE_CHECKER - params->checker = checker; -#endif - - 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->progress_interval = progress_interval; - - // - // Caches - // - 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->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - 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; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; - else - 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 DerivO3CPU(params); - - return cpu; -} diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh deleted file mode 100644 index 7f8f0547b..000000000 --- a/src/cpu/o3/alpha/cpu_impl.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. - * - * Authors: Kevin Lim - */ - -#include "config/use_checker.hh" - -#include "arch/alpha/faults.hh" -#include "arch/alpha/isa_traits.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.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/alpha/thread_context.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 "arch/kernel_stats.hh" -#include "cpu/quiesce_event.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#endif - -template <class Impl> -AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) : FullO3CPU<Impl>(this, params) -{ - DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - // SMT is not supported in FS mode yet. - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0); - this->thread[i]->setStatus(ThreadContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread 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 - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - AlphaTC<Impl> *alpha_tc = - new AlphaTC<Impl>; - - tc = alpha_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext<AlphaTC<Impl> >( - alpha_tc, this->checker); - } -#endif - - alpha_tc->cpu = this; - alpha_tc->thread = this->thread[i]; - -#if FULL_SYSTEM - // Setup quiesce event. - this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); -#endif - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -AlphaO3CPU<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(); -} - - -template <class Impl> -TheISA::MiscReg -AlphaO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template <class Impl> -TheISA::MiscReg -AlphaO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, - unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setMiscReg(int misc_reg, - const TheISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -AlphaO3CPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - -template <class Impl> -Fault -AlphaO3CPU<Impl>::hwrei(unsigned tid) -{ - // Need to clear the lock flag upon returning from an interrupt. - this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); - - this->thread[tid]->kernelStats->hwrei(); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -bool -AlphaO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->threadContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - exitSimLoop("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } - - return true; -} - -template <class Impl> -Fault -AlphaO3CPU<Impl>::getInterrupts() -{ - // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::processInterrupts(Fault interrupt) -{ - // 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. - - assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); - - DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); - this->trap(interrupt, 0); -} - -#endif // FULL_SYSTEM - -template <class Impl> -void -AlphaO3CPU<Impl>::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template <class Impl> -void -AlphaO3CPU<Impl>::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[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(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -AlphaO3CPU<Impl>::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - return this->readArchIntReg(AlphaISA::ArgumentReg[i], tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - this->setArchIntReg(AlphaISA::ArgumentReg[i], val, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/alpha/dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc deleted file mode 100644 index 97d2f3d08..000000000 --- a/src/cpu/o3/alpha/dyn_inst.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. - * - * Authors: Kevin Lim - */ - -#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/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh deleted file mode 100644 index a6fb7b885..000000000 --- a/src/cpu/o3/alpha/dyn_inst.hh +++ /dev/null @@ -1,277 +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. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ -#define __CPU_O3_ALPHA_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha/cpu.hh" -#include "cpu/o3/alpha/impl.hh" - -class Packet; - -/** - * 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::O3CPU O3CPU; - - /** 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; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - /** 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(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *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(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - MiscReg readMiscRegNoEffect(int misc_reg) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const MiscReg &val) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand(const StaticInst *si, int idx, - const MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(int64_t callnum); -#endif - - 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 readIntRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(this->_srcRegIdx[idx]); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, - int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, - int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - 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/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh deleted file mode 100644 index b928ae654..000000000 --- a/src/cpu/o3/alpha/impl.hh +++ /dev/null @@ -1,92 +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. - * - * Authors: Kevin Lim - */ - -#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 AlphaO3CPU; - -/** 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 O3CPU, 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 O3CPU type to be used. */ - typedef AlphaO3CPU<AlphaSimpleImpl> O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - /** The Params to be passed to each stage. */ - typedef AlphaSimpleParams Params; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef AlphaSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_ALPHA_IMPL_HH__ diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc index 0979c5c8f..510109d8a 100644 --- a/src/cpu/o3/base_dyn_inst.cc +++ b/src/cpu/o3/base_dyn_inst.cc @@ -29,11 +29,8 @@ */ #include "cpu/base_dyn_inst_impl.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/isa_specific.hh" // Explicit instantiation template class BaseDynInst<O3CPUImpl>; - -template <> -int -BaseDynInst<O3CPUImpl>::instcount = 0; diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index 3c4c8e478..b32d2bd23 100644 --- a/src/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh @@ -43,6 +43,8 @@ #include <list> +class DerivO3CPUParams; + /** * Basically a wrapper class to hold both the branch predictor * and the BTB. @@ -51,7 +53,6 @@ template<class Impl> class BPredUnit { private: - typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; enum PredType { @@ -61,12 +62,16 @@ class BPredUnit PredType predictor; + const std::string _name; + public: /** * @param params The params object, that has the size of the BP and BTB. */ - BPredUnit(Params *params); + BPredUnit(DerivO3CPUParams *params); + + const std::string &name() const { return _name; } /** * Registers statistics. @@ -236,21 +241,21 @@ class BPredUnit ReturnAddrStack RAS[Impl::MaxThreads]; /** Stat for number of BP lookups. */ - Stats::Scalar<> lookups; + Stats::Scalar lookups; /** Stat for number of conditional branches predicted. */ - Stats::Scalar<> condPredicted; + Stats::Scalar condPredicted; /** Stat for number of conditional branches predicted incorrectly. */ - Stats::Scalar<> condIncorrect; + Stats::Scalar condIncorrect; /** Stat for number of BTB lookups. */ - Stats::Scalar<> BTBLookups; + Stats::Scalar BTBLookups; /** Stat for number of BTB hits. */ - Stats::Scalar<> BTBHits; + Stats::Scalar BTBHits; /** Stat for number of times the BTB is correct. */ - Stats::Scalar<> BTBCorrect; + Stats::Scalar BTBCorrect; /** Stat for number of times the RAS is used to get a target. */ - Stats::Scalar<> usedRAS; + Stats::Scalar usedRAS; /** Stat for number of times the RAS is incorrect. */ - Stats::Scalar<> RASIncorrect; + Stats::Scalar RASIncorrect; }; #endif // __CPU_O3_BPRED_UNIT_HH__ diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh index 84c50b4da..2fa59280d 100644 --- a/src/cpu/o3/bpred_unit_impl.hh +++ b/src/cpu/o3/bpred_unit_impl.hh @@ -34,11 +34,14 @@ #include "base/traceflags.hh" #include "cpu/o3/bpred_unit.hh" +#include "params/DerivO3CPU.hh" + template<class Impl> -BPredUnit<Impl>::BPredUnit(Params *params) - : BTB(params->BTBEntries, - params->BTBTagSize, - params->instShiftAmt) +BPredUnit<Impl>::BPredUnit(DerivO3CPUParams *params) + : _name(params->name + ".BPredUnit"), + BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) { // Setup the selected predictor. if (params->predType == "local") { @@ -71,43 +74,43 @@ void BPredUnit<Impl>::regStats() { lookups - .name(name() + ".BPredUnit.lookups") + .name(name() + ".lookups") .desc("Number of BP lookups") ; condPredicted - .name(name() + ".BPredUnit.condPredicted") + .name(name() + ".condPredicted") .desc("Number of conditional branches predicted") ; condIncorrect - .name(name() + ".BPredUnit.condIncorrect") + .name(name() + ".condIncorrect") .desc("Number of conditional branches incorrect") ; BTBLookups - .name(name() + ".BPredUnit.BTBLookups") + .name(name() + ".BTBLookups") .desc("Number of BTB lookups") ; BTBHits - .name(name() + ".BPredUnit.BTBHits") + .name(name() + ".BTBHits") .desc("Number of BTB hits") ; BTBCorrect - .name(name() + ".BPredUnit.BTBCorrect") + .name(name() + ".BTBCorrect") .desc("Number of correct BTB predictions (this stat may not " "work properly.") ; usedRAS - .name(name() + ".BPredUnit.usedRAS") + .name(name() + ".usedRAS") .desc("Number of times the RAS was used to get a target.") ; RASIncorrect - .name(name() + ".BPredUnit.RASInCorrect") + .name(name() + ".RASInCorrect") .desc("Number of incorrect RAS predictions.") ; } diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index 80e42fa8b..f21c14569 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -37,6 +37,8 @@ #include "cpu/exetrace.hh" #include "cpu/inst_seq.hh" +class DerivO3CPUParams; + template <class> class O3ThreadState; @@ -69,7 +71,6 @@ class DefaultCommit // Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol CPUPol; typedef typename CPUPol::RenameMap RenameMap; @@ -136,7 +137,7 @@ class DefaultCommit public: /** Construct a DefaultCommit with the given parameters. */ - DefaultCommit(O3CPU *_cpu, Params *params); + DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of the DefaultCommit. */ std::string name() const; @@ -451,40 +452,40 @@ class DefaultCommit void updateComInstStats(DynInstPtr &inst); /** Stat for the total number of committed instructions. */ - Stats::Scalar<> commitCommittedInsts; + Stats::Scalar commitCommittedInsts; /** Stat for the total number of squashed instructions discarded by commit. */ - Stats::Scalar<> commitSquashedInsts; + Stats::Scalar commitSquashedInsts; /** Stat for the total number of times commit is told to squash. * @todo: Actually increment this stat. */ - Stats::Scalar<> commitSquashEvents; + 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; + Stats::Scalar commitNonSpecStalls; /** Stat for the total number of branch mispredicts that caused a squash. */ - Stats::Scalar<> branchMispredicts; + Stats::Scalar branchMispredicts; /** Distribution of the number of committed instructions each cycle. */ - Stats::Distribution<> numCommittedDist; + Stats::Distribution numCommittedDist; /** Total number of instructions committed. */ - Stats::Vector<> statComInst; + Stats::Vector statComInst; /** Total number of software prefetches committed. */ - Stats::Vector<> statComSwp; + Stats::Vector statComSwp; /** Stat for the total number of committed memory references. */ - Stats::Vector<> statComRefs; + Stats::Vector statComRefs; /** Stat for the total number of committed loads. */ - Stats::Vector<> statComLoads; + Stats::Vector statComLoads; /** Total number of committed memory barriers. */ - Stats::Vector<> statComMembars; + Stats::Vector statComMembars; /** Total number of committed branches. */ - Stats::Vector<> statComBranches; + Stats::Vector statComBranches; /** Number of cycles where the commit bandwidth limit is reached. */ - Stats::Scalar<> commitEligibleSamples; + Stats::Scalar commitEligibleSamples; /** Number of instructions not committed due to bandwidth limits. */ - Stats::Vector<> commitEligible; + Stats::Vector commitEligible; }; #endif // __CPU_O3_COMMIT_HH__ diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index ee0f2bb59..7cd88b49b 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -36,6 +36,7 @@ #include <string> #include "arch/utility.hh" +#include "base/cp_annotate.hh" #include "base/loader/symtab.hh" #include "base/timebuf.hh" #include "cpu/exetrace.hh" @@ -46,12 +47,14 @@ #include "cpu/checker/cpu.hh" #endif +#include "params/DerivO3CPU.hh" + template <class Impl> DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, unsigned _tid) - : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) + : Event(CPU_Tick_Pri), commit(_commit), tid(_tid) { - this->setFlags(Event::AutoDelete); + this->setFlags(AutoDelete); } template <class Impl> @@ -71,7 +74,7 @@ DefaultCommit<Impl>::TrapEvent::description() const } template <class Impl> -DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params) +DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), squashCounter(0), iewToCommitDelay(params->iewToCommitDelay), @@ -80,7 +83,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params) fetchToCommitDelay(params->commitToFetchDelay), renameWidth(params->renameWidth), commitWidth(params->commitWidth), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), drainPending(false), switchedOut(false), trapLatency(params->trapLatency) @@ -460,7 +463,7 @@ DefaultCommit<Impl>::generateTrapEvent(unsigned tid) TrapEvent *trap = new TrapEvent(this, tid); - trap->schedule(curTick + trapLatency); + cpu->schedule(trap, curTick + trapLatency); trapInFlight[tid] = true; } @@ -663,7 +666,7 @@ DefaultCommit<Impl>::handleInterrupt() DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); } } else if (commitStatus[0] != TrapPending && - cpu->check_interrupts(cpu->tcBase(0)) && + cpu->checkInterrupts(cpu->tcBase(0)) && !trapSquash[0] && !tcSquash[0]) { // Process interrupts if interrupts are enabled, not in PAL @@ -693,7 +696,7 @@ DefaultCommit<Impl>::commit() // Check for any interrupt, and start processing it. Or if we // have an outstanding interrupt and are at a point when it is // valid to take an interrupt, process it. - if (cpu->check_interrupts(cpu->tcBase(0))) { + if (cpu->checkInterrupts(cpu->tcBase(0))) { handleInterrupt(); } #endif // FULL_SYSTEM @@ -812,7 +815,7 @@ DefaultCommit<Impl>::commit() // @todo: Make this handle multi-cycle communication between // commit and IEW. if (checkEmptyROB[tid] && rob->isEmpty(tid) && - !iewStage->hasStoresToWB() && !committedStores[tid]) { + !iewStage->hasStoresToWB(tid) && !committedStores[tid]) { checkEmptyROB[tid] = false; toIEW->commitInfo[tid].usedROB = true; toIEW->commitInfo[tid].emptyROB = true; @@ -966,7 +969,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", head_inst->seqNum, head_inst->readPC()); - if (inst_num > 0 || iewStage->hasStoresToWB()) { + if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { DPRINTF(Commit, "Waiting for all stores to writeback.\n"); return false; } @@ -981,7 +984,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) return false; } else if (head_inst->isLoad()) { - if (inst_num > 0 || iewStage->hasStoresToWB()) { + if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { DPRINTF(Commit, "Waiting for all stores to writeback.\n"); return false; } @@ -1036,7 +1039,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", head_inst->seqNum, head_inst->readPC()); - if (iewStage->hasStoresToWB() || inst_num > 0) { + if (iewStage->hasStoresToWB(tid) || inst_num > 0) { DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); return false; } @@ -1095,6 +1098,12 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) if (node) thread[tid]->profileNode = node; } + if (CPA::available()) { + if (head_inst->isControl()) { + ThreadContext *tc = thread[tid]->getTC(); + CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC()); + } + } #endif if (head_inst->traceData) { diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index c75a08213..1d7fb97c0 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -37,6 +37,7 @@ #include "cpu/thread_context.hh" #include "cpu/o3/isa_specific.hh" #include "cpu/o3/cpu.hh" +#include "cpu/o3/thread_context.hh" #include "enums/MemoryMode.hh" #include "sim/core.hh" #include "sim/stat_control.hh" @@ -52,10 +53,16 @@ #include "cpu/checker/cpu.hh" #endif +#if THE_ISA == ALPHA_ISA +#include "arch/alpha/osfpal.hh" +#endif + +class BaseCPUParams; + using namespace TheISA; -BaseO3CPU::BaseO3CPU(Params *params) - : BaseCPU(params), cpu_id(0) +BaseO3CPU::BaseO3CPU(BaseCPUParams *params) + : BaseCPU(params) { } @@ -67,7 +74,7 @@ BaseO3CPU::regStats() template <class Impl> FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) + : Event(CPU_Tick_Pri), cpu(c) { } @@ -87,7 +94,7 @@ FullO3CPU<Impl>::TickEvent::description() const template <class Impl> FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent() - : Event(&mainEventQueue, CPU_Switch_Pri) + : Event(CPU_Switch_Pri) { } @@ -116,7 +123,7 @@ FullO3CPU<Impl>::ActivateThreadEvent::description() const template <class Impl> FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent() - : Event(&mainEventQueue, CPU_Tick_Pri), tid(0), remove(false), cpu(NULL) + : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL) { } @@ -147,31 +154,34 @@ FullO3CPU<Impl>::DeallocateContextEvent::description() const } template <class Impl> -FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) +FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params) : BaseO3CPU(params), itb(params->itb), dtb(params->dtb), tickEvent(this), +#ifndef NDEBUG + instcount(0), +#endif removeInstsThisCycle(false), - fetch(o3_cpu, params), - decode(o3_cpu, params), - rename(o3_cpu, params), - iew(o3_cpu, params), - commit(o3_cpu, params), + fetch(this, params), + decode(this, params), + rename(this, params), + iew(this, params), + commit(this, params), - regFile(o3_cpu, params->numPhysIntRegs, + regFile(this, params->numPhysIntRegs, params->numPhysFloatRegs), - freeList(params->numberOfThreads, + freeList(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs), - rob(o3_cpu, + rob(this, params->numROBEntries, params->squashWidth, params->smtROBPolicy, params->smtROBThreshold, - params->numberOfThreads), + params->numThreads), - scoreboard(params->numberOfThreads, + scoreboard(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs, TheISA::NumMiscRegs * number_of_threads, @@ -182,7 +192,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) decodeQueue(params->backComSize, params->forwardComSize), renameQueue(params->backComSize, params->forwardComSize), iewQueue(params->backComSize, params->forwardComSize), - activityRec(NumStages, + activityRec(name(), NumStages, params->backComSize + params->forwardComSize, params->activity), @@ -192,7 +202,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) physmem(system->physmem), #endif // FULL_SYSTEM drainCount(0), - deferRegistration(params->deferRegistration), + deferRegistration(params->defer_registration), numThreads(number_of_threads) { if (!deferRegistration) { @@ -336,6 +346,78 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) //} contextSwitch = false; + DPRINTF(O3CPU, "Creating O3CPU object.\n"); + + // Setup any thread state. + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + // SMT is not supported in FS mode yet. + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0); + this->thread[i]->setStatus(ThreadContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(O3CPU, "Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new typename FullO3CPU<Impl>::Thread( + (typename Impl::O3CPU *)(this), + i, params->workload[i], i); + + this->thread[i]->setStatus(ThreadContext::Suspended); + + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new typename FullO3CPU<Impl>::Thread( + (typename Impl::O3CPU *)(this), + i, dummy_proc, i); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + ThreadContext *tc; + + // Setup the TC that will serve as the interface to the threads/CPU. + O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>; + + tc = o3_tc; + + // If we're using a checker, then the TC should be the + // CheckerThreadContext. +#if USE_CHECKER + if (params->checker) { + tc = new CheckerThreadContext<O3ThreadContext<Impl> >( + o3_tc, this->checker); + } +#endif + + o3_tc->cpu = (typename Impl::O3CPU *)(this); + assert(o3_tc->cpu); + o3_tc->thread = this->thread[i]; + +#if FULL_SYSTEM + // Setup quiesce event. + this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); +#endif + // Give the thread the TC. + this->thread[i]->tc = tc; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->setFuncExeInst(0); + } + + lockAddr = 0; + lockFlag = false; } template <class Impl> @@ -345,7 +427,7 @@ FullO3CPU<Impl>::~FullO3CPU() template <class Impl> void -FullO3CPU<Impl>::fullCPURegStats() +FullO3CPU<Impl>::regStats() { BaseO3CPU::regStats(); @@ -399,6 +481,11 @@ FullO3CPU<Impl>::fullCPURegStats() .precision(6); totalIpc = totalCommittedInsts / numCycles; + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); } template <class Impl> @@ -463,7 +550,7 @@ FullO3CPU<Impl>::tick() lastRunningCycle = curTick; timesIdled++; } else { - tickEvent.schedule(nextCycle(curTick + ticks(1))); + schedule(tickEvent, nextCycle(curTick + ticks(1))); DPRINTF(O3CPU, "Scheduling next tick!\n"); } } @@ -471,16 +558,13 @@ FullO3CPU<Impl>::tick() #if !FULL_SYSTEM updateThreadPriority(); #endif - } template <class Impl> void FullO3CPU<Impl>::init() { - if (!deferRegistration) { - registerThreadContexts(); - } + BaseCPU::init(); // Set inSyscall so that the CPU doesn't squash when initially // setting up registers. @@ -499,7 +583,7 @@ FullO3CPU<Impl>::init() } #if FULL_SYSTEM - TheISA::initCPU(src_tc, src_tc->readCpuId()); + TheISA::initCPU(src_tc, src_tc->contextId()); #endif } @@ -602,7 +686,7 @@ FullO3CPU<Impl>::suspendContext(int tid) DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); bool deallocated = deallocateContext(tid, false, 1); // If this was the last thread then unschedule the tick event. - if (activeThreads.size() == 1 && !deallocated || + if ((activeThreads.size() == 1 && !deallocated) || activeThreads.size() == 0) unscheduleTickEvent(); _status = Idle; @@ -782,18 +866,116 @@ FullO3CPU<Impl>::activateWhenReady(int tid) #if FULL_SYSTEM template <class Impl> +Fault +FullO3CPU<Impl>::hwrei(unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + // Need to clear the lock flag upon returning from an interrupt. + this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); + + this->thread[tid]->kernelStats->hwrei(); + + // FIXME: XXX check for interrupts? XXX +#endif + return NoFault; +} + +template <class Impl> +bool +FullO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + if (this->thread[tid]->kernelStats) + this->thread[tid]->kernelStats->callpal(palFunc, + this->threadContexts[tid]); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (this->system->breakpoint()) + return false; + break; + } +#endif + return true; +} + +template <class Impl> +Fault +FullO3CPU<Impl>::getInterrupts() +{ + // Check if there are any outstanding interrupts + return this->interrupts->getInterrupt(this->threadContexts[0]); +} + +template <class Impl> +void +FullO3CPU<Impl>::processInterrupts(Fault interrupt) +{ + // 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. + + assert(interrupt != NoFault); + this->interrupts->updateIntrInfo(this->threadContexts[0]); + + DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); + this->trap(interrupt, 0); +} + +template <class Impl> void FullO3CPU<Impl>::updateMemPorts() { // Update all ThreadContext's memory ports (Functional/Virtual // Ports) for (int i = 0; i < thread.size(); ++i) - thread[i]->connectMemPorts(); + thread[i]->connectMemPorts(thread[i]->getTC()); } #endif template <class Impl> void +FullO3CPU<Impl>::trap(Fault fault, unsigned tid) +{ + // Pass the thread's TC into the invoke method. + fault->invoke(this->threadContexts[tid]); +} + +#if !FULL_SYSTEM + +template <class Impl> +void +FullO3CPU<Impl>::syscall(int64_t callnum, int tid) +{ + DPRINTF(O3CPU, "[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(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +#endif + +template <class Impl> +void FullO3CPU<Impl>::serialize(std::ostream &os) { SimObject::State so_state = SimObject::getState(); @@ -891,7 +1073,7 @@ FullO3CPU<Impl>::resume() #endif if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); _status = Running; } @@ -984,11 +1166,41 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running; - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } } if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); +} + +template <class Impl> +TheISA::MiscReg +FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscRegNoEffect(misc_reg, tid); +} + +template <class Impl> +TheISA::MiscReg +FullO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscRegNoEffect(misc_reg, val, tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setMiscReg(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscReg(misc_reg, val, tid); } template <class Impl> @@ -1210,6 +1422,14 @@ FullO3CPU<Impl>::setNextMicroPC(Addr new_PC,unsigned tid) } template <class Impl> +void +FullO3CPU<Impl>::squashFromTC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateTCEvent(tid); +} + +template <class Impl> typename FullO3CPU<Impl>::ListIt FullO3CPU<Impl>::addInst(DynInstPtr &inst) { @@ -1419,9 +1639,24 @@ FullO3CPU<Impl>::wakeCPU() idleCycles += tickToCycles((curTick - 1) - lastRunningCycle); numCycles += tickToCycles((curTick - 1) - lastRunningCycle); - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } +#if FULL_SYSTEM +template <class Impl> +void +FullO3CPU<Impl>::wakeup() +{ + if (this->thread[0]->status() != ThreadContext::Suspended) + return; + + this->wakeCPU(); + + DPRINTF(Quiesce, "Suspended Processor woken\n"); + this->threadContexts[0]->activate(); +} +#endif + template <class Impl> int FullO3CPU<Impl>::getFreeTid() diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 61d7dcf22..942970f5f 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -53,6 +53,8 @@ //#include "cpu/o3/thread_context.hh" #include "sim/process.hh" +#include "params/DerivO3CPU.hh" + template <class> class Checker; class ThreadContext; @@ -63,24 +65,15 @@ class Checkpoint; class MemObject; class Process; +class BaseCPUParams; + class BaseO3CPU : public BaseCPU { //Stuff that's pretty ISA independent will go here. public: - typedef BaseCPU::Params Params; - - BaseO3CPU(Params *params); + BaseO3CPU(BaseCPUParams *params); void regStats(); - - /** Sets this CPU's ID. */ - void setCpuId(int id) { cpu_id = id; } - - /** Reads this CPU's ID. */ - int readCpuId() { return cpu_id; } - - protected: - int cpu_id; }; /** @@ -96,8 +89,8 @@ class FullO3CPU : public BaseO3CPU typedef typename Impl::CPUPol CPUPolicy; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; + typedef O3ThreadState<Impl> ImplState; typedef O3ThreadState<Impl> Thread; typedef typename std::list<DynInstPtr>::iterator ListIt; @@ -146,9 +139,9 @@ class FullO3CPU : public BaseO3CPU void scheduleTickEvent(int delay) { if (tickEvent.squashed()) - tickEvent.reschedule(nextCycle(curTick + ticks(delay))); + reschedule(tickEvent, nextCycle(curTick + ticks(delay))); else if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle(curTick + ticks(delay))); + schedule(tickEvent, nextCycle(curTick + ticks(delay))); } /** Unschedule tick event, regardless of its current state. */ @@ -186,11 +179,11 @@ class FullO3CPU : public BaseO3CPU { // Schedule thread to activate, regardless of its current state. if (activateThreadEvent[tid].squashed()) - activateThreadEvent[tid]. - reschedule(nextCycle(curTick + ticks(delay))); + reschedule(activateThreadEvent[tid], + nextCycle(curTick + ticks(delay))); else if (!activateThreadEvent[tid].scheduled()) - activateThreadEvent[tid]. - schedule(nextCycle(curTick + ticks(delay))); + schedule(activateThreadEvent[tid], + nextCycle(curTick + ticks(delay))); } /** Unschedule actiavte thread event, regardless of its current state. */ @@ -237,11 +230,11 @@ class FullO3CPU : public BaseO3CPU { // Schedule thread to activate, regardless of its current state. if (deallocateContextEvent[tid].squashed()) - deallocateContextEvent[tid]. - reschedule(nextCycle(curTick + ticks(delay))); + reschedule(deallocateContextEvent[tid], + nextCycle(curTick + ticks(delay))); else if (!deallocateContextEvent[tid].scheduled()) - deallocateContextEvent[tid]. - schedule(nextCycle(curTick + ticks(delay))); + schedule(deallocateContextEvent[tid], + nextCycle(curTick + ticks(delay))); } /** Unschedule thread deallocation in CPU */ @@ -256,12 +249,12 @@ class FullO3CPU : public BaseO3CPU public: /** Constructs a CPU with the given parameters. */ - FullO3CPU(O3CPU *o3_cpu, Params *params); + FullO3CPU(DerivO3CPUParams *params); /** Destructor. */ ~FullO3CPU(); /** Registers statistics. */ - void fullCPURegStats(); + void regStats(); void demapPage(Addr vaddr, uint64_t asn) { @@ -279,24 +272,6 @@ class FullO3CPU : public BaseO3CPU this->dtb->demapPage(vaddr, asn); } - /** Translates instruction requestion. */ - Fault translateInstReq(RequestPtr &req, Thread *thread) - { - return this->itb->translate(req, thread->getTC()); - } - - /** Translates data read request. */ - Fault translateDataReadReq(RequestPtr &req, Thread *thread) - { - return this->dtb->translate(req, thread->getTC(), false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(RequestPtr &req, Thread *thread) - { - return this->dtb->translate(req, thread->getTC(), true); - } - /** Returns a specific port. */ Port *getPort(const std::string &if_name, int idx); @@ -367,12 +342,12 @@ class FullO3CPU : public BaseO3CPU virtual void unserialize(Checkpoint *cp, const std::string §ion); public: - /** Executes a syscall on this cycle. - * --------------------------------------- - * Note: this is a virtual function. CPU-Specific - * functionality defined in derived classes +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. */ - virtual void syscall(int tid) { panic("Unimplemented!"); } + void syscall(int64_t callnum, int tid); +#endif /** Starts draining the CPU's pipeline of all instructions in * order to stop all memory accesses. */ @@ -394,7 +369,24 @@ class FullO3CPU : public BaseO3CPU InstSeqNum getAndIncrementInstSeq() { return globalSeqNum++; } + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + #if FULL_SYSTEM + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + + bool simPalCheck(int palFunc, unsigned tid); + + /** Returns the Fault for any valid interrupt. */ + Fault getInterrupts(); + + /** Processes any an interrupt fault. */ + void processInterrupts(Fault interrupt); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } + /** Update the Virt and Phys ports of all ThreadContexts to * reflect change in memory connections. */ void updateMemPorts(); @@ -424,6 +416,24 @@ class FullO3CPU : public BaseO3CPU #endif /** Register accessors. Index refers to the physical register index. */ + + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const TheISA::MiscReg &val, + unsigned tid); + uint64_t readIntReg(int reg_idx); TheISA::FloatReg readFloatReg(int reg_idx); @@ -495,6 +505,12 @@ class FullO3CPU : public BaseO3CPU /** Sets the commit next micro PC of a specific thread. */ void setNextMicroPC(Addr val, unsigned tid); + /** Initiates a squash of all in-flight instructions for a given + * thread. The source of the squash is an external update of + * state through the TC. + */ + void squashFromTC(unsigned tid); + /** Function to add instruction onto the head of the list of the * instructions. Used when new instructions are fetched. */ @@ -528,6 +544,11 @@ class FullO3CPU : public BaseO3CPU void dumpInsts(); public: +#ifndef NDEBUG + /** Count of total number of dynamic instructions in flight. */ + int instcount; +#endif + /** List of all the instructions in flight. */ std::list<DynInstPtr> instList; @@ -648,6 +669,10 @@ class FullO3CPU : public BaseO3CPU /** Wakes the CPU, rescheduling the CPU if it's not already active. */ void wakeCPU(); +#if FULL_SYSTEM + virtual void wakeup(); +#endif + /** Gets a free thread id. Use if thread ids change across system. */ int getFreeTid(); @@ -710,14 +735,33 @@ class FullO3CPU : public BaseO3CPU /** Available thread ids in the cpu*/ std::vector<unsigned> tids; + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(RequestPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(RequestPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + /** Temporary fix for the lock flag, works in the UP case. */ + bool lockFlag; + /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; + Stats::Scalar timesIdled; /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; + Stats::Scalar idleCycles; /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; + Stats::Vector committedInsts; /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; + Stats::Scalar totalCommittedInsts; /** Stat for the CPI per thread. */ Stats::Formula cpi; /** Stat for the total CPI. */ diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/cpu_builder.cc index 6d61501ac..77d7091ad 100644 --- a/src/cpu/o3/alpha/thread_context.hh +++ b/src/cpu/o3/cpu_builder.cc @@ -28,49 +28,51 @@ * Authors: Kevin Lim */ -#include "arch/alpha/types.hh" -#include "cpu/o3/thread_context.hh" +#include <string> -template <class Impl> -class AlphaTC : public O3ThreadContext<Impl> +#include "config/full_system.hh" +#include "config/use_checker.hh" +#include "cpu/o3/cpu.hh" +#include "cpu/o3/impl.hh" +#include "params/DerivO3CPU.hh" + +class DerivO3CPU : public FullO3CPU<O3CPUImpl> { public: + DerivO3CPU(DerivO3CPUParams *p) + : FullO3CPU<O3CPUImpl>(p) + { } +}; + +DerivO3CPU * +DerivO3CPUParams::create() +{ #if FULL_SYSTEM - /** Returns pointer to the quiesce event. */ - virtual EndQuiesceEvent *getQuiesceEvent() - { - return this->thread->quiesceEvent; - } -#endif + // 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 >= workload.size()) ? numThreads : workload.size(); - virtual uint64_t readNextNPC() - { - return this->readNextPC() + sizeof(TheISA::MachInst); + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); } +#endif - virtual void setNextNPC(uint64_t val) - { - panic("Alpha has no NextNPC!"); - } + numThreads = actual_num_threads; - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Alpha!"); } + // Default smtFetchPolicy to "RoundRobin", if necessary. + std::string round_robin_policy = "RoundRobin"; + std::string single_thread = "SingleThread"; + if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) + smtFetchPolicy = round_robin_policy; + else + smtFetchPolicy = smtFetchPolicy; - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() - { - this->deallocate(); + instShiftAmt = 2; - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } -}; + return new DerivO3CPU(this); +} diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh index 32a0adcf1..c06c9a201 100644 --- a/src/cpu/o3/cpu_policy.hh +++ b/src/cpu/o3/cpu_policy.hh @@ -65,7 +65,7 @@ struct SimpleCPUPolicy /** Typedef for the branch prediction unit (which includes the BP, * RAS, and BTB). */ - typedef BPredUnit<Impl> BPredUnit; + typedef ::BPredUnit<Impl> BPredUnit; /** Typedef for the register file. Most classes assume a unified * physical register file. */ @@ -75,15 +75,15 @@ struct SimpleCPUPolicy /** Typedef for the rename map. */ typedef SimpleRenameMap RenameMap; /** Typedef for the ROB. */ - typedef ROB<Impl> ROB; + typedef ::ROB<Impl> ROB; /** Typedef for the instruction queue/scheduler. */ typedef InstructionQueue<Impl> IQ; /** Typedef for the memory dependence unit. */ - typedef MemDepUnit<StoreSet, Impl> MemDepUnit; + typedef ::MemDepUnit<StoreSet, Impl> MemDepUnit; /** Typedef for the LSQ. */ - typedef LSQ<Impl> LSQ; + typedef ::LSQ<Impl> LSQ; /** Typedef for the thread-specific LSQ units. */ - typedef LSQUnit<Impl> LSQUnit; + typedef ::LSQUnit<Impl> LSQUnit; /** Typedef for fetch. */ typedef DefaultFetch<Impl> Fetch; @@ -109,7 +109,7 @@ struct SimpleCPUPolicy typedef DefaultIEWDefaultCommit<Impl> IEWStruct; /** The struct for communication within the IEW stage. */ - typedef IssueStruct<Impl> IssueStruct; + typedef ::IssueStruct<Impl> IssueStruct; /** The struct for all backwards communication. */ typedef TimeBufStruct<Impl> TimeStruct; diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh index 3e82033ca..294b5b623 100644 --- a/src/cpu/o3/decode.hh +++ b/src/cpu/o3/decode.hh @@ -36,6 +36,8 @@ #include "base/statistics.hh" #include "base/timebuf.hh" +class DerivO3CPUParams; + /** * DefaultDecode class handles both single threaded and SMT * decode. Its width is specified by the parameters; each cycles it @@ -50,7 +52,6 @@ class DefaultDecode // Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol CPUPol; // Typedefs from the CPU policy. @@ -86,7 +87,7 @@ class DefaultDecode public: /** DefaultDecode constructor. */ - DefaultDecode(O3CPU *_cpu, Params *params); + DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of decode. */ std::string name() const; @@ -287,27 +288,27 @@ class DefaultDecode /** Stat for total number of idle cycles. */ - Stats::Scalar<> decodeIdleCycles; + Stats::Scalar decodeIdleCycles; /** Stat for total number of blocked cycles. */ - Stats::Scalar<> decodeBlockedCycles; + Stats::Scalar decodeBlockedCycles; /** Stat for total number of normal running cycles. */ - Stats::Scalar<> decodeRunCycles; + Stats::Scalar decodeRunCycles; /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> decodeUnblockCycles; + Stats::Scalar decodeUnblockCycles; /** Stat for total number of squashing cycles. */ - Stats::Scalar<> decodeSquashCycles; + Stats::Scalar decodeSquashCycles; /** Stat for number of times a branch is resolved at decode. */ - Stats::Scalar<> decodeBranchResolved; + Stats::Scalar decodeBranchResolved; /** Stat for number of times a branch mispredict is detected. */ - Stats::Scalar<> decodeBranchMispred; + Stats::Scalar decodeBranchMispred; /** Stat for number of times decode detected a non-control instruction * incorrectly predicted as a branch. */ - Stats::Scalar<> decodeControlMispred; + Stats::Scalar decodeControlMispred; /** Stat for total number of decoded instructions. */ - Stats::Scalar<> decodeDecodedInsts; + Stats::Scalar decodeDecodedInsts; /** Stat for total number of squashed instructions. */ - Stats::Scalar<> decodeSquashedInsts; + Stats::Scalar decodeSquashedInsts; }; #endif // __CPU_O3_DECODE_HH__ diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh index ce6738456..015bc8d7f 100644 --- a/src/cpu/o3/decode_impl.hh +++ b/src/cpu/o3/decode_impl.hh @@ -30,15 +30,17 @@ #include "cpu/o3/decode.hh" +#include "params/DerivO3CPU.hh" + template<class Impl> -DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, Params *params) +DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), renameToDecodeDelay(params->renameToDecodeDelay), iewToDecodeDelay(params->iewToDecodeDelay), commitToDecodeDelay(params->commitToDecodeDelay), fetchToDecodeDelay(params->fetchToDecodeDelay), decodeWidth(params->decodeWidth), - numThreads(params->numberOfThreads) + numThreads(params->numThreads) { _status = Inactive; diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/dyn_inst.cc index 984b58f4b..d828ef1b0 100644 --- a/src/cpu/o3/sparc/dyn_inst.cc +++ b/src/cpu/o3/dyn_inst.cc @@ -28,9 +28,9 @@ * Authors: Gabe Black */ -#include "cpu/o3/sparc/dyn_inst_impl.hh" -#include "cpu/o3/sparc/impl.hh" +#include "cpu/o3/dyn_inst_impl.hh" +#include "cpu/o3/impl.hh" -// Force instantiation of SparcDynInst for all the implementations that +// Force instantiation of BaseO3DynInst for all the implementations that // are needed. -template class SparcDynInst<SparcSimpleImpl>; +template class BaseO3DynInst<O3CPUImpl>; diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index a1f9e0591..292547b6b 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * 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 @@ -25,36 +25,266 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Korey Sewell + * Authors: Kevin Lim */ #ifndef __CPU_O3_DYN_INST_HH__ #define __CPU_O3_DYN_INST_HH__ -#include "arch/isa_specific.hh" - -#if THE_ISA == ALPHA_ISA - template <class Impl> class AlphaDynInst; - struct AlphaSimpleImpl; - typedef AlphaDynInst<AlphaSimpleImpl> O3DynInst; -#elif THE_ISA == MIPS_ISA - template <class Impl> class MipsDynInst; - struct MipsSimpleImpl; - typedef MipsDynInst<MipsSimpleImpl> O3DynInst; -#elif THE_ISA == SPARC_ISA - template <class Impl> class SparcDynInst; - struct SparcSimpleImpl; - typedef SparcDynInst<SparcSimpleImpl> O3DynInst; -#elif THE_ISA == X86_ISA - template <class Impl> class X86DynInst; - struct X86SimpleImpl; - typedef X86DynInst<X86SimpleImpl> O3DynInst; -#elif THE_ISA == ARM_ISA - template <class Impl> class ArmDynInst; - struct ArmSimpleImpl; - typedef ArmDynInst<ArmSimpleImpl> O3DynInst; +#include "arch/isa_traits.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/cpu.hh" +#include "cpu/o3/isa_specific.hh" + +class Packet; + +/** + * 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 BaseO3DynInst : public BaseDynInst<Impl> +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::O3CPU O3CPU; + + /** 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; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + /** 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. */ + BaseO3DynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a binary instruction. */ + BaseO3DynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + BaseO3DynInst(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(PacketPtr pkt); + + private: + /** Initializes variables. */ + void initVars(); + + public: + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg) + { + return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val) + { + return this->cpu->setMiscReg(misc_reg, val, + this->threadNumber); + } + + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) + { + return this->cpu->readMiscRegNoEffect( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readMiscReg( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscRegNoEffect( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscRegOperand(const StaticInst *si, int idx, + const MiscReg &val) + { + return this->cpu->setMiscReg( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); #else - #error "O3DynInst not defined for this ISA" + /** Calls a syscall. */ + void syscall(int64_t callnum); #endif -#endif // __CPU_O3_DYN_INST_HH__ + 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 readIntRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readIntReg(this->_srcRegIdx[idx]); + } + + FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); + } + + FloatReg readFloatRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx]); + } + + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, + int width) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); + } + + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) + { + this->cpu->setIntReg(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setIntRegOperand(si, idx, val); + } + + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, + int width) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); + } + + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); + } + + void setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); + } + + void setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); + } + +#if THE_ISA == MIPS_ISA + uint64_t readRegOtherThread(int misc_reg) + { + panic("MIPS MT not defined for O3 CPU.\n"); + return 0; + } + + void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val) + { + panic("MIPS MT not defined for O3 CPU.\n"); + } +#endif + + 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/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index 6dfe0ccdd..8d391ceaf 100644 --- a/src/cpu/o3/alpha/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -28,34 +28,35 @@ * Authors: Kevin Lim */ -#include "cpu/o3/alpha/dyn_inst.hh" +#include "base/cp_annotate.hh" +#include "cpu/o3/dyn_inst.hh" template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, - Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) +BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr staticInst, + Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, + Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu) : BaseDynInst<Impl>(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) + Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) { initVars(); } template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, - Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) +BaseO3DynInst<Impl>::BaseO3DynInst(ExtMachInst inst, + Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, + Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu) : BaseDynInst<Impl>(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) + Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) { initVars(); } template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) +BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr &_staticInst) : BaseDynInst<Impl>(_staticInst) { initVars(); @@ -63,7 +64,7 @@ AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) template <class Impl> void -AlphaDynInst<Impl>::initVars() +BaseO3DynInst<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 @@ -80,7 +81,7 @@ AlphaDynInst<Impl>::initVars() template <class Impl> Fault -AlphaDynInst<Impl>::execute() +BaseO3DynInst<Impl>::execute() { // @todo: Pretty convoluted way to avoid squashing from happening // when using the TC during an instruction's execution @@ -98,7 +99,7 @@ AlphaDynInst<Impl>::execute() template <class Impl> Fault -AlphaDynInst<Impl>::initiateAcc() +BaseO3DynInst<Impl>::initiateAcc() { // @todo: Pretty convoluted way to avoid squashing from happening // when using the TC during an instruction's execution @@ -116,7 +117,7 @@ AlphaDynInst<Impl>::initiateAcc() template <class Impl> Fault -AlphaDynInst<Impl>::completeAcc(PacketPtr pkt) +BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt) { this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); @@ -126,8 +127,9 @@ AlphaDynInst<Impl>::completeAcc(PacketPtr pkt) #if FULL_SYSTEM template <class Impl> Fault -AlphaDynInst<Impl>::hwrei() +BaseO3DynInst<Impl>::hwrei() { +#if THE_ISA == ALPHA_ISA // Can only do a hwrei when in pal mode. if (!(this->readPC() & 0x3)) return new AlphaISA::UnimplementedOpcodeFault; @@ -135,33 +137,50 @@ AlphaDynInst<Impl>::hwrei() // Set the next PC based on the value of the EXC_ADDR IPR. this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, this->threadNumber)); + if (CPA::available()) { + ThreadContext *tc = this->cpu->tcBase(this->threadNumber); + CPA::cpa()->swAutoBegin(tc, this->readNextPC()); + } // Tell CPU to clear any state it needs to if a hwrei is taken. this->cpu->hwrei(this->threadNumber); +#else +#endif // FIXME: XXX check for interrupts? XXX return NoFault; } template <class Impl> void -AlphaDynInst<Impl>::trap(Fault fault) +BaseO3DynInst<Impl>::trap(Fault fault) { this->cpu->trap(fault, this->threadNumber); } template <class Impl> bool -AlphaDynInst<Impl>::simPalCheck(int palFunc) +BaseO3DynInst<Impl>::simPalCheck(int palFunc) { +#if THE_ISA != ALPHA_ISA + panic("simPalCheck called, but PAL only exists in Alpha!\n"); +#endif return this->cpu->simPalCheck(palFunc, this->threadNumber); } #else template <class Impl> void -AlphaDynInst<Impl>::syscall(int64_t callnum) +BaseO3DynInst<Impl>::syscall(int64_t callnum) { + // HACK: check CPU's nextPC before and after syscall. If it + // changes, update this instruction's nextPC because the syscall + // must have changed the nextPC. + Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber); this->cpu->syscall(callnum, this->threadNumber); + Addr new_next_pc = this->cpu->readNextPC(this->threadNumber); + if (cpu_next_pc != new_next_pc) { + this->setNextPC(new_next_pc); + } } #endif diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index d954bd1e7..08ccb094b 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -41,6 +41,8 @@ #include "mem/port.hh" #include "sim/eventq.hh" +class DerivO3CPUParams; + /** * DefaultFetch class handles both single threaded and SMT fetch. Its * width is specified by the parameters; each cycle it tries to fetch @@ -58,7 +60,6 @@ class DefaultFetch typedef typename Impl::DynInst DynInst; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; /** Typedefs from the CPU policy. */ typedef typename CPUPol::BPredUnit BPredUnit; @@ -81,7 +82,7 @@ class DefaultFetch public: /** Default constructor. */ IcachePort(DefaultFetch<Impl> *_fetch) - : Port(_fetch->name() + "-iport"), fetch(_fetch) + : Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch) { } bool snoopRangeSent; @@ -160,7 +161,7 @@ class DefaultFetch public: /** DefaultFetch constructor. */ - DefaultFetch(O3CPU *_cpu, Params *params); + DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of fetch. */ std::string name() const; @@ -447,33 +448,33 @@ class DefaultFetch // @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; + Stats::Scalar icacheStallCycles; /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; + Stats::Scalar fetchedInsts; /** Total number of fetched branches. */ - Stats::Scalar<> fetchedBranches; + Stats::Scalar fetchedBranches; /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; + Stats::Scalar predictedBranches; /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; + Stats::Scalar fetchCycles; /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; + Stats::Scalar fetchSquashCycles; /** Stat for total number of cycles spent blocked due to other stages in * the pipeline. */ - Stats::Scalar<> fetchIdleCycles; + Stats::Scalar fetchIdleCycles; /** Total number of cycles spent blocked. */ - Stats::Scalar<> fetchBlockedCycles; + Stats::Scalar fetchBlockedCycles; /** Total number of cycles spent in any other state. */ - Stats::Scalar<> fetchMiscStallCycles; + Stats::Scalar fetchMiscStallCycles; /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; + Stats::Scalar fetchedCacheLines; /** Total number of outstanding icache accesses that were dropped * due to a squash. */ - Stats::Scalar<> fetchIcacheSquashes; + Stats::Scalar fetchIcacheSquashes; /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; + Stats::Distribution fetchNisnDist; /** Rate of how often fetch was idle. */ Stats::Formula idleRate; /** Number of branch fetches per cycle. */ diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 7d344fa33..79a4f2b7a 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -51,6 +51,8 @@ #include "sim/system.hh" #endif // FULL_SYSTEM +#include "params/DerivO3CPU.hh" + template<class Impl> void DefaultFetch<Impl>::IcachePort::setPeer(Port *port) @@ -111,7 +113,7 @@ DefaultFetch<Impl>::IcachePort::recvRetry() } template<class Impl> -DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params) +DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), branchPred(params), predecoder(NULL), @@ -123,14 +125,16 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params) cacheBlocked(false), retryPkt(NULL), retryTid(-1), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), numFetchingThreads(params->smtNumFetchingThreads), interruptPending(false), drainPending(false), switchedOut(false) { if (numThreads > Impl::MaxThreads) - fatal("numThreads is not a valid value\n"); + fatal("numThreads (%d) is larger than compiled limit (%d),\n" + "\tincrease MaxThreads in src/cpu/o3/impl.hh\n", + numThreads, static_cast<int>(Impl::MaxThreads)); // Set fetch stage's status to inactive. _status = Inactive; @@ -360,7 +364,7 @@ template<class Impl> void DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt) { - unsigned tid = pkt->req->getThreadNum(); + unsigned tid = pkt->req->threadId(); DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); @@ -591,12 +595,13 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid // Set the appropriate read size and flags as well. // Build request here. RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0, - fetch_PC, cpu->readCpuId(), tid); + fetch_PC, cpu->thread[tid]->contextId(), + tid); memReq[tid] = mem_req; // Translate the instruction request. - fault = cpu->translateInstReq(mem_req, cpu->thread[tid]); + fault = cpu->itb->translateAtomic(mem_req, cpu->thread[tid]->getTC()); // In the case of faults, the fetch stage may need to stall and wait // for the ITB miss to be handled. diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 457e2a024..3458f09d6 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -41,6 +41,7 @@ #include "cpu/o3/scoreboard.hh" #include "cpu/o3/lsq.hh" +class DerivO3CPUParams; class FUPool; /** @@ -70,7 +71,6 @@ class DefaultIEW typedef typename Impl::CPUPol CPUPol; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; typedef typename CPUPol::IQ IQ; typedef typename CPUPol::RenameMap RenameMap; @@ -115,7 +115,7 @@ class DefaultIEW public: /** Constructs a DefaultIEW with the given parameters. */ - DefaultIEW(O3CPU *_cpu, Params *params); + DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of the DefaultIEW stage. */ std::string name() const; @@ -208,6 +208,9 @@ class DefaultIEW /** Returns if the LSQ has any stores to writeback. */ bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); } + /** Returns if the LSQ has any stores to writeback. */ + bool hasStoresToWB(unsigned tid) { return ldstQueue.hasStoresToWB(tid); } + void incrWb(InstSeqNum &sn) { if (++wbOutstanding == wbMax) @@ -462,69 +465,69 @@ class DefaultIEW bool switchedOut; /** Stat for total number of idle cycles. */ - Stats::Scalar<> iewIdleCycles; + Stats::Scalar iewIdleCycles; /** Stat for total number of squashing cycles. */ - Stats::Scalar<> iewSquashCycles; + Stats::Scalar iewSquashCycles; /** Stat for total number of blocking cycles. */ - Stats::Scalar<> iewBlockCycles; + Stats::Scalar iewBlockCycles; /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> iewUnblockCycles; + Stats::Scalar iewUnblockCycles; /** Stat for total number of instructions dispatched. */ - Stats::Scalar<> iewDispatchedInsts; + Stats::Scalar iewDispatchedInsts; /** Stat for total number of squashed instructions dispatch skips. */ - Stats::Scalar<> iewDispSquashedInsts; + Stats::Scalar iewDispSquashedInsts; /** Stat for total number of dispatched load instructions. */ - Stats::Scalar<> iewDispLoadInsts; + Stats::Scalar iewDispLoadInsts; /** Stat for total number of dispatched store instructions. */ - Stats::Scalar<> iewDispStoreInsts; + Stats::Scalar iewDispStoreInsts; /** Stat for total number of dispatched non speculative instructions. */ - Stats::Scalar<> iewDispNonSpecInsts; + Stats::Scalar iewDispNonSpecInsts; /** Stat for number of times the IQ becomes full. */ - Stats::Scalar<> iewIQFullEvents; + Stats::Scalar iewIQFullEvents; /** Stat for number of times the LSQ becomes full. */ - Stats::Scalar<> iewLSQFullEvents; + Stats::Scalar iewLSQFullEvents; /** Stat for total number of memory ordering violation events. */ - Stats::Scalar<> memOrderViolationEvents; + Stats::Scalar memOrderViolationEvents; /** Stat for total number of incorrect predicted taken branches. */ - Stats::Scalar<> predictedTakenIncorrect; + Stats::Scalar predictedTakenIncorrect; /** Stat for total number of incorrect predicted not taken branches. */ - Stats::Scalar<> predictedNotTakenIncorrect; + Stats::Scalar predictedNotTakenIncorrect; /** Stat for total number of mispredicted branches detected at execute. */ Stats::Formula branchMispredicts; /** Stat for total number of executed instructions. */ - Stats::Scalar<> iewExecutedInsts; + Stats::Scalar iewExecutedInsts; /** Stat for total number of executed load instructions. */ - Stats::Vector<> iewExecLoadInsts; + Stats::Vector iewExecLoadInsts; /** Stat for total number of executed store instructions. */ -// Stats::Scalar<> iewExecStoreInsts; +// Stats::Scalar iewExecStoreInsts; /** Stat for total number of squashed instructions skipped at execute. */ - Stats::Scalar<> iewExecSquashedInsts; + Stats::Scalar iewExecSquashedInsts; /** Number of executed software prefetches. */ - Stats::Vector<> iewExecutedSwp; + Stats::Vector iewExecutedSwp; /** Number of executed nops. */ - Stats::Vector<> iewExecutedNop; + Stats::Vector iewExecutedNop; /** Number of executed meomory references. */ - Stats::Vector<> iewExecutedRefs; + Stats::Vector iewExecutedRefs; /** Number of executed branches. */ - Stats::Vector<> iewExecutedBranches; + Stats::Vector iewExecutedBranches; /** Number of executed store instructions. */ Stats::Formula iewExecStoreInsts; /** Number of instructions executed per cycle. */ Stats::Formula iewExecRate; /** Number of instructions sent to commit. */ - Stats::Vector<> iewInstsToCommit; + Stats::Vector iewInstsToCommit; /** Number of instructions that writeback. */ - Stats::Vector<> writebackCount; + Stats::Vector writebackCount; /** Number of instructions that wake consumers. */ - Stats::Vector<> producerInst; + Stats::Vector producerInst; /** Number of instructions that wake up from producers. */ - Stats::Vector<> consumerInst; + Stats::Vector consumerInst; /** Number of instructions that were delayed in writing back due * to resource contention. */ - Stats::Vector<> wbPenalized; + Stats::Vector wbPenalized; /** Number of instructions per cycle written back. */ Stats::Formula wbRate; /** Average number of woken instructions per writeback. */ diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 84d10e966..1daecd669 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -37,9 +37,10 @@ #include "base/timebuf.hh" #include "cpu/o3/fu_pool.hh" #include "cpu/o3/iew.hh" +#include "params/DerivO3CPU.hh" template<class Impl> -DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params) +DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params) : issueToExecQueue(params->backComSize, params->forwardComSize), cpu(_cpu), instQueue(_cpu, this, params), @@ -52,7 +53,7 @@ DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params) issueWidth(params->issueWidth), wbOutstanding(0), wbWidth(params->wbWidth), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), switchedOut(false) { _status = Active; diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/impl.hh index 0a970c2f0..4b29b4daa 100644 --- a/src/cpu/o3/sparc/impl.hh +++ b/src/cpu/o3/impl.hh @@ -25,24 +25,23 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black + * Authors: Kevin Lim */ -#ifndef __CPU_O3_SPARC_IMPL_HH__ -#define __CPU_O3_SPARC_IMPL_HH__ +#ifndef __CPU_O3_IMPL_HH__ +#define __CPU_O3_IMPL_HH__ -#include "arch/sparc/isa_traits.hh" +#include "arch/isa_traits.hh" -#include "cpu/o3/sparc/params.hh" #include "cpu/o3/cpu_policy.hh" // Forward declarations. template <class Impl> -class SparcDynInst; +class BaseO3DynInst; template <class Impl> -class SparcO3CPU; +class FullO3CPU; /** Implementation specific struct that defines several key types to the * CPU, the stages within the CPU, the time buffers, and the DynInst. @@ -52,16 +51,16 @@ class SparcO3CPU; * This is one of the key things that must be defined for each hardware * specific CPU implementation. */ -struct SparcSimpleImpl +struct O3CPUImpl { /** The type of MachInst. */ typedef TheISA::MachInst MachInst; /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<SparcSimpleImpl> CPUPol; + typedef SimpleCPUPolicy<O3CPUImpl> CPUPol; /** The DynInst type to be used. */ - typedef SparcDynInst<SparcSimpleImpl> DynInst; + typedef BaseO3DynInst<O3CPUImpl> DynInst; /** The refcounted DynInst pointer to be used. In most cases this is * what should be used, and not DynInst *. @@ -69,7 +68,7 @@ struct SparcSimpleImpl typedef RefCountingPtr<DynInst> DynInstPtr; /** The O3CPU type to be used. */ - typedef SparcO3CPU<SparcSimpleImpl> O3CPU; + typedef FullO3CPU<O3CPUImpl> O3CPU; /** Same typedef, but for CPUType. BaseDynInst may not always use * an O3 CPU, so it's clearer to call it CPUType instead in that @@ -77,16 +76,10 @@ struct SparcSimpleImpl */ typedef O3CPU CPUType; - /** The Params to be passed to each stage. */ - typedef SparcSimpleParams Params; - enum { MaxWidth = 8, MaxThreads = 4 }; }; -/** The O3Impl to be used. */ -typedef SparcSimpleImpl O3CPUImpl; - #endif // __CPU_O3_SPARC_IMPL_HH__ diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index d0f503977..0c3f44436 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -41,8 +41,10 @@ #include "cpu/inst_seq.hh" #include "cpu/o3/dep_graph.hh" #include "cpu/op_class.hh" +#include "sim/eventq.hh" #include "sim/host.hh" +class DerivO3CPUParams; class FUPool; class MemInterface; @@ -70,7 +72,6 @@ class InstructionQueue //Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol::IEW IEW; typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; @@ -110,7 +111,7 @@ class InstructionQueue }; /** Constructs an IQ. */ - InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params); + InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params); /** Destructs the IQ. */ ~InstructionQueue(); @@ -442,58 +443,58 @@ class InstructionQueue void dumpInsts(); /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; + Stats::Scalar iqInstsAdded; /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; + Stats::Scalar iqNonSpecInstsAdded; - Stats::Scalar<> iqInstsIssued; + Stats::Scalar iqInstsIssued; /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; + Stats::Scalar iqIntInstsIssued; /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; + Stats::Scalar iqFloatInstsIssued; /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; + Stats::Scalar iqBranchInstsIssued; /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; + Stats::Scalar iqMemInstsIssued; /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; + Stats::Scalar iqMiscInstsIssued; /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; + Stats::Scalar iqSquashedInstsIssued; /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; + Stats::Scalar iqSquashedInstsExamined; /** Stat for number of squashed instruction operands examined when * squashing. */ - Stats::Scalar<> iqSquashedOperandsExamined; + Stats::Scalar iqSquashedOperandsExamined; /** Stat for number of non-speculative instructions removed due to a squash. */ - Stats::Scalar<> iqSquashedNonSpecRemoved; + Stats::Scalar iqSquashedNonSpecRemoved; // Also include number of instructions rescheduled and replayed. /** Distribution of number of instructions in the queue. * @todo: Need to create struct to track the entry time for each * instruction. */ -// Stats::VectorDistribution<> queueResDist; +// Stats::VectorDistribution queueResDist; /** Distribution of the number of instructions issued. */ - Stats::Distribution<> numIssuedDist; + Stats::Distribution numIssuedDist; /** Distribution of the cycles it takes to issue an instruction. * @todo: Need to create struct to track the ready time for each * instruction. */ -// Stats::VectorDistribution<> issueDelayDist; +// Stats::VectorDistribution issueDelayDist; /** Number of times an instruction could not be issued because a * FU was busy. */ - Stats::Vector<> statFuBusy; -// Stats::Vector<> dist_unissued; + Stats::Vector statFuBusy; +// Stats::Vector dist_unissued; /** Stat for total number issued for each instruction type. */ - Stats::Vector2d<> statIssuedInstType; + Stats::Vector2d statIssuedInstType; /** Number of instructions issued per cycle. */ Stats::Formula issueRate; /** Number of times the FU was busy. */ - Stats::Vector<> fuBusy; + Stats::Vector fuBusy; /** Number of times the FU was busy per instruction issued. */ Stats::Formula fuBusyRate; }; diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index fb06f20df..1d0f4b9f6 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -37,12 +37,13 @@ #include "enums/OpClass.hh" #include "sim/core.hh" +#include "params/DerivO3CPU.hh" + 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) + int fu_idx, InstructionQueue<Impl> *iq_ptr) + : Event(Stat_Event_Pri), inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), + freeFU(false) { this->setFlags(Event::AutoDelete); } @@ -65,7 +66,7 @@ InstructionQueue<Impl>::FUCompletion::description() const template <class Impl> InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, - Params *params) + DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), fuPool(params->fuPool), @@ -79,7 +80,7 @@ InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, switchedOut = false; - numThreads = params->numberOfThreads; + numThreads = params->numThreads; // Set the number of physical registers as the number of int + float numPhysRegs = numPhysIntRegs + numPhysFloatRegs; @@ -752,7 +753,7 @@ InstructionQueue<Impl>::scheduleReadyInsts() FUCompletion *execution = new FUCompletion(issuing_inst, idx, this); - execution->schedule(curTick + cpu->ticks(op_latency - 1)); + cpu->schedule(execution, curTick + cpu->ticks(op_latency - 1)); // @todo: Enforce that issue_latency == 1 or op_latency if (issue_latency > 1) { diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 72a8d4021..e9347af91 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -30,21 +30,5 @@ #include "cpu/base.hh" -#if THE_ISA == ALPHA_ISA - #include "cpu/o3/alpha/cpu.hh" - #include "cpu/o3/alpha/impl.hh" - #include "cpu/o3/alpha/params.hh" - #include "cpu/o3/alpha/dyn_inst.hh" -#elif THE_ISA == MIPS_ISA - #include "cpu/o3/mips/cpu.hh" - #include "cpu/o3/mips/impl.hh" - #include "cpu/o3/mips/params.hh" - #include "cpu/o3/mips/dyn_inst.hh" -#elif THE_ISA == SPARC_ISA - #include "cpu/o3/sparc/cpu.hh" - #include "cpu/o3/sparc/impl.hh" - #include "cpu/o3/sparc/params.hh" - #include "cpu/o3/sparc/dyn_inst.hh" -#else - #error "ISA-specific header files O3CPU not defined ISA" -#endif +#include "cpu/o3/impl.hh" +#include "cpu/o3/dyn_inst.hh" diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 06de608e0..cf27552d4 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -40,10 +40,11 @@ #include "mem/port.hh" #include "sim/sim_object.hh" +class DerivO3CPUParams; + template <class Impl> class LSQ { public: - typedef typename Impl::Params Params; typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; @@ -57,7 +58,7 @@ class LSQ { }; /** Constructs an LSQ with the given parameters. */ - LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params); + LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params); /** Returns the name of the LSQ. */ std::string name() const; @@ -297,7 +298,7 @@ class LSQ { public: /** Default constructor. */ DcachePort(LSQ *_lsq) - : Port(_lsq->name() + "-dport"), lsq(_lsq) + : Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq) { } bool snoopRangeSent; @@ -370,7 +371,7 @@ template <class T> Fault LSQ<Impl>::read(RequestPtr req, T &data, int load_idx) { - unsigned tid = req->getThreadNum(); + unsigned tid = req->threadId(); return thread[tid].read(req, data, load_idx); } @@ -380,7 +381,7 @@ template <class T> Fault LSQ<Impl>::write(RequestPtr req, T &data, int store_idx) { - unsigned tid = req->getThreadNum(); + unsigned tid = req->threadId(); return thread[tid].write(req, data, store_idx); } diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 8ed6f7f54..8f9f63081 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -34,6 +34,8 @@ #include "cpu/o3/lsq.hh" +#include "params/DerivO3CPU.hh" + template<class Impl> void LSQ<Impl>::DcachePort::setPeer(Port *port) @@ -83,7 +85,7 @@ LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt) if (pkt->isError()) DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr()); if (pkt->isResponse()) { - lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt); + lsq->thread[pkt->req->threadId()].completeDataAccess(pkt); } else { // must be a snoop @@ -111,11 +113,11 @@ LSQ<Impl>::DcachePort::recvRetry() } template <class Impl> -LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) +LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), LQEntries(params->LQEntries), SQEntries(params->SQEntries), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), retryTid(-1) { dcachePort.snoopRangeSent = false; @@ -582,17 +584,14 @@ LSQ<Impl>::hasStoresToWB() std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); - if (threads == end) - return false; - while (threads != end) { unsigned tid = *threads++; - if (!hasStoresToWB(tid)) - return false; + if (hasStoresToWB(tid)) + return true; } - return true; + return false; } template<class Impl> @@ -605,11 +604,11 @@ LSQ<Impl>::willWB() while (threads != end) { unsigned tid = *threads++; - if (!willWB(tid)) - return false; + if (willWB(tid)) + return true; } - return true; + return false; } template<class Impl> diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 128a71dbc..5323e3a47 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -40,11 +40,14 @@ #include "arch/faults.hh" #include "arch/locked_mem.hh" #include "config/full_system.hh" +#include "base/fast_alloc.hh" #include "base/hashmap.hh" #include "cpu/inst_seq.hh" #include "mem/packet.hh" #include "mem/port.hh" +class DerivO3CPUParams; + /** * Class that implements the actual LQ and SQ for each specific * thread. Both are circular queues; load entries are freed upon @@ -62,7 +65,6 @@ class LSQUnit { protected: typedef TheISA::IntReg IntReg; public: - typedef typename Impl::Params Params; typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; @@ -74,8 +76,9 @@ class LSQUnit { LSQUnit(); /** Initializes the LSQ unit with the specified number of entries. */ - void init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr, - unsigned maxLQEntries, unsigned maxSQEntries, unsigned id); + void init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params, + LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, + unsigned id); /** Returns the name of the LSQ unit. */ std::string name() const; @@ -245,7 +248,7 @@ class LSQUnit { Port *dcachePort; /** Derived class to hold any sender state the LSQ needs. */ - class LSQSenderState : public Packet::SenderState + class LSQSenderState : public Packet::SenderState, public FastAlloc { public: /** Default constructor. */ @@ -406,35 +409,35 @@ class LSQUnit { // of that in stage that is one level up, and only call executeLoad/Store // the appropriate number of times. /** Total number of loads forwaded from LSQ stores. */ - Stats::Scalar<> lsqForwLoads; + Stats::Scalar lsqForwLoads; /** Total number of loads ignored due to invalid addresses. */ - Stats::Scalar<> invAddrLoads; + Stats::Scalar invAddrLoads; /** Total number of squashed loads. */ - Stats::Scalar<> lsqSquashedLoads; + Stats::Scalar lsqSquashedLoads; /** Total number of responses from the memory system that are * ignored due to the instruction already being squashed. */ - Stats::Scalar<> lsqIgnoredResponses; + Stats::Scalar lsqIgnoredResponses; /** Tota number of memory ordering violations. */ - Stats::Scalar<> lsqMemOrderViolation; + Stats::Scalar lsqMemOrderViolation; /** Total number of squashed stores. */ - Stats::Scalar<> lsqSquashedStores; + Stats::Scalar lsqSquashedStores; /** Total number of software prefetches ignored due to invalid addresses. */ - Stats::Scalar<> invAddrSwpfs; + Stats::Scalar invAddrSwpfs; /** Ready loads blocked due to partial store-forwarding. */ - Stats::Scalar<> lsqBlockedLoads; + Stats::Scalar lsqBlockedLoads; /** Number of loads that were rescheduled. */ - Stats::Scalar<> lsqRescheduledLoads; + Stats::Scalar lsqRescheduledLoads; /** Number of times the LSQ is blocked due to the cache. */ - Stats::Scalar<> lsqCacheBlocked; + Stats::Scalar lsqCacheBlocked; public: /** Executes the load at the given index. */ @@ -581,7 +584,7 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx) // We'll say this has a 1 cycle load-store forwarding latency // for now. // @todo: Need to make this a parameter. - wb->schedule(curTick); + cpu->schedule(wb, curTick); ++lsqForwLoads; return NoFault; diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index e6ff5e931..85662d496 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -45,7 +45,7 @@ template<class Impl> LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt, LSQUnit *lsq_ptr) - : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) + : inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) { this->setFlags(Event::AutoDelete); } @@ -112,8 +112,9 @@ LSQUnit<Impl>::LSQUnit() template<class Impl> void -LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr, - unsigned maxLQEntries, unsigned maxSQEntries, unsigned id) +LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params, + LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, + unsigned id) { cpu = cpu_ptr; iewStage = iew_ptr; @@ -683,7 +684,7 @@ LSQUnit<Impl>::writebackStores() "Instantly completing it.\n", inst->seqNum); WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this); - wb->schedule(curTick + 1); + cpu->schedule(wb, curTick + 1); completeStore(storeWBIdx); incrStIdx(storeWBIdx); continue; diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index a12a3001b..4f9e7c9f7 100644 --- a/src/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh @@ -48,6 +48,8 @@ struct SNHash { } }; +class DerivO3CPUParams; + template <class Impl> class InstructionQueue; @@ -63,25 +65,28 @@ class InstructionQueue; * dependence prediction schemes. */ template <class MemDepPred, class Impl> -class MemDepUnit { +class MemDepUnit +{ + protected: + std::string _name; + 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); + MemDepUnit(DerivO3CPUParams *params); /** Frees up any memory allocated. */ ~MemDepUnit(); /** Returns the name of the memory dependence unit. */ - std::string name() const; + std::string name() const { return _name; } /** Initializes the unit with parameters and a thread id. */ - void init(Params *params, int tid); + void init(DerivO3CPUParams *params, int tid); /** Registers statistics. */ void regStats(); @@ -252,13 +257,13 @@ class MemDepUnit { int id; /** Stat for number of inserted loads. */ - Stats::Scalar<> insertedLoads; + Stats::Scalar insertedLoads; /** Stat for number of inserted stores. */ - Stats::Scalar<> insertedStores; + Stats::Scalar insertedStores; /** Stat for number of conflicting loads that had to wait for a store. */ - Stats::Scalar<> conflictingLoads; + Stats::Scalar conflictingLoads; /** Stat for number of conflicting stores that had to wait for a store. */ - Stats::Scalar<> conflictingStores; + Stats::Scalar conflictingStores; }; #endif // __CPU_O3_MEM_DEP_UNIT_HH__ diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh index 64558efaa..8754539f9 100644 --- a/src/cpu/o3/mem_dep_unit_impl.hh +++ b/src/cpu/o3/mem_dep_unit_impl.hh @@ -33,6 +33,8 @@ #include "cpu/o3/inst_queue.hh" #include "cpu/o3/mem_dep_unit.hh" +#include "params/DerivO3CPU.hh" + template <class MemDepPred, class Impl> MemDepUnit<MemDepPred, Impl>::MemDepUnit() : loadBarrier(false), loadBarrierSN(0), storeBarrier(false), @@ -41,8 +43,9 @@ MemDepUnit<MemDepPred, Impl>::MemDepUnit() } template <class MemDepPred, class Impl> -MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params) - : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), +MemDepUnit<MemDepPred, Impl>::MemDepUnit(DerivO3CPUParams *params) + : _name(params->name + ".memdepunit"), + depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) { DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n"); @@ -74,18 +77,12 @@ MemDepUnit<MemDepPred, Impl>::~MemDepUnit() } 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) +MemDepUnit<MemDepPred, Impl>::init(DerivO3CPUParams *params, int tid) { DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); + _name = csprintf("%s.memDep%d", params->name, tid); id = tid; depPred.init(params->SSITSize, params->LFSTSize); @@ -96,19 +93,19 @@ void MemDepUnit<MemDepPred, Impl>::regStats() { insertedLoads - .name(name() + ".memDep.insertedLoads") + .name(name() + ".insertedLoads") .desc("Number of loads inserted to the mem dependence unit."); insertedStores - .name(name() + ".memDep.insertedStores") + .name(name() + ".insertedStores") .desc("Number of stores inserted to the mem dependence unit."); conflictingLoads - .name(name() + ".memDep.conflictingLoads") + .name(name() + ".conflictingLoads") .desc("Number of conflicting loads."); conflictingStores - .name(name() + ".memDep.conflictingStores") + .name(name() + ".conflictingStores") .desc("Number of conflicting stores."); } diff --git a/src/cpu/o3/mips/cpu.cc b/src/cpu/o3/mips/cpu.cc deleted file mode 100755 index 420f460b2..000000000 --- a/src/cpu/o3/mips/cpu.cc +++ /dev/null @@ -1,39 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/mips/impl.hh" -#include "cpu/o3/mips/cpu_impl.hh" -#include "cpu/o3/mips/dyn_inst.hh" - -// Force instantiation of MipsO3CPU for all the implemntations that are -// needed. Consider merging this and mips_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (mips_impl.cc?). -template class MipsO3CPU<MipsSimpleImpl>; diff --git a/src/cpu/o3/mips/cpu.hh b/src/cpu/o3/mips/cpu.hh deleted file mode 100755 index 3724ced46..000000000 --- a/src/cpu/o3/mips/cpu.hh +++ /dev/null @@ -1,130 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_CPU_HH__ -#define __CPU_O3_MIPS_CPU_HH__ - -#include "arch/mips/regfile.hh" -#include "arch/mips/syscallreturn.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" -#include "sim/faults.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * MipsO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template <class Impl> -class MipsO3CPU : public FullO3CPU<Impl> -{ - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an MipsO3CPU with the given parameters. */ - MipsO3CPU(Params *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, - const TheISA::MiscReg &val, unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_MIPS_CPU_HH__ diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc deleted file mode 100644 index 4690b9804..000000000 --- a/src/cpu/o3/mips/cpu_builder.cc +++ /dev/null @@ -1,182 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include <string> - -#include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/impl.hh" -#include "cpu/o3/mips/params.hh" -#include "cpu/o3/fu_pool.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public MipsO3CPU<MipsSimpleImpl> -{ - public: - DerivO3CPU(MipsSimpleParams *p) - : MipsO3CPU<MipsSimpleImpl>(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ - DerivO3CPU *cpu; - - // 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 >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } - - MipsSimpleParams *params = new MipsSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->workload = workload; - -#if USE_CHECKER - params->checker = checker; -#endif - - 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->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->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - 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; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; - else - 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 DerivO3CPU(params); - - return cpu; -} diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh deleted file mode 100644 index 09d73b4a2..000000000 --- a/src/cpu/o3/mips/cpu_impl.hh +++ /dev/null @@ -1,217 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include "config/use_checker.hh" - -#include "arch/mips/faults.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/params.hh" -#include "cpu/o3/mips/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -template <class Impl> -MipsO3CPU<Impl>::MipsO3CPU(Params *params) - : FullO3CPU<Impl>(this, params) -{ - DPRINTF(O3CPU, "Creating MipsO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread 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; - } - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - MipsTC<Impl> *mips_tc = - new MipsTC<Impl>; - - tc = mips_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext<MipsTC<Impl> >( - mips_tc, this->checker); - } -#endif - - mips_tc->cpu = this; - mips_tc->thread = this->thread[i]; - - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -MipsO3CPU<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(); -} - - -template <class Impl> -MiscReg -MipsO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template <class Impl> -MiscReg -MipsO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, - unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template <class Impl> -void -MipsO3CPU<Impl>::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[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(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); - - DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2)); -} - -template <class Impl> -TheISA::IntReg -MipsO3CPU<Impl>::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - return this->readArchIntReg(MipsISA::ArgumentReg[i], tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - this->setArchIntReg(MipsISA::ArgumentReg[i], val, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/mips/dyn_inst.cc b/src/cpu/o3/mips/dyn_inst.cc deleted file mode 100755 index 216aa7d2c..000000000 --- a/src/cpu/o3/mips/dyn_inst.cc +++ /dev/null @@ -1,37 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/mips/dyn_inst_impl.hh" -#include "cpu/o3/mips/impl.hh" - -// Force instantiation of MipsDynInst for all the implementations that -// are needed. -template class MipsDynInst<MipsSimpleImpl>; diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh deleted file mode 100755 index b1a29ccf9..000000000 --- a/src/cpu/o3/mips/dyn_inst.hh +++ /dev/null @@ -1,281 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_DYN_INST_HH__ -#define __CPU_O3_MIPS_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific MipsDynInst. 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 MipsDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class MipsDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - /** 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. */ - MipsDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - MipsDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - MipsDynInst(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(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - /** TODO: Use thread number from argument if given, will probably not work for MIPS MT as is */ - MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - MiscReg readMiscReg(int misc_reg, unsigned tid = 0) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0) - { - this->instResult.integer = val; - this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - - /** Calls a syscall. */ - void syscall(int64_t callnum); - - 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 readIntRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(this->_srcRegIdx[idx]); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, - int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, - int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand(const StaticInst *si, int idx, - const MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - uint64_t readRegOtherThread(int misc_reg) - { - panic("MIPS MT not defined for O3 CPU.\n"); - return 0; - } - - void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val) - { - panic("MIPS MT not defined for O3 CPU.\n"); - } - - 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_MIPS_DYN_INST_HH__ - diff --git a/src/cpu/o3/mips/dyn_inst_impl.hh b/src/cpu/o3/mips/dyn_inst_impl.hh deleted file mode 100755 index 7e8697b32..000000000 --- a/src/cpu/o3/mips/dyn_inst_impl.hh +++ /dev/null @@ -1,130 +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. - * - * Authors: Kevin Lim - */ - -#include "cpu/o3/mips/dyn_inst.hh" - -template <class Impl> -MipsDynInst<Impl>::MipsDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -MipsDynInst<Impl>::MipsDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -MipsDynInst<Impl>::MipsDynInst(StaticInstPtr &_staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initVars(); -} - -template <class Impl> -void -MipsDynInst<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++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template <class Impl> -Fault -MipsDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). 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 -MipsDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). 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 -MipsDynInst<Impl>::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -template <class Impl> -void -MipsDynInst<Impl>::syscall(int64_t callnum) -{ - this->cpu->syscall(callnum, this->threadNumber); -} - diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh deleted file mode 100644 index ac7181a19..000000000 --- a/src/cpu/o3/mips/impl.hh +++ /dev/null @@ -1,93 +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. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_IMPL_HH__ -#define __CPU_O3_MIPS_IMPL_HH__ - -#include "arch/mips/isa_traits.hh" - -#include "cpu/o3/mips/params.hh" -#include "cpu/o3/cpu_policy.hh" - - -// Forward declarations. -template <class Impl> -class MipsDynInst; - -template <class Impl> -class MipsO3CPU; - -/** 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 O3CPU, 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 MipsSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<MipsSimpleImpl> CPUPol; - - /** The DynInst type to be used. */ - typedef MipsDynInst<MipsSimpleImpl> 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 O3CPU type to be used. */ - typedef MipsO3CPU<MipsSimpleImpl> O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - /** The Params to be passed to each stage. */ - typedef MipsSimpleParams Params; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef MipsSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_MIPS_IMPL_HH__ diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh index 97846ed16..f0621c5b5 100644 --- a/src/cpu/o3/ras.hh +++ b/src/cpu/o3/ras.hh @@ -71,6 +71,9 @@ class ReturnAddrStack */ void restore(unsigned top_entry_idx, const Addr &restored_target); + bool empty() { return usedEntries == 0; } + + bool full() { return usedEntries == numEntries; } private: /** Increments the top of stack index. */ inline void incrTos() diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh index 75d3fa6eb..53ac2d683 100644 --- a/src/cpu/o3/regfile.hh +++ b/src/cpu/o3/regfile.hh @@ -33,6 +33,7 @@ #define __CPU_O3_REGFILE_HH__ #include "arch/isa_traits.hh" +#include "arch/regfile.hh" #include "arch/types.hh" #include "base/trace.hh" #include "config/full_system.hh" @@ -264,7 +265,7 @@ class PhysRegFile #if FULL_SYSTEM private: - int intrflag; // interrupt flag + int intrflag; // interrupt flag #endif private: diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index b2faffe43..0fdf28b19 100644 --- a/src/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh @@ -36,6 +36,8 @@ #include "base/statistics.hh" #include "base/timebuf.hh" +class DerivO3CPUParams; + /** * DefaultRename handles both single threaded and SMT rename. Its * width is specified by the parameters; each cycle it tries to rename @@ -56,7 +58,6 @@ class DefaultRename typedef typename Impl::CPUPol CPUPol; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; // Typedefs from the CPUPol typedef typename CPUPol::DecodeStruct DecodeStruct; @@ -107,7 +108,7 @@ class DefaultRename public: /** DefaultRename constructor. */ - DefaultRename(O3CPU *_cpu, Params *params); + DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of rename. */ std::string name() const; @@ -440,44 +441,44 @@ class DefaultRename inline void incrFullStat(const FullSource &source); /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> renameSquashCycles; + Stats::Scalar renameSquashCycles; /** Stat for total number of cycles spent idle. */ - Stats::Scalar<> renameIdleCycles; + Stats::Scalar renameIdleCycles; /** Stat for total number of cycles spent blocking. */ - Stats::Scalar<> renameBlockCycles; + Stats::Scalar renameBlockCycles; /** Stat for total number of cycles spent stalling for a serializing inst. */ - Stats::Scalar<> renameSerializeStallCycles; + Stats::Scalar renameSerializeStallCycles; /** Stat for total number of cycles spent running normally. */ - Stats::Scalar<> renameRunCycles; + Stats::Scalar renameRunCycles; /** Stat for total number of cycles spent unblocking. */ - Stats::Scalar<> renameUnblockCycles; + Stats::Scalar renameUnblockCycles; /** Stat for total number of renamed instructions. */ - Stats::Scalar<> renameRenamedInsts; + Stats::Scalar renameRenamedInsts; /** Stat for total number of squashed instructions that rename discards. */ - Stats::Scalar<> renameSquashedInsts; + Stats::Scalar renameSquashedInsts; /** Stat for total number of times that the ROB starts a stall in rename. */ - Stats::Scalar<> renameROBFullEvents; + Stats::Scalar renameROBFullEvents; /** Stat for total number of times that the IQ starts a stall in rename. */ - Stats::Scalar<> renameIQFullEvents; + Stats::Scalar renameIQFullEvents; /** Stat for total number of times that the LSQ starts a stall in rename. */ - Stats::Scalar<> renameLSQFullEvents; + Stats::Scalar renameLSQFullEvents; /** Stat for total number of times that rename runs out of free registers * to use to rename. */ - Stats::Scalar<> renameFullRegistersEvents; + Stats::Scalar renameFullRegistersEvents; /** Stat for total number of renamed destination registers. */ - Stats::Scalar<> renameRenamedOperands; + Stats::Scalar renameRenamedOperands; /** Stat for total number of source register rename lookups. */ - Stats::Scalar<> renameRenameLookups; + Stats::Scalar renameRenameLookups; /** Stat for total number of committed renaming mappings. */ - Stats::Scalar<> renameCommittedMaps; + Stats::Scalar renameCommittedMaps; /** Stat for total number of mappings that were undone due to a squash. */ - Stats::Scalar<> renameUndoneMaps; + Stats::Scalar renameUndoneMaps; /** Number of serialize instructions handled. */ - Stats::Scalar<> renamedSerializing; + Stats::Scalar renamedSerializing; /** Number of instructions marked as temporarily serializing. */ - Stats::Scalar<> renamedTempSerializing; + Stats::Scalar renamedTempSerializing; /** Number of instructions inserted into skid buffers. */ - Stats::Scalar<> renameSkidInsts; + Stats::Scalar renameSkidInsts; }; #endif // __CPU_O3_RENAME_HH__ diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index 49c885753..81647b133 100644 --- a/src/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh @@ -35,9 +35,10 @@ #include "arch/regfile.hh" #include "config/full_system.hh" #include "cpu/o3/rename.hh" +#include "params/DerivO3CPU.hh" template <class Impl> -DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params) +DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), iewToRenameDelay(params->iewToRenameDelay), decodeToRenameDelay(params->decodeToRenameDelay), @@ -46,7 +47,7 @@ DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params) commitWidth(params->commitWidth), resumeSerialize(false), resumeUnblocking(false), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs) { _status = Inactive; diff --git a/src/cpu/o3/sparc/cpu.cc b/src/cpu/o3/sparc/cpu.cc deleted file mode 100644 index 1546a2b88..000000000 --- a/src/cpu/o3/sparc/cpu.cc +++ /dev/null @@ -1,38 +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. - * - * Authors: Gabe Black - */ - -#include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/sparc/cpu_impl.hh" -#include "cpu/o3/sparc/dyn_inst.hh" - -// Force instantiation of SparcO3CPU for all the implementations that are -// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (sparc_impl.cc?). -template class SparcO3CPU<SparcSimpleImpl>; diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh deleted file mode 100644 index 3fd193e0f..000000000 --- a/src/cpu/o3/sparc/cpu.hh +++ /dev/null @@ -1,148 +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. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_SPARC_CPU_HH__ -#define __CPU_O3_SPARC_CPU_HH__ - -#include "arch/sparc/regfile.hh" -#include "arch/sparc/types.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * SparcO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template <class Impl> -class SparcO3CPU : public FullO3CPU<Impl> -{ - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaO3CPU with the given parameters. */ - SparcO3CPU(Params *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - -#if FULL_SYSTEM - /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - - bool simPalCheck(int palFunc, unsigned tid); - - /** Returns the Fault for any valid interrupt. */ - Fault getInterrupts(); - - /** Processes any an interrupt fault. */ - void processInterrupts(Fault interrupt); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_SPARC_CPU_HH__ diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc deleted file mode 100644 index b08845b4e..000000000 --- a/src/cpu/o3/sparc/cpu_builder.cc +++ /dev/null @@ -1,200 +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. - * - * Authors: Gabe Black - */ - -#include <string> - -#include "config/full_system.hh" -#include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/sparc/params.hh" -#include "cpu/o3/fu_pool.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public SparcO3CPU<SparcSimpleImpl> -{ - public: - DerivO3CPU(SparcSimpleParams *p) - : SparcO3CPU<SparcSimpleImpl>(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ - DerivO3CPU *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 >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - SparcSimpleParams *params = new SparcSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->itb = itb; - params->dtb = dtb; - - params->system = system; -#if FULL_SYSTEM - params->profile = profile; - - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else - params->workload = workload; -#endif // FULL_SYSTEM - -#if USE_CHECKER - params->checker = checker; -#endif - - 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->progress_interval = progress_interval; - - // - // Caches - // - 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->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - 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; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; - else - 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 DerivO3CPU(params); - - return cpu; -} diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh deleted file mode 100644 index 068057fc0..000000000 --- a/src/cpu/o3/sparc/cpu_impl.hh +++ /dev/null @@ -1,298 +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. - * - * Authors: Gabe Black - */ - -#include "config/use_checker.hh" - -#include "arch/sparc/faults.hh" -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/miscregfile.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/params.hh" -#include "cpu/o3/sparc/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/kernel_stats.hh" -#include "cpu/quiesce_event.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#endif - -template <class Impl> -SparcO3CPU<Impl>::SparcO3CPU(Params *params) : FullO3CPU<Impl>(this, params) -{ - DPRINTF(O3CPU, "Creating SparcO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - // SMT is not supported in FS mode yet. - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0); - this->thread[i]->setStatus(ThreadContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread 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 - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - SparcTC<Impl> *sparc_tc = new SparcTC<Impl>; - - tc = sparc_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext<SparcTC<Impl> >( - sparc_tc, this->checker); - } -#endif - - sparc_tc->cpu = this; - sparc_tc->thread = this->thread[i]; - -#if FULL_SYSTEM - // Setup quiesce event. - this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); -#endif - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -SparcO3CPU<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(); -} - - -template <class Impl> -TheISA::MiscReg -SparcO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template <class Impl> -TheISA::MiscReg -SparcO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, - const SparcISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::setMiscReg(int misc_reg, - const SparcISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -SparcO3CPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - -template <class Impl> -Fault -SparcO3CPU<Impl>::hwrei(unsigned tid) -{ - panic("This doesn't make sense for SPARC\n"); - return NoFault; -} - -template <class Impl> -bool -SparcO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - panic("This doesn't make sense for SPARC\n"); - return true; -} - -template <class Impl> -Fault -SparcO3CPU<Impl>::getInterrupts() -{ - // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); -} - -template <class Impl> -void -SparcO3CPU<Impl>::processInterrupts(Fault interrupt) -{ - // 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. - - assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); - - DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); - this->trap(interrupt, 0); -} - -#endif // FULL_SYSTEM - -template <class Impl> -void -SparcO3CPU<Impl>::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template <class Impl> -void -SparcO3CPU<Impl>::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[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(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -SparcO3CPU<Impl>::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - SparcISA::ArgumentReg[i]); - TheISA::IntReg val = this->readArchIntReg(idx, tid); - if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3)) - val = bits(val, 31, 0); - return val; -} - -template <class Impl> -void -SparcO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - SparcISA::ArgumentReg[i]); - this->setArchIntReg(idx, val, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh deleted file mode 100644 index a7ab6cd79..000000000 --- a/src/cpu/o3/sparc/dyn_inst.hh +++ /dev/null @@ -1,265 +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. - * - * Authors: Gabe Black - */ - -#ifndef __CPU_O3_SPARC_DYN_INST_HH__ -#define __CPU_O3_SPARC_DYN_INST_HH__ - -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/types.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific SparcDynInst. 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 SparcDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class SparcDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - public: - /** BaseDynInst constructor given a binary instruction. */ - SparcDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - SparcDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - SparcDynInst(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(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, - int idx, const TheISA::MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand( - const StaticInst *si, int idx, const TheISA::MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(int64_t callnum); -#endif - - 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 readIntRegOperand(const StaticInst *si, int idx) - { - uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]); - DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val); - return val; - } - - TheISA::FloatReg readFloatRegOperand(const StaticInst *si, - int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - TheISA::FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, - int idx, int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val); - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, - TheISA::FloatReg val, int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, TheISA::FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - TheISA::FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, - int idx, TheISA::FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - 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_SPARC_DYN_INST_HH__ - diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh deleted file mode 100644 index 6bfe97717..000000000 --- a/src/cpu/o3/sparc/dyn_inst_impl.hh +++ /dev/null @@ -1,154 +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. - * - * Authors: Gabe Black - */ - -#include "cpu/o3/sparc/dyn_inst.hh" - -template <class Impl> -SparcDynInst<Impl>::SparcDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -SparcDynInst<Impl>::SparcDynInst(StaticInstPtr &_staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initVars(); -} - -template <class Impl> -void -SparcDynInst<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++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template <class Impl> -Fault -SparcDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). 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 -SparcDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). 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 -SparcDynInst<Impl>::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -#if FULL_SYSTEM -template <class Impl> -Fault -SparcDynInst<Impl>::hwrei() -{ - return NoFault; -} - -template <class Impl> -void -SparcDynInst<Impl>::trap(Fault fault) -{ - this->cpu->trap(fault, this->threadNumber); -} - -template <class Impl> -bool -SparcDynInst<Impl>::simPalCheck(int palFunc) -{ - panic("simPalCheck called, but there's no PAL in SPARC!\n"); - return false; -} -#else -template <class Impl> -void -SparcDynInst<Impl>::syscall(int64_t callnum) -{ - this->cpu->syscall(callnum, this->threadNumber); -} -#endif - diff --git a/src/cpu/o3/alpha/thread_context.cc b/src/cpu/o3/thread_context.cc index 4a02715bc..0d8c67643 100755 --- a/src/cpu/o3/alpha/thread_context.cc +++ b/src/cpu/o3/thread_context.cc @@ -26,11 +26,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim - * Korey Sewell */ #include "cpu/o3/thread_context.hh" #include "cpu/o3/thread_context_impl.hh" +#include "cpu/o3/impl.hh" -template class O3ThreadContext<AlphaSimpleImpl>; +template class O3ThreadContext<O3CPUImpl>; diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index e7bdc6de5..f3058925d 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -75,16 +75,21 @@ class O3ThreadContext : public ThreadContext /** Returns a pointer to this CPU. */ virtual BaseCPU *getCpuPtr() { return cpu; } - /** Sets this CPU's ID. */ - virtual void setCpuId(int id) { cpu->setCpuId(id); } - /** Reads this CPU's ID. */ - virtual int readCpuId() { return cpu->readCpuId(); } + virtual int cpuId() { return cpu->cpuId(); } + + virtual int contextId() { return thread->contextId(); } + + virtual void setContextId(int id) { thread->setContextId(id); } + + /** Returns this thread's ID number. */ + virtual int threadId() { return thread->threadId(); } + virtual void setThreadId(int id) { return thread->setThreadId(id); } -#if FULL_SYSTEM /** Returns a pointer to the system. */ virtual System *getSystemPtr() { return cpu->system; } +#if FULL_SYSTEM /** Returns a pointer to physical memory. */ virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } @@ -94,11 +99,9 @@ class O3ThreadContext : public ThreadContext virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); } - virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL); - - void delVirtPort(VirtualPort *vp); + virtual VirtualPort *getVirtPort(); - virtual void connectMemPorts() { thread->connectMemPorts(); } + virtual void connectMemPorts(ThreadContext *tc) { thread->connectMemPorts(tc); } #else virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } @@ -153,9 +156,6 @@ class O3ThreadContext : public ThreadContext /** Samples the function profiling information. */ virtual void profileSample(); #endif - /** Returns this thread's ID number. */ - virtual int getThreadNum() { return thread->readTid(); } - /** Returns the instruction this thread is currently committing. * Only used when an instruction faults. */ @@ -191,36 +191,36 @@ class O3ThreadContext : public ThreadContext /** Reads this thread's PC. */ virtual uint64_t readPC() - { return cpu->readPC(thread->readTid()); } + { return cpu->readPC(thread->threadId()); } /** Sets this thread's PC. */ virtual void setPC(uint64_t val); /** Reads this thread's next PC. */ virtual uint64_t readNextPC() - { return cpu->readNextPC(thread->readTid()); } + { return cpu->readNextPC(thread->threadId()); } /** Sets this thread's next PC. */ virtual void setNextPC(uint64_t val); virtual uint64_t readMicroPC() - { return cpu->readMicroPC(thread->readTid()); } + { return cpu->readMicroPC(thread->threadId()); } virtual void setMicroPC(uint64_t val); virtual uint64_t readNextMicroPC() - { return cpu->readNextMicroPC(thread->readTid()); } + { return cpu->readNextMicroPC(thread->threadId()); } virtual void setNextMicroPC(uint64_t val); /** Reads a miscellaneous register. */ virtual MiscReg readMiscRegNoEffect(int misc_reg) - { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); } + { return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); } /** Reads a misc. register, including any side-effects the * read might have as defined by the architecture. */ virtual MiscReg readMiscReg(int misc_reg) - { return cpu->readMiscReg(misc_reg, thread->readTid()); } + { return cpu->readMiscReg(misc_reg, thread->threadId()); } /** Sets a misc. register. */ virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val); @@ -247,22 +247,48 @@ class O3ThreadContext : public ThreadContext virtual bool misspeculating() { return false; } #if !FULL_SYSTEM - /** Gets a syscall argument by index. */ - virtual IntReg getSyscallArg(int i); - - /** Sets a syscall argument. */ - virtual void setSyscallArg(int i, IntReg val); - - /** Sets the syscall return value. */ - virtual void setSyscallReturn(SyscallReturn return_value); - /** Executes a syscall in SE mode. */ virtual void syscall(int64_t callnum) - { return cpu->syscall(callnum, thread->readTid()); } + { return cpu->syscall(callnum, thread->threadId()); } /** Reads the funcExeInst counter. */ virtual Counter readFuncExeInst() { return thread->funcExeInst; } +#else + /** Returns pointer to the quiesce event. */ + virtual EndQuiesceEvent *getQuiesceEvent() + { + return this->thread->quiesceEvent; + } #endif + + virtual uint64_t readNextNPC() + { + return this->cpu->readNextNPC(this->thread->threadId()); + } + + virtual void setNextNPC(uint64_t val) + { +#if THE_ISA == ALPHA_ISA + panic("Not supported on Alpha!"); +#endif + this->cpu->setNextNPC(val, this->thread->threadId()); + } + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system + if (this->cpu->numActiveThreads()) + return 0; // don't exit simulation + else + return 1; // exit simulation + } }; #endif diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 865d58635..fc8b66b83 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -36,16 +36,9 @@ #if FULL_SYSTEM template <class Impl> VirtualPort * -O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc) +O3ThreadContext<Impl>::getVirtPort() { - if (!src_tc) - return thread->getVirtPort(); - - VirtualPort *vp; - - vp = new VirtualPort("tc-vport", src_tc); - thread->connectToMemFunc(vp); - return vp; + return thread->getVirtPort(); } template <class Impl> @@ -61,16 +54,16 @@ void O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context) { // some things should already be set up -#if FULL_SYSTEM assert(getSystemPtr() == old_context->getSystemPtr()); -#else +#if !FULL_SYSTEM assert(getProcessPtr() == old_context->getProcessPtr()); #endif // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); + setContextId(old_context->contextId()); + setThreadId(old_context->threadId()); #if !FULL_SYSTEM thread->funcExeInst = old_context->readFuncExeInst(); @@ -97,24 +90,12 @@ O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context) thread->trapPending = false; } -#if FULL_SYSTEM -template <class Impl> -void -O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp) -{ - if (vp != thread->getVirtPort()) { - vp->removeConn(); - delete vp; - } -} -#endif - template <class Impl> void O3ThreadContext<Impl>::activate(int delay) { DPRINTF(O3CPU, "Calling activate on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Active) return; @@ -124,14 +105,14 @@ O3ThreadContext<Impl>::activate(int delay) #endif if (thread->status() == ThreadContext::Unallocated) { - cpu->activateWhenReady(thread->readTid()); + cpu->activateWhenReady(thread->threadId()); return; } thread->setStatus(ThreadContext::Active); // status() == Suspended - cpu->activateContext(thread->readTid(), delay); + cpu->activateContext(thread->threadId(), delay); } template <class Impl> @@ -139,7 +120,7 @@ void O3ThreadContext<Impl>::suspend(int delay) { DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Suspended) return; @@ -151,14 +132,14 @@ O3ThreadContext<Impl>::suspend(int delay) /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { + if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } #endif */ thread->setStatus(ThreadContext::Suspended); - cpu->suspendContext(thread->readTid()); + cpu->suspendContext(thread->threadId()); } template <class Impl> @@ -166,13 +147,13 @@ void O3ThreadContext<Impl>::deallocate(int delay) { DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n", - getThreadNum(), delay); + threadId(), delay); if (thread->status() == ThreadContext::Unallocated) return; thread->setStatus(ThreadContext::Unallocated); - cpu->deallocateContext(thread->readTid(), true, delay); + cpu->deallocateContext(thread->threadId(), true, delay); } template <class Impl> @@ -180,13 +161,13 @@ void O3ThreadContext<Impl>::halt(int delay) { DPRINTF(O3CPU, "Calling halt on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Halted) return; thread->setStatus(ThreadContext::Halted); - cpu->haltContext(thread->readTid()); + cpu->haltContext(thread->threadId()); } template <class Impl> @@ -264,7 +245,7 @@ O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc) { // This function will mess things up unless the ROB is empty and // there are no instructions in the pipeline. - unsigned tid = thread->readTid(); + unsigned tid = thread->threadId(); PhysRegIndex renamed_reg; // First loop through the integer registers. @@ -311,7 +292,7 @@ uint64_t O3ThreadContext<Impl>::readIntReg(int reg_idx) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); - return cpu->readArchIntReg(reg_idx, thread->readTid()); + return cpu->readArchIntReg(reg_idx, thread->threadId()); } template <class Impl> @@ -321,9 +302,9 @@ O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width) reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: - return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); case 64: - return cpu->readArchFloatRegDouble(reg_idx, thread->readTid()); + return cpu->readArchFloatRegDouble(reg_idx, thread->threadId()); default: panic("Unsupported width!"); return 0; @@ -335,7 +316,7 @@ TheISA::FloatReg O3ThreadContext<Impl>::readFloatReg(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); } template <class Impl> @@ -344,7 +325,7 @@ O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width) { DPRINTF(Fault, "Reading floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); + return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template <class Impl> @@ -352,7 +333,7 @@ TheISA::FloatRegBits O3ThreadContext<Impl>::readFloatRegBits(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); + return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template <class Impl> @@ -360,11 +341,11 @@ void O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); - cpu->setArchIntReg(reg_idx, val, thread->readTid()); + cpu->setArchIntReg(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -375,16 +356,16 @@ O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: - cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); break; case 64: - cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegDouble(reg_idx, val, thread->threadId()); break; } // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -393,10 +374,10 @@ void O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -407,11 +388,11 @@ O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, { DPRINTF(Fault, "Setting floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -420,11 +401,11 @@ void O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -432,11 +413,11 @@ template <class Impl> void O3ThreadContext<Impl>::setPC(uint64_t val) { - cpu->setPC(val, thread->readTid()); + cpu->setPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -444,11 +425,11 @@ template <class Impl> void O3ThreadContext<Impl>::setNextPC(uint64_t val) { - cpu->setNextPC(val, thread->readTid()); + cpu->setNextPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -456,11 +437,11 @@ template <class Impl> void O3ThreadContext<Impl>::setMicroPC(uint64_t val) { - cpu->setMicroPC(val, thread->readTid()); + cpu->setMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -468,11 +449,11 @@ template <class Impl> void O3ThreadContext<Impl>::setNextMicroPC(uint64_t val) { - cpu->setNextMicroPC(val, thread->readTid()); + cpu->setNextMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -480,11 +461,11 @@ template <class Impl> void O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val) { - cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); + cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -493,36 +474,11 @@ void O3ThreadContext<Impl>::setMiscReg(int misc_reg, const MiscReg &val) { - cpu->setMiscReg(misc_reg, val, thread->readTid()); + cpu->setMiscReg(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } -#if !FULL_SYSTEM - -template <class Impl> -TheISA::IntReg -O3ThreadContext<Impl>::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->readTid()); -} - -template <class Impl> -void -O3ThreadContext<Impl>::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->readTid()); -} - -template <class Impl> -void -O3ThreadContext<Impl>::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->readTid()); -} - -#endif // FULL_SYSTEM - diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh index d8720b3ab..1f0e7a3bb 100644 --- a/src/cpu/o3/thread_state.hh +++ b/src/cpu/o3/thread_state.hh @@ -77,11 +77,11 @@ struct O3ThreadState : public ThreadState { #if FULL_SYSTEM O3ThreadState(O3CPU *_cpu, int _thread_num) - : ThreadState(_cpu, -1, _thread_num), + : ThreadState(_cpu, _thread_num), cpu(_cpu), inSyscall(0), trapPending(0) { - if (cpu->params->profile) { - profile = new FunctionProfile(cpu->params->system->kernelSymtab); + if (cpu->params()->profile) { + profile = new FunctionProfile(cpu->params()->system->kernelSymtab); Callback *cb = new MakeCallback<O3ThreadState, &O3ThreadState::dumpFuncProfile>(this); @@ -96,7 +96,7 @@ struct O3ThreadState : public ThreadState { } #else O3ThreadState(O3CPU *_cpu, int _thread_num, Process *_process, int _asid) - : ThreadState(_cpu, -1, _thread_num, _process, _asid), + : ThreadState(_cpu, _thread_num, _process, _asid), cpu(_cpu), inSyscall(0), trapPending(0) { } #endif diff --git a/src/cpu/ozone/OzoneCPU.py b/src/cpu/ozone/OzoneCPU.py index b9cfb448f..37386898d 100644 --- a/src/cpu/ozone/OzoneCPU.py +++ b/src/cpu/ozone/OzoneCPU.py @@ -40,8 +40,6 @@ class DerivOzoneCPU(BaseCPU): if build_env['USE_CHECKER']: checker = Param.BaseCPU("Checker CPU") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") diff --git a/src/cpu/ozone/OzoneChecker.py b/src/cpu/ozone/OzoneChecker.py index f20b8770e..bfa39ead9 100644 --- a/src/cpu/ozone/OzoneChecker.py +++ b/src/cpu/ozone/OzoneChecker.py @@ -39,5 +39,3 @@ class OzoneChecker(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh index 4cdc86c3c..ca858ce2e 100644 --- a/src/cpu/ozone/back_end.hh +++ b/src/cpu/ozone/back_end.hh @@ -157,13 +157,13 @@ class BackEnd int numInsts; int width; - Stats::VectorDistribution<> occ_dist; + Stats::VectorDistribution occ_dist; - Stats::Vector<> inst_count; - Stats::Vector<> peak_inst_count; - Stats::Scalar<> empty_count; - Stats::Scalar<> current_count; - Stats::Scalar<> fullCount; + Stats::Vector inst_count; + Stats::Vector peak_inst_count; + Stats::Scalar empty_count; + Stats::Scalar current_count; + Stats::Scalar fullCount; Stats::Formula occ_rate; Stats::Formula avg_residency; @@ -371,45 +371,45 @@ class BackEnd bool fetchRedirect[Impl::MaxThreads]; // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; +/* Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; */ - Stats::Vector<> rob_cap_events; - Stats::Vector<> rob_cap_inst_count; - Stats::Vector<> iq_cap_events; - Stats::Vector<> iq_cap_inst_count; + Stats::Vector rob_cap_events; + Stats::Vector rob_cap_inst_count; + Stats::Vector iq_cap_events; + Stats::Vector iq_cap_inst_count; // total number of instructions executed - Stats::Vector<> exe_inst; - Stats::Vector<> exe_swp; - Stats::Vector<> exe_nop; - Stats::Vector<> exe_refs; - Stats::Vector<> exe_loads; - Stats::Vector<> exe_branches; + Stats::Vector exe_inst; + Stats::Vector exe_swp; + Stats::Vector exe_nop; + Stats::Vector exe_refs; + Stats::Vector exe_loads; + Stats::Vector exe_branches; - Stats::Vector<> issued_ops; + Stats::Vector issued_ops; // total number of loads forwaded from LSQ stores - Stats::Vector<> lsq_forw_loads; + Stats::Vector lsq_forw_loads; // total number of loads ignored due to invalid addresses - Stats::Vector<> inv_addr_loads; + Stats::Vector inv_addr_loads; // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> inv_addr_swpfs; + Stats::Vector inv_addr_swpfs; // ready loads blocked due to memory disambiguation - Stats::Vector<> lsq_blocked_loads; + Stats::Vector lsq_blocked_loads; - Stats::Scalar<> lsqInversion; + Stats::Scalar lsqInversion; - Stats::Vector<> n_issued_dist; - Stats::VectorDistribution<> issue_delay_dist; + Stats::Vector n_issued_dist; + Stats::VectorDistribution issue_delay_dist; - Stats::VectorDistribution<> queue_res_dist; + Stats::VectorDistribution queue_res_dist; /* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; + Stats::Vector stat_fu_busy; + Stats::Vector2d stat_fuBusy; + Stats::Vector dist_unissued; + Stats::Vector2d stat_issued_inst_type; Stats::Formula misspec_cnt; Stats::Formula misspec_ipc; @@ -422,34 +422,34 @@ class BackEnd Stats::Formula commit_ipb; Stats::Formula lsq_inv_rate; */ - Stats::Vector<> writeback_count; - Stats::Vector<> producer_inst; - Stats::Vector<> consumer_inst; - Stats::Vector<> wb_penalized; + Stats::Vector writeback_count; + Stats::Vector producer_inst; + Stats::Vector consumer_inst; + Stats::Vector wb_penalized; Stats::Formula wb_rate; Stats::Formula wb_fanout; Stats::Formula wb_penalized_rate; // total number of instructions committed - Stats::Vector<> stat_com_inst; - Stats::Vector<> stat_com_swp; - Stats::Vector<> stat_com_refs; - Stats::Vector<> stat_com_loads; - Stats::Vector<> stat_com_membars; - Stats::Vector<> stat_com_branches; + Stats::Vector stat_com_inst; + Stats::Vector stat_com_swp; + Stats::Vector stat_com_refs; + Stats::Vector stat_com_loads; + Stats::Vector stat_com_membars; + Stats::Vector stat_com_branches; - Stats::Distribution<> n_committed_dist; + Stats::Distribution n_committed_dist; - Stats::Scalar<> commit_eligible_samples; - Stats::Vector<> commit_eligible; + Stats::Scalar commit_eligible_samples; + Stats::Vector commit_eligible; - Stats::Scalar<> ROB_fcount; + Stats::Scalar ROB_fcount; Stats::Formula ROB_full_rate; - Stats::Vector<> ROB_count; // cumulative ROB occupancy + Stats::Vector ROB_count; // cumulative ROB occupancy Stats::Formula ROB_occ_rate; - Stats::VectorDistribution<> ROB_occ_dist; + Stats::VectorDistribution ROB_occ_dist; public: void dumpInsts(); }; @@ -482,8 +482,8 @@ BackEnd<Impl>::read(RequestPtr req, T &data, int load_idx) memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; +// unscheduleTickEvent(); +// status = DcacheMissStall; DPRINTF(OzoneCPU, "Dcache miss stall!\n"); } else { // do functional access @@ -524,8 +524,8 @@ BackEnd<Impl>::write(RequestPtr req, T &data, int store_idx) if (result != MA_HIT && dcacheInterface->doEvents()) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; +// unscheduleTickEvent(); +// status = DcacheMissStall; DPRINTF(OzoneCPU, "Dcache miss stall!\n"); } } diff --git a/src/cpu/ozone/base_dyn_inst.cc b/src/cpu/ozone/base_dyn_inst.cc index 5a3a69dff..e0570fd16 100644 --- a/src/cpu/ozone/base_dyn_inst.cc +++ b/src/cpu/ozone/base_dyn_inst.cc @@ -33,7 +33,3 @@ // Explicit instantiation template class BaseDynInst<OzoneImpl>; - -template <> -int -BaseDynInst<OzoneImpl>::instcount = 0; diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index b0ea2cba9..0bfb4bfa9 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -116,10 +116,6 @@ class OzoneCPU : public BaseCPU BaseCPU *getCpuPtr(); - void setCpuId(int id); - - int readCpuId() { return thread->readCpuId(); } - TheISA::ITB *getITBPtr() { return cpu->itb; } TheISA::DTB * getDTBPtr() { return cpu->dtb; } @@ -134,10 +130,8 @@ class OzoneCPU : public BaseCPU FunctionalPort *getPhysPort() { return thread->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) - { return thread->getVirtPort(tc); } - - void delVirtPort(VirtualPort *vp); + VirtualPort *getVirtPort() + { return thread->getVirtPort(); } #else TranslatingPort *getMemPort() { return thread->getMemPort(); } @@ -182,7 +176,7 @@ class OzoneCPU : public BaseCPU void profileSample(); #endif - int getThreadNum(); + int threadId(); // Also somewhat obnoxious. Really only used for the TLB fault. TheISA::MachInst getInst(); @@ -252,30 +246,11 @@ class OzoneCPU : public BaseCPU bool misspeculating() { return false; } #if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - assert(i < TheISA::NumArgumentRegs); - return thread->renameTable[TheISA::ArgumentReg[i]]->readIntResult(); - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - assert(i < TheISA::NumArgumentRegs); - thread->renameTable[TheISA::ArgumentReg[i]]->setIntResult(i); - } - - void setSyscallReturn(SyscallReturn return_value) - { cpu->setSyscallReturn(return_value, thread->readTid()); } - Counter readFuncExeInst() { return thread->funcExeInst; } void setFuncExeInst(Counter new_val) { thread->funcExeInst = new_val; } #endif - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Alpha!"); } }; // Ozone specific thread context @@ -296,6 +271,11 @@ class OzoneCPU : public BaseCPU // main simulation loop (one cycle) void tick(); +#ifndef NDEBUG + /** Count of total number of dynamic instructions in flight. */ + int instcount; +#endif + std::set<InstSeqNum> snList; std::set<Addr> lockAddrList; private: @@ -337,7 +317,7 @@ class OzoneCPU : public BaseCPU Status _status; public: - void post_interrupt(int int_num, int index); + void wakeup(); void zero_fill_64(Addr addr) { static int warned = 0; @@ -358,12 +338,6 @@ class OzoneCPU : public BaseCPU public: BaseCPU *getCpuPtr() { return this; } - void setCpuId(int id) { cpuId = id; } - - int readCpuId() { return cpuId; } - - int cpuId; - void switchOut(); void signalSwitched(); void takeOverFrom(BaseCPU *oldCPU); @@ -416,7 +390,7 @@ class OzoneCPU : public BaseCPU Counter startNumLoad; // number of idle cycles - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; public: @@ -425,59 +399,20 @@ class OzoneCPU : public BaseCPU void demapPage(Addr vaddr, uint64_t asn) { - itb->demap(vaddr, asn); - dtb->demap(vaddr, asn); + cpu->itb->demap(vaddr, asn); + cpu->dtb->demap(vaddr, asn); } void demapInstPage(Addr vaddr, uint64_t asn) { - itb->demap(vaddr, asn); + cpu->itb->demap(vaddr, asn); } void demapDataPage(Addr vaddr, uint64_t asn) { - dtb->demap(vaddr, asn); - } - -#if FULL_SYSTEM - /** Translates instruction requestion. */ - Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return itb->translate(req, thread->getTC()); - } - - /** Translates data read request. */ - Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return dtb->translate(req, thread->getTC(), false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return dtb->translate(req, thread->getTC(), true); - } - -#else - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return thread->getProcessPtr()->pTable->translate(req); + cpu->dtb->demap(vaddr, asn); } - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } -#endif - /** CPU read function, forwards read to LSQ. */ template <class T> Fault read(Request *req, T &data, int load_idx) @@ -517,7 +452,6 @@ class OzoneCPU : public BaseCPU void processInterrupts(); #else void syscall(uint64_t &callnum); - void setSyscallReturn(SyscallReturn return_value, int tid); #endif ThreadContext *tcBase() { return tc; } @@ -539,7 +473,7 @@ class OzoneCPU : public BaseCPU bool lockFlag; - Stats::Scalar<> quiesceCycles; + Stats::Scalar quiesceCycles; Checker<DynInstPtr> *checker; }; diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 0c7105382..aa76c8aa6 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -95,6 +95,9 @@ OzoneCPU<Impl>::OzoneCPU(Params *p) : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width), #endif +#ifndef NDEBUG + instcount(0), +#endif comm(5, 5) { frontEnd = new FrontEnd(p); @@ -417,7 +420,7 @@ OzoneCPU<Impl>::init() ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, tc->readCpuId()); + TheISA::initCPU(tc, tc->contextId()); } #endif frontEnd->renameTable.copyFrom(thread.renameTable); @@ -579,16 +582,14 @@ OzoneCPU<Impl>::dbg_vtophys(Addr addr) #if FULL_SYSTEM template <class Impl> void -OzoneCPU<Impl>::post_interrupt(int int_num, int index) +OzoneCPU<Impl>::wakeup() { - BaseCPU::post_interrupt(int_num, index); - if (_status == Idle) { DPRINTF(IPI,"Suspended Processor awoke\n"); -// thread.activate(); +// thread.activate(); // Hack for now. Otherwise might have to go through the tc, or // I need to figure out what's the right thing to call. - activateContext(thread.readTid(), 1); + activateContext(thread.threadId(), 1); } } #endif // FULL_SYSTEM @@ -647,26 +648,6 @@ OzoneCPU<Impl>::syscall(uint64_t &callnum) 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 @@ -693,10 +674,10 @@ OzoneCPU<Impl>::processInterrupts() // Check if there are any outstanding interrupts //Handle the interrupts - Fault interrupt = this->interrupts.getInterrupt(thread.getTC()); + Fault interrupt = this->interrupts->getInterrupt(thread.getTC()); if (interrupt != NoFault) { - this->interrupts.updateIntrInfo(thread.getTC()); + this->interrupts->updateIntrInfo(thread.getTC()); interrupt->invoke(thread.getTC()); } } @@ -711,7 +692,7 @@ OzoneCPU<Impl>::simPalCheck(int palFunc) switch (palFunc) { case PAL::halt: - haltContext(thread.readTid()); + haltContext(thread.threadId()); if (--System::numSystemsRunning == 0) exitSimLoop("all cpus halted"); break; @@ -736,24 +717,6 @@ OzoneCPU<Impl>::OzoneTC::getCpuPtr() template <class Impl> void -OzoneCPU<Impl>::OzoneTC::setCpuId(int id) -{ - cpu->cpuId = id; - thread->setCpuId(id); -} - -#if FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp) -{ - vp->removeConn(); - delete vp; -} -#endif - -template <class Impl> -void OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status) { thread->setStatus(new_status); @@ -763,7 +726,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::activate(int delay) { - cpu->activateContext(thread->readTid(), delay); + cpu->activateContext(thread->threadId(), delay); } /// Set the status to Suspended. @@ -771,7 +734,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::suspend() { - cpu->suspendContext(thread->readTid()); + cpu->suspendContext(thread->threadId()); } /// Set the status to Unallocated. @@ -779,7 +742,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::deallocate(int delay) { - cpu->deallocateContext(thread->readTid(), delay); + cpu->deallocateContext(thread->threadId(), delay); } /// Set the status to Halted. @@ -787,7 +750,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::halt() { - cpu->haltContext(thread->readTid()); + cpu->haltContext(thread->threadId()); } #if FULL_SYSTEM @@ -813,7 +776,8 @@ OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context) // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); + setCpuId(old_context->cpuId()); + setContextId(old_context->contextId()); thread->setInst(old_context->getInst()); #if !FULL_SYSTEM @@ -901,9 +865,9 @@ OzoneCPU<Impl>::OzoneTC::profileSample() template <class Impl> int -OzoneCPU<Impl>::OzoneTC::getThreadNum() +OzoneCPU<Impl>::OzoneTC::threadId() { - return thread->readTid(); + return thread->threadId(); } template <class Impl> diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh index 667392c06..38fc89e3f 100644 --- a/src/cpu/ozone/front_end.hh +++ b/src/cpu/ozone/front_end.hh @@ -275,48 +275,48 @@ class FrontEnd private: // number of idle cycles /* - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; */ // @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; + Stats::Scalar icacheStallCycles; /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; - Stats::Scalar<> fetchedBranches; + Stats::Scalar fetchedInsts; + Stats::Scalar fetchedBranches; /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; + Stats::Scalar predictedBranches; /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; + Stats::Scalar fetchCycles; - Stats::Scalar<> fetchIdleCycles; + Stats::Scalar fetchIdleCycles; /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; + Stats::Scalar fetchSquashCycles; /** Stat for total number of cycles spent blocked due to other stages in * the pipeline. */ - Stats::Scalar<> fetchBlockedCycles; + Stats::Scalar fetchBlockedCycles; /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; + Stats::Scalar fetchedCacheLines; - Stats::Scalar<> fetchIcacheSquashes; + Stats::Scalar fetchIcacheSquashes; /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; -// Stats::Vector<> qfull_iq_occupancy; -// Stats::VectorDistribution<> qfull_iq_occ_dist_; + Stats::Distribution fetchNisnDist; +// Stats::Vector qfull_iq_occupancy; +// Stats::VectorDistribution qfull_iq_occ_dist_; Stats::Formula idleRate; Stats::Formula branchRate; Stats::Formula fetchRate; - Stats::Scalar<> IFQCount; // cumulative IFQ occupancy + Stats::Scalar IFQCount; // cumulative IFQ occupancy Stats::Formula IFQOccupancy; Stats::Formula IFQLatency; - Stats::Scalar<> IFQFcount; // cumulative IFQ full count + Stats::Scalar IFQFcount; // cumulative IFQ full count Stats::Formula IFQFullRate; - Stats::Scalar<> dispatchCountStat; - Stats::Scalar<> dispatchedSerializing; - Stats::Scalar<> dispatchedTempSerializing; - Stats::Scalar<> dispatchSerializeStallCycles; + Stats::Scalar dispatchCountStat; + Stats::Scalar dispatchedSerializing; + Stats::Scalar dispatchedTempSerializing; + Stats::Scalar dispatchSerializeStallCycles; Stats::Formula dispatchRate; Stats::Formula regIntFull; Stats::Formula regFpFull; diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index 198ce0308..6b47ef539 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -477,10 +477,10 @@ FrontEnd<Impl>::fetchCacheLine() // Setup the memReq to do a read of the first isntruction's address. // Set the appropriate read size and flags as well. memReq = new Request(0, fetch_PC, cacheBlkSize, 0, - PC, cpu->readCpuId(), 0); + PC, cpu->thread->contextId()); // Translate the instruction request. - fault = cpu->translateInstReq(memReq, thread); + fault = cpu->itb->translateAtomic(memReq, thread); // Now do the timing access to see whether or not the instruction // exists within the cache. diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh index aef29b1e2..e930144be 100644 --- a/src/cpu/ozone/inorder_back_end.hh +++ b/src/cpu/ozone/inorder_back_end.hh @@ -192,7 +192,7 @@ class InorderBackEnd TimeBuffer<CommStruct> *comm; // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; + Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; }; @@ -204,7 +204,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->translateDataReadReq(memReq); + Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), false); // if we have a cache, do cache access too if (fault == NoFault && dcacheInterface) { @@ -222,7 +222,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags) // are executed twice. memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { @@ -245,11 +245,11 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->translateDataWriteReq(memReq); + Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), true); if (fault == NoFault && dcacheInterface) { memReq->cmd = Write; -// memcpy(memReq->data,(uint8_t *)&data,memReq->size); +// memcpy(memReq->data,(uint8_t *)&data,memReq->size); memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; @@ -261,7 +261,7 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) if (result != MA_HIT) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { @@ -307,7 +307,7 @@ InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx) if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss load stall!\n"); } else { @@ -372,7 +372,7 @@ InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx) if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss store stall!\n"); } else { diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh index cf8634a42..798b628d6 100644 --- a/src/cpu/ozone/inorder_back_end_impl.hh +++ b/src/cpu/ozone/inorder_back_end_impl.hh @@ -149,8 +149,7 @@ InorderBackEnd<Impl>::tick() // if (interrupt) then set thread PC, stall front end, record that // I'm waiting for it to drain. (for now just squash) #if FULL_SYSTEM - if (interruptBlocked || - cpu->check_interrupts(tc)) { + if (interruptBlocked || cpu->checkInterrupts(tc)) { if (!robEmpty()) { interruptBlocked = true; //AlphaDep diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh index a11d5204b..e840d5c21 100644 --- a/src/cpu/ozone/inst_queue.hh +++ b/src/cpu/ozone/inst_queue.hh @@ -473,35 +473,35 @@ class InstQueue void dumpInsts(); /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; + Stats::Scalar iqInstsAdded; /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; -// Stats::Scalar<> iqIntInstsAdded; + Stats::Scalar iqNonSpecInstsAdded; +// Stats::Scalar iqIntInstsAdded; /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; -// Stats::Scalar<> iqFloatInstsAdded; + Stats::Scalar iqIntInstsIssued; +// Stats::Scalar iqFloatInstsAdded; /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; -// Stats::Scalar<> iqBranchInstsAdded; + Stats::Scalar iqFloatInstsIssued; +// Stats::Scalar iqBranchInstsAdded; /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; -// Stats::Scalar<> iqMemInstsAdded; + Stats::Scalar iqBranchInstsIssued; +// Stats::Scalar iqMemInstsAdded; /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; -// Stats::Scalar<> iqMiscInstsAdded; + Stats::Scalar iqMemInstsIssued; +// Stats::Scalar iqMiscInstsAdded; /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; + Stats::Scalar iqMiscInstsIssued; /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; + Stats::Scalar iqSquashedInstsIssued; /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; + Stats::Scalar iqSquashedInstsExamined; /** Stat for number of squashed instruction operands examined when * squashing. */ - Stats::Scalar<> iqSquashedOperandsExamined; + Stats::Scalar iqSquashedOperandsExamined; /** Stat for number of non-speculative instructions removed due to a squash. */ - Stats::Scalar<> iqSquashedNonSpecRemoved; + Stats::Scalar iqSquashedNonSpecRemoved; }; diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh index 981682c26..47be245e5 100644 --- a/src/cpu/ozone/lsq_unit.hh +++ b/src/cpu/ozone/lsq_unit.hh @@ -331,7 +331,7 @@ class OzoneLSQ { //list<InstSeqNum> mshrSeqNums; - //Stats::Scalar<> dcacheStallCycles; + //Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; /** Wire to read information from the issue stage time queue. */ diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh index 84a90eede..c24410520 100644 --- a/src/cpu/ozone/lsq_unit_impl.hh +++ b/src/cpu/ozone/lsq_unit_impl.hh @@ -553,7 +553,7 @@ OzoneLSQ<Impl>::writebackStores() MemReqPtr req = storeQueue[storeWBIdx].req; storeQueue[storeWBIdx].committed = true; -// Fault fault = cpu->translateDataReadReq(req); +// Fault fault = cpu->translateDataReadReq(req); req->cmd = Write; req->completionEvent = NULL; req->time = curTick; diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh index a335ab7dc..4a1657c9b 100644 --- a/src/cpu/ozone/lw_back_end.hh +++ b/src/cpu/ozone/lw_back_end.hh @@ -326,47 +326,47 @@ class LWBackEnd bool exactFullStall; // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; +/* Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; */ - Stats::Vector<> robCapEvents; - Stats::Vector<> robCapInstCount; - Stats::Vector<> iqCapEvents; - Stats::Vector<> iqCapInstCount; + Stats::Vector robCapEvents; + Stats::Vector robCapInstCount; + Stats::Vector iqCapEvents; + Stats::Vector iqCapInstCount; // total number of instructions executed - Stats::Vector<> exeInst; - Stats::Vector<> exeSwp; - Stats::Vector<> exeNop; - Stats::Vector<> exeRefs; - Stats::Vector<> exeLoads; - Stats::Vector<> exeBranches; + Stats::Vector exeInst; + Stats::Vector exeSwp; + Stats::Vector exeNop; + Stats::Vector exeRefs; + Stats::Vector exeLoads; + Stats::Vector exeBranches; - Stats::Vector<> issuedOps; + Stats::Vector issuedOps; // total number of loads forwaded from LSQ stores - Stats::Vector<> lsqForwLoads; + Stats::Vector lsqForwLoads; // total number of loads ignored due to invalid addresses - Stats::Vector<> invAddrLoads; + Stats::Vector invAddrLoads; // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> invAddrSwpfs; + Stats::Vector invAddrSwpfs; // ready loads blocked due to memory disambiguation - Stats::Vector<> lsqBlockedLoads; + Stats::Vector lsqBlockedLoads; - Stats::Scalar<> lsqInversion; + Stats::Scalar lsqInversion; - Stats::Vector<> nIssuedDist; + Stats::Vector nIssuedDist; /* - Stats::VectorDistribution<> issueDelayDist; + Stats::VectorDistribution issueDelayDist; - Stats::VectorDistribution<> queueResDist; + Stats::VectorDistribution queueResDist; */ /* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; + Stats::Vector stat_fu_busy; + Stats::Vector2d stat_fuBusy; + Stats::Vector dist_unissued; + Stats::Vector2d stat_issued_inst_type; Stats::Formula misspec_cnt; Stats::Formula misspec_ipc; @@ -379,37 +379,37 @@ class LWBackEnd Stats::Formula commit_ipb; Stats::Formula lsq_inv_rate; */ - Stats::Vector<> writebackCount; - Stats::Vector<> producerInst; - Stats::Vector<> consumerInst; - Stats::Vector<> wbPenalized; + Stats::Vector writebackCount; + Stats::Vector producerInst; + Stats::Vector consumerInst; + Stats::Vector wbPenalized; Stats::Formula wbRate; Stats::Formula wbFanout; Stats::Formula wbPenalizedRate; // total number of instructions committed - Stats::Vector<> statComInst; - Stats::Vector<> statComSwp; - Stats::Vector<> statComRefs; - Stats::Vector<> statComLoads; - Stats::Vector<> statComMembars; - Stats::Vector<> statComBranches; + Stats::Vector statComInst; + Stats::Vector statComSwp; + Stats::Vector statComRefs; + Stats::Vector statComLoads; + Stats::Vector statComMembars; + Stats::Vector statComBranches; - Stats::Distribution<> nCommittedDist; + Stats::Distribution nCommittedDist; - Stats::Scalar<> commitEligibleSamples; - Stats::Vector<> commitEligible; + Stats::Scalar commitEligibleSamples; + Stats::Vector commitEligible; - Stats::Vector<> squashedInsts; - Stats::Vector<> ROBSquashedInsts; + Stats::Vector squashedInsts; + Stats::Vector ROBSquashedInsts; - Stats::Scalar<> ROBFcount; + Stats::Scalar ROBFcount; Stats::Formula ROBFullRate; - Stats::Vector<> ROBCount; // cumulative ROB occupancy + Stats::Vector ROBCount; // cumulative ROB occupancy Stats::Formula ROBOccRate; -// Stats::VectorDistribution<> ROBOccDist; +// Stats::VectorDistribution ROBOccDist; public: void dumpInsts(); diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh index a5d79a789..60c42edd3 100644 --- a/src/cpu/ozone/lw_back_end_impl.hh +++ b/src/cpu/ozone/lw_back_end_impl.hh @@ -525,10 +525,7 @@ template <class Impl> void LWBackEnd<Impl>::checkInterrupts() { - if (cpu->checkInterrupts && - cpu->check_interrupts(tc) && - !trapSquash && - !tcSquash) { + if (cpu->checkInterrupts(tc) && !trapSquash && !tcSquash) { frontEnd->interruptPending = true; if (robEmpty() && !LSQ.hasStoresToWB()) { // Will need to squash all instructions currently in flight and have diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh index 7fc8b6307..4f8101bc0 100644 --- a/src/cpu/ozone/lw_lsq.hh +++ b/src/cpu/ozone/lw_lsq.hh @@ -39,6 +39,7 @@ #include "arch/faults.hh" #include "arch/types.hh" #include "config/full_system.hh" +#include "base/fast_alloc.hh" #include "base/hashmap.hh" #include "cpu/inst_seq.hh" #include "mem/packet.hh" @@ -301,7 +302,7 @@ class OzoneLWLSQ { }; /** Derived class to hold any sender state the LSQ needs. */ - class LSQSenderState : public Packet::SenderState + class LSQSenderState : public Packet::SenderState, public FastAlloc { public: /** Default constructor. */ @@ -410,9 +411,9 @@ class OzoneLWLSQ { //list<InstSeqNum> mshrSeqNums; /** Tota number of memory ordering violations. */ - Stats::Scalar<> lsqMemOrderViolation; + Stats::Scalar lsqMemOrderViolation; - //Stats::Scalar<> dcacheStallCycles; + //Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; // Make these per thread? diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc index 438218df2..79f5277d5 100644 --- a/src/cpu/pc_event.cc +++ b/src/cpu/pc_event.cc @@ -34,12 +34,12 @@ #include <string> #include <utility> +#include "base/debug.hh" #include "base/trace.hh" #include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" #include "cpu/pc_event.hh" -#include "sim/debug.hh" #include "sim/core.hh" #include "sim/system.hh" diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc index 81384d529..38ffb74e4 100644 --- a/src/cpu/quiesce_event.cc +++ b/src/cpu/quiesce_event.cc @@ -33,7 +33,7 @@ #include "cpu/quiesce_event.hh" EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc) - : Event(&mainEventQueue), tc(_tc) + : tc(_tc) { } diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index 28c2aa9c9..b7174bb43 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -28,18 +28,15 @@ from m5.params import * from m5 import build_env -from BaseCPU import BaseCPU +from BaseSimpleCPU import BaseSimpleCPU -class AtomicSimpleCPU(BaseCPU): +class AtomicSimpleCPU(BaseSimpleCPU): type = 'AtomicSimpleCPU' width = Param.Int(1, "CPU width") - simulate_stalls = Param.Bool(False, "Simulate cache stall cycles") - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") + simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles") + simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") physmem_port = Port("Physical Memory Port") - _mem_ports = BaseCPU._mem_ports + \ + _mem_ports = BaseSimpleCPU._mem_ports + \ ['icache_port', 'dcache_port', 'physmem_port'] diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py new file mode 100644 index 000000000..9f528bc20 --- /dev/null +++ b/src/cpu/simple/BaseSimpleCPU.py @@ -0,0 +1,34 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# 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. +# +# Authors: Gabe Black + +from m5.params import * +from BaseCPU import BaseCPU + +class BaseSimpleCPU(BaseCPU): + type = 'BaseSimpleCPU' + abstract = True diff --git a/src/cpu/simple/SConscript b/src/cpu/simple/SConscript index c090a938c..76598666f 100644 --- a/src/cpu/simple/SConscript +++ b/src/cpu/simple/SConscript @@ -47,3 +47,4 @@ if 'AtomicSimpleCPU' in env['CPU_MODELS'] or \ if need_simple_base: Source('base.cc') + SimObject('BaseSimpleCPU.py') diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py index 7e777e813..ce6839241 100644 --- a/src/cpu/simple/TimingSimpleCPU.py +++ b/src/cpu/simple/TimingSimpleCPU.py @@ -28,14 +28,10 @@ from m5.params import * from m5 import build_env -from BaseCPU import BaseCPU +from BaseSimpleCPU import BaseSimpleCPU -class TimingSimpleCPU(BaseCPU): +class TimingSimpleCPU(BaseSimpleCPU): type = 'TimingSimpleCPU' - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") - _mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port'] + _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port'] diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 23bd40b9b..17f93c882 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -43,7 +43,7 @@ using namespace std; using namespace TheISA; AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) + : Event(CPU_Tick_Pri), cpu(c) { } @@ -79,13 +79,12 @@ void AtomicSimpleCPU::init() { BaseCPU::init(); - cpuId = tc->readCpuId(); #if FULL_SYSTEM for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, cpuId); + TheISA::initCPU(tc, tc->contextId()); } #endif if (hasPhysMemPort) { @@ -94,9 +93,10 @@ AtomicSimpleCPU::init() physmemPort.getPeerAddressRanges(pmAddrList, snoop); physMemAddr = *pmAddrList.begin(); } - ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT - data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too - data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too + // Atomic doesn't do MT right now, so contextId == threadId + ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT + data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too + data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too } bool @@ -148,13 +148,14 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port) #if FULL_SYSTEM // Update the ThreadContext's memory ports (Functional/Virtual // Ports) - cpu->tcBase()->connectMemPorts(); + cpu->tcBase()->connectMemPorts(cpu->tcBase()); #endif } -AtomicSimpleCPU::AtomicSimpleCPU(Params *p) - : BaseSimpleCPU(p), tickEvent(this), - width(p->width), simulate_stalls(p->simulate_stalls), +AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p) + : BaseSimpleCPU(p), tickEvent(this), width(p->width), + simulate_data_stalls(p->simulate_data_stalls), + simulate_inst_stalls(p->simulate_inst_stalls), icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this), physmemPort(name() + "-iport", this), hasPhysMemPort(false) { @@ -175,8 +176,6 @@ AtomicSimpleCPU::serialize(ostream &os) { SimObject::State so_state = SimObject::getState(); SERIALIZE_ENUM(so_state); - Status _status = status(); - SERIALIZE_ENUM(_status); BaseSimpleCPU::serialize(os); nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); @@ -187,7 +186,6 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { SimObject::State so_state; UNSERIALIZE_ENUM(so_state); - UNSERIALIZE_ENUM(_status); BaseSimpleCPU::unserialize(cp, section); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); } @@ -203,16 +201,15 @@ AtomicSimpleCPU::resume() changeState(SimObject::Running); if (thread->status() == ThreadContext::Active) { - if (!tickEvent.scheduled()) { - tickEvent.schedule(nextCycle()); - } + if (!tickEvent.scheduled()) + schedule(tickEvent, nextCycle()); } } void AtomicSimpleCPU::switchOut() { - assert(status() == Running || status() == Idle); + assert(_status == Running || _status == Idle); _status = SwitchedOut; tickEvent.squash(); @@ -232,7 +229,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running; - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); break; } } @@ -240,10 +237,9 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _status = Idle; } assert(threadContexts.size() == 1); - cpuId = tc->readCpuId(); - ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT - data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too - data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too + ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT + data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too + data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too } @@ -262,7 +258,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay) numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend); //Make sure ticks are still on multiples of cycles - tickEvent.schedule(nextCycle(curTick + ticks(delay))); + schedule(tickEvent, nextCycle(curTick + ticks(delay))); _status = Running; } @@ -280,7 +276,7 @@ AtomicSimpleCPU::suspendContext(int thread_num) // tick event may not be scheduled if this gets called from inside // an instruction's execution, e.g. "quiesce" if (tickEvent.scheduled()) - tickEvent.deschedule(); + deschedule(tickEvent); notIdleFraction--; _status = Idle; @@ -318,7 +314,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->translateDataReadReq(req); + Fault fault = thread->dtb->translateAtomic(req, tc, false); // Now do the access. if (fault == NoFault) { @@ -355,6 +351,9 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) if (secondAddr <= addr) { data = gtoh(data); + if (traceData) { + traceData->setData(data); + } return fault; } @@ -371,61 +370,6 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) } } -Fault -AtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr, - int size, unsigned flags) -{ - // use the CPU's statically allocated read request and packet objects - Request *req = &data_read_req; - - if (traceData) { - traceData->setAddr(vaddr); - } - - //The block size of our peer. - int blockSize = dcachePort.peerBlockSize(); - //The size of the data we're trying to read. - int dataSize = size; - - bool firstTimeThrough = true; - - //The address of the second part of this access if it needs to be split - //across a cache line boundary. - Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize); - - if(secondAddr > vaddr) - dataSize = secondAddr - vaddr; - - while(1) { - req->setVirt(0, vaddr, dataSize, flags, thread->readPC()); - - // translate to physical address - Fault fault = thread->translateDataReadReq(req); - - //If there's a fault, return it - if (fault != NoFault) - return fault; - - if (firstTimeThrough) { - paddr = req->getPaddr(); - firstTimeThrough = false; - } - - //If we don't need to access a second cache line, stop now. - if (secondAddr <= vaddr) - return fault; - - /* - * Set up for accessing the second cache line. - */ - - //Adjust the size to get the remaining bytes. - dataSize = vaddr + size - secondAddr; - //And access the right address. - vaddr = secondAddr; - } -} - #ifndef DOXYGEN_SHOULD_SKIP_THIS template @@ -508,7 +452,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->translateDataWriteReq(req); + Fault fault = thread->dtb->translateAtomic(req, tc, true); // Now do the access. if (fault == NoFault) { @@ -568,6 +512,9 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) // If the write needs to have a fault on the access, consider // calling changeStatus() and changing it to "bad addr write" // or something. + if (traceData) { + traceData->setData(gtoh(data)); + } return fault; } @@ -584,64 +531,6 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) } } -Fault -AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - // use the CPU's statically allocated write request and packet objects - Request *req = &data_write_req; - - if (traceData) { - traceData->setAddr(vaddr); - } - - //The block size of our peer. - int blockSize = dcachePort.peerBlockSize(); - - //The address of the second part of this access if it needs to be split - //across a cache line boundary. - Addr secondAddr = roundDown(vaddr + size - 1, blockSize); - - //The size of the data we're trying to read. - int dataSize = size; - - bool firstTimeThrough = true; - - if(secondAddr > vaddr) - dataSize = secondAddr - vaddr; - - dcache_latency = 0; - - while(1) { - req->setVirt(0, vaddr, dataSize, flags, thread->readPC()); - - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); - - //If there's a fault or we don't need to access a second cache line, - //stop now. - if (fault != NoFault) - return fault; - - if (firstTimeThrough) { - paddr = req->getPaddr(); - firstTimeThrough = false; - } - - if (secondAddr <= vaddr) - return fault; - - /* - * Set up for accessing the second cache line. - */ - - //Adjust the size to get the remaining bytes. - dataSize = vaddr + size - secondAddr; - //And access the right address. - vaddr = secondAddr; - } -} - #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -705,7 +594,7 @@ AtomicSimpleCPU::tick() { DPRINTF(SimpleCPU, "Tick\n"); - Tick latency = ticks(1); // instruction takes one cycle by default + Tick latency = 0; for (int i = 0; i < width; ++i) { numCycles++; @@ -715,31 +604,43 @@ AtomicSimpleCPU::tick() checkPcEventQueue(); - Fault fault = setupFetchRequest(&ifetch_req); + Fault fault = NoFault; + + bool fromRom = isRomMicroPC(thread->readMicroPC()); + if (!fromRom && !curMacroStaticInst) { + setupFetchRequest(&ifetch_req); + fault = thread->itb->translateAtomic(&ifetch_req, tc); + } if (fault == NoFault) { Tick icache_latency = 0; bool icache_access = false; dcache_access = false; // assume no dcache access - //Fetch more instruction memory if necessary - //if(predecoder.needMoreBytes()) - //{ - icache_access = true; - Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, - Packet::Broadcast); - ifetch_pkt.dataStatic(&inst); - - if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) - icache_latency = physmemPort.sendAtomic(&ifetch_pkt); - else - icache_latency = icachePort.sendAtomic(&ifetch_pkt); + if (!fromRom && !curMacroStaticInst) { + // This is commented out because the predecoder would act like + // a tiny cache otherwise. It wouldn't be flushed when needed + // like the I cache. It should be flushed, and when that works + // this code should be uncommented. + //Fetch more instruction memory if necessary + //if(predecoder.needMoreBytes()) + //{ + icache_access = true; + Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, + Packet::Broadcast); + ifetch_pkt.dataStatic(&inst); + + if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) + icache_latency = physmemPort.sendAtomic(&ifetch_pkt); + else + icache_latency = icachePort.sendAtomic(&ifetch_pkt); - assert(!ifetch_pkt.isError()); + assert(!ifetch_pkt.isError()); - // ifetch_req is initialized to read the instruction directly - // into the CPU object's inst field. - //} + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + //} + } preExecute(); @@ -763,16 +664,21 @@ AtomicSimpleCPU::tick() curStaticInst->isFirstMicroop())) instCnt++; - if (simulate_stalls) { - Tick icache_stall = - icache_access ? icache_latency - ticks(1) : 0; - Tick dcache_stall = - dcache_access ? dcache_latency - ticks(1) : 0; - Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1); - if (ticks(stall_cycles) < (icache_stall + dcache_stall)) - latency += ticks(stall_cycles+1); - else - latency += ticks(stall_cycles); + Tick stall_ticks = 0; + if (simulate_inst_stalls && icache_access) + stall_ticks += icache_latency; + + if (simulate_data_stalls && dcache_access) + stall_ticks += dcache_latency; + + if (stall_ticks) { + Tick stall_cycles = stall_ticks / ticks(1); + Tick aligned_stall_ticks = ticks(stall_cycles); + + if (aligned_stall_ticks < stall_ticks) + aligned_stall_ticks += 1; + + latency += aligned_stall_ticks; } } @@ -780,8 +686,12 @@ AtomicSimpleCPU::tick() advancePC(fault); } + // instruction takes at least one cycle + if (latency < ticks(1)) + latency = ticks(1); + if (_status != Idle) - tickEvent.schedule(curTick + latency); + schedule(tickEvent, curTick + latency); } @@ -799,38 +709,10 @@ AtomicSimpleCPU::printAddr(Addr a) AtomicSimpleCPU * AtomicSimpleCPUParams::create() { - AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); - params->name = name; - 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->progress_interval = progress_interval; - params->deferRegistration = defer_registration; - params->phase = phase; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->width = width; - params->simulate_stalls = simulate_stalls; - params->system = system; - params->cpu_id = cpu_id; - params->tracer = tracer; - - params->itb = itb; - params->dtb = dtb; -#if FULL_SYSTEM - params->profile = profile; - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else + numThreads = 1; +#if !FULL_SYSTEM if (workload.size() != 1) panic("only one workload allowed"); - params->process = workload[0]; #endif - - AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); - return cpu; + return new AtomicSimpleCPU(this); } diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 19bc0e13b..190097637 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -32,34 +32,17 @@ #define __CPU_SIMPLE_ATOMIC_HH__ #include "cpu/simple/base.hh" +#include "params/AtomicSimpleCPU.hh" class AtomicSimpleCPU : public BaseSimpleCPU { public: - struct Params : public BaseSimpleCPU::Params { - int width; - bool simulate_stalls; - }; - - AtomicSimpleCPU(Params *params); + AtomicSimpleCPU(AtomicSimpleCPUParams *params); virtual ~AtomicSimpleCPU(); virtual void init(); - public: - // - enum Status { - Running, - Idle, - SwitchedOut - }; - - protected: - Status _status; - - Status status() const { return _status; } - private: struct TickEvent : public Event @@ -74,7 +57,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU TickEvent tickEvent; const int width; - const bool simulate_stalls; + const bool simulate_data_stalls; + const bool simulate_inst_stalls; // main simulation loop (one cycle) void tick(); @@ -152,11 +136,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU template <class T> Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - /** * Print state of address in memory system via PrintReq (for * debugging). diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4a91a9e12..348d2392f 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -31,6 +31,7 @@ #include "arch/utility.hh" #include "arch/faults.hh" #include "base/cprintf.hh" +#include "base/cp_annotate.hh" #include "base/inifile.hh" #include "base/loader/symtab.hh" #include "base/misc.hh" @@ -65,16 +66,18 @@ #include "mem/mem_object.hh" #endif // FULL_SYSTEM +#include "params/BaseSimpleCPU.hh" + using namespace std; using namespace TheISA; -BaseSimpleCPU::BaseSimpleCPU(Params *p) +BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p) : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL) { #if FULL_SYSTEM thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); #else - thread = new SimpleThread(this, /* thread_num */ 0, p->process, + thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0], p->itb, p->dtb, /* asid */ 0); #endif // !FULL_SYSTEM @@ -174,12 +177,13 @@ void BaseSimpleCPU::resetStats() { // startNumInst = numInst; - // notIdleFraction = (_status != Idle); + notIdleFraction = (_status != Idle); } void BaseSimpleCPU::serialize(ostream &os) { + SERIALIZE_ENUM(_status); BaseCPU::serialize(os); // SERIALIZE_SCALAR(inst); nameOut(os, csprintf("%s.xc.0", name())); @@ -189,6 +193,7 @@ BaseSimpleCPU::serialize(ostream &os) void BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { + UNSERIALIZE_ENUM(_status); BaseCPU::unserialize(cp, section); // UNSERIALIZE_SCALAR(inst); thread->unserialize(cp, csprintf("%s.xc.0", section)); @@ -299,14 +304,13 @@ BaseSimpleCPU::dbg_vtophys(Addr addr) #if FULL_SYSTEM void -BaseSimpleCPU::post_interrupt(int int_num, int index) +BaseSimpleCPU::wakeup() { - BaseCPU::post_interrupt(int_num, index); + if (thread->status() != ThreadContext::Suspended) + return; - if (thread->status() == ThreadContext::Suspended) { - DPRINTF(Quiesce,"Suspended Processor awoke\n"); - thread->activate(); - } + DPRINTF(Quiesce,"Suspended Processor awoke\n"); + thread->activate(); } #endif // FULL_SYSTEM @@ -314,11 +318,12 @@ void BaseSimpleCPU::checkForInterrupts() { #if FULL_SYSTEM - if (check_interrupts(tc)) { - Fault interrupt = interrupts.getInterrupt(tc); + if (checkInterrupts(tc)) { + Fault interrupt = interrupts->getInterrupt(tc); if (interrupt != NoFault) { - interrupts.updateIntrInfo(tc); + predecoder.reset(); + interrupts->updateIntrInfo(tc); interrupt->invoke(tc); } } @@ -326,7 +331,7 @@ BaseSimpleCPU::checkForInterrupts() } -Fault +void BaseSimpleCPU::setupFetchRequest(Request *req) { Addr threadPC = thread->readPC(); @@ -342,10 +347,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req) Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); - - Fault fault = thread->translateInstReq(req); - - return fault; } @@ -364,9 +365,13 @@ BaseSimpleCPU::preExecute() // decode the instruction inst = gtoh(inst); - //If we're not in the middle of a macro instruction - if (!curMacroStaticInst) { + MicroPC upc = thread->readMicroPC(); + if (isRomMicroPC(upc)) { + stayAtPC = false; + curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst); + } else if (!curMacroStaticInst) { + //We're not in the middle of a macro instruction StaticInstPtr instPtr = NULL; //Predecode, ie bundle up an ExtMachInst @@ -397,23 +402,22 @@ BaseSimpleCPU::preExecute() //out micro ops if (instPtr && instPtr->isMacroop()) { curMacroStaticInst = instPtr; - curStaticInst = curMacroStaticInst-> - fetchMicroop(thread->readMicroPC()); + curStaticInst = curMacroStaticInst->fetchMicroop(upc); } else { curStaticInst = instPtr; } } else { //Read the next micro op from the macro op - curStaticInst = curMacroStaticInst-> - fetchMicroop(thread->readMicroPC()); + curStaticInst = curMacroStaticInst->fetchMicroop(upc); } //If we decoded an instruction this "tick", record information about it. if(curStaticInst) { #if TRACING_ON - traceData = tracer->getInstRecord(curTick, tc, curStaticInst, - thread->readPC()); + traceData = tracer->getInstRecord(curTick, tc, + curStaticInst, thread->readPC(), + curMacroStaticInst, thread->readMicroPC()); DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", curStaticInst->getName(), curStaticInst->machInst); @@ -447,6 +451,10 @@ BaseSimpleCPU::postExecute() comLoadEventQueue[0]->serviceEvents(numLoad); } + if (CPA::available()) { + CPA::cpa()->swAutoBegin(tc, thread->readNextPC()); + } + traceFunctions(thread->readPC()); if (traceData) { @@ -465,22 +473,21 @@ BaseSimpleCPU::advancePC(Fault fault) if (fault != NoFault) { curMacroStaticInst = StaticInst::nullStaticInstPtr; predecoder.reset(); - thread->setMicroPC(0); - thread->setNextMicroPC(1); fault->invoke(tc); } else { //If we're at the last micro op for this instruction if (curStaticInst && curStaticInst->isLastMicroop()) { - //We should be working with a macro op - assert(curMacroStaticInst); + //We should be working with a macro op or be in the ROM + assert(curMacroStaticInst || + isRomMicroPC(thread->readMicroPC())); //Close out this macro op, and clean up the //microcode state curMacroStaticInst = StaticInst::nullStaticInstPtr; - thread->setMicroPC(0); - thread->setNextMicroPC(1); + thread->setMicroPC(normalMicroPC(0)); + thread->setNextMicroPC(normalMicroPC(1)); } //If we're still in a macro op - if (curMacroStaticInst) { + if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) { //Advance the micro pc thread->setMicroPC(thread->readNextMicroPC()); //Advance the "next" micro pc. Note that there are no delay diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 918965fdb..e80606388 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -76,6 +76,8 @@ namespace Trace { class InstRecord; } +class BaseSimpleCPUParams; + class BaseSimpleCPU : public BaseCPU { @@ -96,7 +98,7 @@ class BaseSimpleCPU : public BaseCPU } public: - void post_interrupt(int int_num, int index); + void wakeup(); void zero_fill_64(Addr addr) { static int warned = 0; @@ -107,15 +109,7 @@ class BaseSimpleCPU : public BaseCPU }; public: - struct Params : public BaseCPU::Params - { - TheISA::ITB *itb; - TheISA::DTB *dtb; -#if !FULL_SYSTEM - Process *process; -#endif - }; - BaseSimpleCPU(Params *params); + BaseSimpleCPU(BaseSimpleCPUParams *params); virtual ~BaseSimpleCPU(); public: @@ -127,7 +121,22 @@ class BaseSimpleCPU : public BaseCPU */ ThreadContext *tc; protected: - int cpuId; + + enum Status { + Idle, + Running, + ITBWaitResponse, + IcacheRetry, + IcacheWaitResponse, + IcacheWaitSwitch, + DTBWaitResponse, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, + SwitchedOut + }; + + Status _status; public: @@ -153,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU bool stayAtPC; void checkForInterrupts(); - Fault setupFetchRequest(Request *req); + void setupFetchRequest(Request *req); void preExecute(); void postExecute(); void advancePC(Fault fault); @@ -168,7 +177,7 @@ class BaseSimpleCPU : public BaseCPU // number of simulated instructions Counter numInst; Counter startNumInst; - Stats::Scalar<> numInsts; + Stats::Scalar numInsts; void countInst() { @@ -187,30 +196,30 @@ class BaseSimpleCPU : public BaseCPU static const Addr PCMask = ~((Addr)sizeof(TheISA::MachInst) - 1); // number of simulated memory references - Stats::Scalar<> numMemRefs; + Stats::Scalar numMemRefs; // number of simulated loads Counter numLoad; Counter startNumLoad; // number of idle cycles - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; // number of cycles stalled for I-cache responses - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; Counter lastIcacheStall; // number of cycles stalled for I-cache retries - Stats::Scalar<> icacheRetryCycles; + Stats::Scalar icacheRetryCycles; Counter lastIcacheRetry; // number of cycles stalled for D-cache responses - Stats::Scalar<> dcacheStallCycles; + Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; // number of cycles stalled for D-cache retries - Stats::Scalar<> dcacheRetryCycles; + Stats::Scalar dcacheRetryCycles; Counter lastDcacheRetry; virtual void serialize(std::ostream &os); @@ -219,7 +228,7 @@ class BaseSimpleCPU : public BaseCPU // These functions are only used in CPU models that split // effective address computation from the actual memory access. void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); + Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); M5_DUMMY_RETURN} void prefetch(Addr addr, unsigned flags) diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index a76824ff3..a8f86f8d2 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -57,13 +57,12 @@ void TimingSimpleCPU::init() { BaseCPU::init(); - cpuId = tc->readCpuId(); #if FULL_SYSTEM for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, cpuId); + TheISA::initCPU(tc, _cpuId); } #endif } @@ -101,11 +100,12 @@ void TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) { pkt = _pkt; - Event::schedule(t); + cpu->schedule(this, t); } -TimingSimpleCPU::TimingSimpleCPU(Params *p) - : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) +TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) + : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), + dcachePort(this, p->clock), fetchEvent(this) { _status = Idle; @@ -114,7 +114,6 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p) ifetch_pkt = dcache_pkt = NULL; drainEvent = NULL; - fetchEvent = NULL; previousTick = 0; changeState(SimObject::Running); } @@ -145,7 +144,7 @@ TimingSimpleCPU::drain(Event *drain_event) { // TimingSimpleCPU is ready to drain if it's not waiting for // an access to complete. - if (status() == Idle || status() == Running || status() == SwitchedOut) { + if (_status == Idle || _status == Running || _status == SwitchedOut) { changeState(SimObject::Drained); return 0; } else { @@ -162,15 +161,10 @@ TimingSimpleCPU::resume() if (_status != SwitchedOut && _status != Idle) { assert(system->getMemoryMode() == Enums::timing); - // Delete the old event if it existed. - if (fetchEvent) { - if (fetchEvent->scheduled()) - fetchEvent->deschedule(); + if (fetchEvent.scheduled()) + deschedule(fetchEvent); - delete fetchEvent; - } - - fetchEvent = new FetchEvent(this, nextCycle()); + schedule(fetchEvent, nextCycle()); } changeState(SimObject::Running); @@ -179,14 +173,14 @@ TimingSimpleCPU::resume() void TimingSimpleCPU::switchOut() { - assert(status() == Running || status() == Idle); + assert(_status == Running || _status == Idle); _status = SwitchedOut; numCycles += tickToCycles(curTick - previousTick); // If we've been scheduled to resume but are then told to switch out, // we'll need to cancel it. - if (fetchEvent && fetchEvent->scheduled()) - fetchEvent->deschedule(); + if (fetchEvent.scheduled()) + deschedule(fetchEvent); } @@ -209,7 +203,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _status = Idle; } assert(threadContexts.size() == 1); - cpuId = tc->readCpuId(); previousTick = curTick; } @@ -228,7 +221,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay) _status = Running; // kick things off by initiating the fetch of the next instruction - fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay))); + schedule(fetchEvent, nextCycle(curTick + ticks(delay))); } @@ -249,74 +242,239 @@ TimingSimpleCPU::suspendContext(int thread_num) _status = Idle; } +bool +TimingSimpleCPU::handleReadPacket(PacketPtr pkt) +{ + RequestPtr req = pkt->req; + if (req->isMmapedIpr()) { + Tick delay; + delay = TheISA::handleIprRead(thread->getTC(), pkt); + new IprEvent(pkt, this, nextCycle(curTick + delay)); + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } else if (!dcachePort.sendTiming(pkt)) { + _status = DcacheRetry; + dcache_pkt = pkt; + } else { + _status = DcacheWaitResponse; + // memory system takes ownership of packet + dcache_pkt = NULL; + } + return dcache_pkt == NULL; +} -template <class T> -Fault -TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) +void +TimingSimpleCPU::sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read) { - Request *req = - new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - cpuId, /* thread ID */ 0); + _status = Running; + if (fault != NoFault) { + delete data; + delete req; - if (traceData) { - traceData->setAddr(req->getVaddr()); + translationFault(fault); + return; } + PacketPtr pkt; + buildPacket(pkt, req, read); + pkt->dataDynamic<uint8_t>(data); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt->makeResponse(); + completeDataAccess(pkt); + } else if (read) { + handleReadPacket(pkt); + } else { + bool do_access = true; // flag to suppress cache access - // translate to physical address - Fault fault = thread->translateDataReadReq(req); + if (req->isLocked()) { + do_access = TheISA::handleLockedWrite(thread, req); + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); + } - // Now do the access. - if (fault == NoFault) { - PacketPtr pkt = - new Packet(req, - (req->isLocked() ? - MemCmd::LoadLockedReq : MemCmd::ReadReq), - Packet::Broadcast); - pkt->dataDynamic<T>(new T); - - if (req->isMmapedIpr()) { - Tick delay; - delay = TheISA::handleIprRead(thread->getTC(), pkt); - new IprEvent(pkt, this, nextCycle(curTick + delay)); - _status = DcacheWaitResponse; - dcache_pkt = NULL; - } else if (!dcachePort.sendTiming(pkt)) { - _status = DcacheRetry; + if (do_access) { dcache_pkt = pkt; + handleWritePacket(); } else { _status = DcacheWaitResponse; - // memory system takes ownership of packet - dcache_pkt = NULL; + completeDataAccess(pkt); } + } +} - // This will need a new way to tell if it has a dcache attached. - if (req->isUncacheable()) - recordEvent("Uncached Read"); +void +TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + _status = Running; + if (fault1 != NoFault || fault2 != NoFault) { + delete data; + delete req1; + delete req2; + if (fault1 != NoFault) + translationFault(fault1); + else if (fault2 != NoFault) + translationFault(fault2); + return; + } + PacketPtr pkt1, pkt2; + buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt1->makeResponse(); + completeDataAccess(pkt1); + } else if (read) { + if (handleReadPacket(pkt1)) { + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); + send_state->clearFromParent(); + if (handleReadPacket(pkt2)) { + send_state = dynamic_cast<SplitFragmentSenderState *>( + pkt1->senderState); + send_state->clearFromParent(); + } + } } else { - delete req; + dcache_pkt = pkt1; + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); + send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleWritePacket()) { + send_state = dynamic_cast<SplitFragmentSenderState *>( + pkt1->senderState); + send_state->clearFromParent(); + } + } + } +} + +void +TimingSimpleCPU::translationFault(Fault fault) +{ + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; + + if (traceData) { + // Since there was a fault, we shouldn't trace this instruction. + delete traceData; + traceData = NULL; } - return fault; + postExecute(); + + if (getState() == SimObject::Draining) { + advancePC(fault); + completeDrain(); + } else { + advanceInst(fault); + } } +void +TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) +{ + MemCmd cmd; + if (read) { + cmd = MemCmd::ReadReq; + if (req->isLocked()) + cmd = MemCmd::LoadLockedReq; + } else { + cmd = MemCmd::WriteReq; + if (req->isLocked()) { + cmd = MemCmd::StoreCondReq; + } else if (req->isSwap()) { + cmd = MemCmd::SwapReq; + } + } + pkt = new Packet(req, cmd, Packet::Broadcast); +} + +void +TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + pkt1 = pkt2 = NULL; + + assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + + if (req->getFlags().isSet(Request::NO_ACCESS)) { + buildPacket(pkt1, req, read); + return; + } + + buildPacket(pkt1, req1, read); + buildPacket(pkt2, req2, read); + + req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); + PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), + Packet::Broadcast); + + pkt->dataDynamic<uint8_t>(data); + pkt1->dataStatic<uint8_t>(data); + pkt2->dataStatic<uint8_t>(data + req1->getSize()); + + SplitMainSenderState * main_send_state = new SplitMainSenderState; + pkt->senderState = main_send_state; + main_send_state->fragments[0] = pkt1; + main_send_state->fragments[1] = pkt2; + main_send_state->outstanding = 2; + pkt1->senderState = new SplitFragmentSenderState(pkt, 0); + pkt2->senderState = new SplitFragmentSenderState(pkt, 1); +} + +template <class T> Fault -TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) +TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) { - Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); + Fault fault; + const int asid = 0; + const int thread_id = 0; + const Addr pc = thread->readPC(); + int block_size = dcachePort.peerBlockSize(); + int data_size = sizeof(T); + + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); + + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); + + + _status = DTBWaitResponse; + if (split_addr > addr) { + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)(new T), true); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), false); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), false); + } else { + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)(new T), NULL, true), + false); + } if (traceData) { - traceData->setAddr(vaddr); + traceData->setData(data); + traceData->setAddr(addr); } - Fault fault = thread->translateDataWriteReq(req); + // This will need a new way to tell if it has a dcache attached. + if (req->isUncacheable()) + recordEvent("Uncached Read"); - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; + return NoFault; } #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -369,92 +527,75 @@ TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) return read(addr, (uint32_t&)data, flags); } +bool +TimingSimpleCPU::handleWritePacket() +{ + RequestPtr req = dcache_pkt->req; + if (req->isMmapedIpr()) { + Tick delay; + delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); + new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } else if (!dcachePort.sendTiming(dcache_pkt)) { + _status = DcacheRetry; + } else { + _status = DcacheWaitResponse; + // memory system takes ownership of packet + dcache_pkt = NULL; + } + return dcache_pkt == NULL; +} template <class T> Fault TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { - Request *req = - new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - cpuId, /* thread ID */ 0); + const int asid = 0; + const int thread_id = 0; + const Addr pc = thread->readPC(); + int block_size = dcachePort.peerBlockSize(); + int data_size = sizeof(T); + + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); + + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); + + T *dataP = new T; + *dataP = TheISA::htog(data); + _status = DTBWaitResponse; + if (split_addr > addr) { + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)dataP, false); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), true); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), true); + } else { + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)dataP, res, false), + true); + } if (traceData) { traceData->setAddr(req->getVaddr()); + traceData->setData(data); } - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); - - // Now do the access. - if (fault == NoFault) { - MemCmd cmd = MemCmd::WriteReq; // default - bool do_access = true; // flag to suppress cache access - - if (req->isLocked()) { - cmd = MemCmd::StoreCondReq; - do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isSwap()) { - cmd = MemCmd::SwapReq; - if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } - } - - // Note: need to allocate dcache_pkt even if do_access is - // false, as it's used unconditionally to call completeAcc(). - assert(dcache_pkt == NULL); - dcache_pkt = new Packet(req, cmd, Packet::Broadcast); - dcache_pkt->allocate(); - dcache_pkt->set(data); - - if (do_access) { - if (req->isMmapedIpr()) { - Tick delay; - dcache_pkt->set(htog(data)); - delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); - new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); - _status = DcacheWaitResponse; - dcache_pkt = NULL; - } else if (!dcachePort.sendTiming(dcache_pkt)) { - _status = DcacheRetry; - } else { - _status = DcacheWaitResponse; - // memory system takes ownership of packet - dcache_pkt = NULL; - } - } - // This will need a new way to tell if it's hooked up to a cache or not. - if (req->isUncacheable()) - recordEvent("Uncached Write"); - } else { - delete req; - } - + // This will need a new way to tell if it's hooked up to a cache or not. + if (req->isUncacheable()) + recordEvent("Uncached Write"); // If the write needs to have a fault on the access, consider calling // changeStatus() and changing it to "bad addr write" or something. - return fault; -} - -Fault -TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); - - if (traceData) { - traceData->setAddr(vaddr); - } - - Fault fault = thread->translateDataWriteReq(req); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; + return NoFault; } @@ -524,14 +665,31 @@ TimingSimpleCPU::fetch() checkPcEventQueue(); - Request *ifetch_req = new Request(); - ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); - Fault fault = setupFetchRequest(ifetch_req); + bool fromRom = isRomMicroPC(thread->readMicroPC()); - ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); - ifetch_pkt->dataStatic(&inst); + if (!fromRom && !curMacroStaticInst) { + Request *ifetch_req = new Request(); + ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); + setupFetchRequest(ifetch_req); + thread->itb->translateTiming(ifetch_req, tc, + &fetchTranslation); + } else { + _status = IcacheWaitResponse; + completeIfetch(NULL); + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; + } +} + + +void +TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) +{ if (fault == NoFault) { + ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + if (!icachePort.sendTiming(ifetch_pkt)) { // Need to wait for retry _status = IcacheRetry; @@ -542,8 +700,7 @@ TimingSimpleCPU::fetch() ifetch_pkt = NULL; } } else { - delete ifetch_req; - delete ifetch_pkt; + delete req; // fetch fault: advance directly to next instruction (fault handler) advanceInst(fault); } @@ -556,7 +713,8 @@ TimingSimpleCPU::fetch() void TimingSimpleCPU::advanceInst(Fault fault) { - advancePC(fault); + if (fault != NoFault || !stayAtPC) + advancePC(fault); if (_status == Running) { // kick off fetch of next instruction... callback from icache @@ -574,7 +732,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) // received a response from the icache: execute the received // instruction - assert(!pkt->isError()); + + assert(!pkt || !pkt->isError()); assert(_status == IcacheWaitResponse); _status = Running; @@ -583,41 +742,27 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) previousTick = curTick; if (getState() == SimObject::Draining) { - delete pkt->req; - delete pkt; + if (pkt) { + delete pkt->req; + delete pkt; + } completeDrain(); return; } preExecute(); - if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { + if (curStaticInst && + curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { // load or store: just send to dcache Fault fault = curStaticInst->initiateAcc(this, traceData); if (_status != Running) { // instruction will complete in dcache response callback - assert(_status == DcacheWaitResponse || _status == DcacheRetry); + assert(_status == DcacheWaitResponse || + _status == DcacheRetry || DTBWaitResponse); assert(fault == NoFault); } else { - if (fault == NoFault) { - // Note that ARM can have NULL packets if the instruction gets - // squashed due to predication - // early fail on store conditional: complete now - assert(dcache_pkt != NULL || THE_ISA == ARM_ISA); - - fault = curStaticInst->completeAcc(dcache_pkt, this, - traceData); - if (dcache_pkt != NULL) - { - delete dcache_pkt->req; - delete dcache_pkt; - dcache_pkt = NULL; - } - - // keep an instruction count - if (fault == NoFault) - countInst(); - } else if (traceData) { + if (fault != NoFault && traceData) { // If there was a fault, we shouldn't trace this instruction. delete traceData; traceData = NULL; @@ -630,7 +775,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) instCnt++; advanceInst(fault); } - } else { + } else if (curStaticInst) { // non-memory instruction: execute completely now Fault fault = curStaticInst->execute(this, traceData); @@ -649,10 +794,14 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) curStaticInst->isFirstMicroop())) instCnt++; advanceInst(fault); + } else { + advanceInst(NoFault); } - delete pkt->req; - delete pkt; + if (pkt) { + delete pkt->req; + delete pkt; + } } void @@ -707,12 +856,38 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) // received a response from the dcache: complete the load or store // instruction assert(!pkt->isError()); - assert(_status == DcacheWaitResponse); - _status = Running; numCycles += tickToCycles(curTick - previousTick); previousTick = curTick; + if (pkt->senderState) { + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); + assert(send_state); + delete pkt->req; + delete pkt; + PacketPtr big_pkt = send_state->bigPkt; + delete send_state; + + SplitMainSenderState * main_send_state = + dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); + assert(main_send_state); + // Record the fact that this packet is no longer outstanding. + assert(main_send_state->outstanding != 0); + main_send_state->outstanding--; + + if (main_send_state->outstanding) { + return; + } else { + delete main_send_state; + big_pkt->senderState = NULL; + pkt = big_pkt; + } + } + + assert(_status == DcacheWaitResponse || _status == DTBWaitResponse); + _status = Running; + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); // keep an instruction count @@ -724,7 +899,9 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) traceData = NULL; } - if (pkt->isRead() && pkt->isLocked()) { + // the locked flag may be cleared on the response packet, so check + // pkt->req and not pkt to see if it was a load-locked + if (pkt->isRead() && pkt->req->isLocked()) { TheISA::handleLockedRead(thread, pkt->req); } @@ -760,7 +937,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port) #if FULL_SYSTEM // Update the ThreadContext's memory ports (Functional/Virtual // Ports) - cpu->tcBase()->connectMemPorts(); + cpu->tcBase()->connectMemPorts(cpu->tcBase()); #endif } @@ -771,10 +948,11 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) // delay processing of returned data until next CPU clock edge Tick next_tick = cpu->nextCycle(curTick); - if (next_tick == curTick) + if (next_tick == curTick) { cpu->completeDataAccess(pkt); - else + } else { tickEvent.schedule(pkt, next_tick); + } return true; } @@ -804,17 +982,47 @@ TimingSimpleCPU::DcachePort::recvRetry() assert(cpu->dcache_pkt != NULL); assert(cpu->_status == DcacheRetry); PacketPtr tmp = cpu->dcache_pkt; - if (sendTiming(tmp)) { + if (tmp->senderState) { + // This is a packet from a split access. + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); + assert(send_state); + PacketPtr big_pkt = send_state->bigPkt; + + SplitMainSenderState * main_send_state = + dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); + assert(main_send_state); + + if (sendTiming(tmp)) { + // If we were able to send without retrying, record that fact + // and try sending the other fragment. + send_state->clearFromParent(); + int other_index = main_send_state->getPendingFragment(); + if (other_index > 0) { + tmp = main_send_state->fragments[other_index]; + cpu->dcache_pkt = tmp; + if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || + (big_pkt->isWrite() && cpu->handleWritePacket())) { + main_send_state->fragments[other_index] = NULL; + } + } else { + cpu->_status = DcacheWaitResponse; + // memory system takes ownership of packet + cpu->dcache_pkt = NULL; + } + } + } else if (sendTiming(tmp)) { cpu->_status = DcacheWaitResponse; // memory system takes ownership of packet cpu->dcache_pkt = NULL; } } -TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t) - : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu) +TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, + Tick t) + : pkt(_pkt), cpu(_cpu) { - schedule(t); + cpu->schedule(this, t); } void @@ -844,36 +1052,10 @@ TimingSimpleCPU::printAddr(Addr a) TimingSimpleCPU * TimingSimpleCPUParams::create() { - TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); - params->name = name; - 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->progress_interval = progress_interval; - params->deferRegistration = defer_registration; - params->clock = clock; - params->phase = phase; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->system = system; - params->cpu_id = cpu_id; - params->tracer = tracer; - - params->itb = itb; - params->dtb = dtb; -#if FULL_SYSTEM - params->profile = profile; - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else + numThreads = 1; +#if !FULL_SYSTEM if (workload.size() != 1) panic("only one workload allowed"); - params->process = workload[0]; #endif - - TimingSimpleCPU *cpu = new TimingSimpleCPU(params); - return cpu; + return new TimingSimpleCPU(this); } diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index f8b77604a..a02ec48c9 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -33,40 +33,181 @@ #include "cpu/simple/base.hh" +#include "params/TimingSimpleCPU.hh" + class TimingSimpleCPU : public BaseSimpleCPU { public: - struct Params : public BaseSimpleCPU::Params { - }; - - TimingSimpleCPU(Params *params); + TimingSimpleCPU(TimingSimpleCPUParams * params); virtual ~TimingSimpleCPU(); virtual void init(); public: - // - enum Status { - Idle, - Running, - IcacheRetry, - IcacheWaitResponse, - IcacheWaitSwitch, - DcacheRetry, - DcacheWaitResponse, - DcacheWaitSwitch, - SwitchedOut + Event *drainEvent; + + private: + + /* + * If an access needs to be broken into fragments, currently at most two, + * the the following two classes are used as the sender state of the + * packets so the CPU can keep track of everything. In the main packet + * sender state, there's an array with a spot for each fragment. If a + * fragment has already been accepted by the CPU, aka isn't waiting for + * a retry, it's pointer is NULL. After each fragment has successfully + * been processed, the "outstanding" counter is decremented. Once the + * count is zero, the entire larger access is complete. + */ + class SplitMainSenderState : public Packet::SenderState + { + public: + int outstanding; + PacketPtr fragments[2]; + + int + getPendingFragment() + { + if (fragments[0]) { + return 0; + } else if (fragments[1]) { + return 1; + } else { + return -1; + } + } }; - protected: - Status _status; + class SplitFragmentSenderState : public Packet::SenderState + { + public: + SplitFragmentSenderState(PacketPtr _bigPkt, int _index) : + bigPkt(_bigPkt), index(_index) + {} + PacketPtr bigPkt; + int index; + + void + clearFromParent() + { + SplitMainSenderState * main_send_state = + dynamic_cast<SplitMainSenderState *>(bigPkt->senderState); + main_send_state->fragments[index] = NULL; + } + }; - Status status() const { return _status; } + class FetchTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; - Event *drainEvent; + public: + FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu) + {} - private: + void finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendFetch(fault, req, tc); + } + }; + FetchTranslation fetchTranslation; + + class DataTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; + uint8_t *data; + uint64_t *res; + bool read; + + public: + DataTranslation(TimingSimpleCPU *_cpu, + uint8_t *_data, uint64_t *_res, bool _read) : + cpu(_cpu), data(_data), res(_res), read(_read) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendData(fault, req, data, res, read); + delete this; + } + }; + + class SplitDataTranslation : public BaseTLB::Translation + { + public: + struct WholeTranslationState + { + public: + int outstanding; + RequestPtr requests[2]; + RequestPtr mainReq; + Fault faults[2]; + uint8_t *data; + bool read; + + WholeTranslationState(RequestPtr req1, RequestPtr req2, + RequestPtr main, uint8_t *_data, bool _read) + { + outstanding = 2; + requests[0] = req1; + requests[1] = req2; + mainReq = main; + faults[0] = faults[1] = NoFault; + data = _data; + read = _read; + } + }; + + TimingSimpleCPU *cpu; + int index; + WholeTranslationState *state; + + SplitDataTranslation(TimingSimpleCPU *_cpu, int _index, + WholeTranslationState *_state) : + cpu(_cpu), index(_index), state(_state) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + assert(state); + assert(state->outstanding); + state->faults[index] = fault; + if (--state->outstanding == 0) { + cpu->sendSplitData(state->faults[0], + state->faults[1], + state->requests[0], + state->requests[1], + state->mainReq, + state->data, + state->read); + delete state; + } + delete this; + } + }; + + void sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read); + void sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); + + void translationFault(Fault fault); + + void buildPacket(PacketPtr &pkt, RequestPtr req, bool read); + void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); + + bool handleReadPacket(PacketPtr pkt); + // This function always implicitly uses dcache_pkt. + bool handleWritePacket(); class CpuPort : public Port { @@ -99,8 +240,7 @@ class TimingSimpleCPU : public BaseSimpleCPU PacketPtr pkt; TimingSimpleCPU *cpu; - TickEvent(TimingSimpleCPU *_cpu) - :Event(&mainEventQueue), cpu(_cpu) {} + TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {} const char *description() const { return "Timing CPU tick"; } void schedule(PacketPtr _pkt, Tick t); }; @@ -189,18 +329,13 @@ class TimingSimpleCPU : public BaseSimpleCPU template <class T> Fault read(Addr addr, T &data, unsigned flags); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - template <class T> Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - void fetch(); + void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc); void completeIfetch(PacketPtr ); - void completeDataAccess(PacketPtr ); + void completeDataAccess(PacketPtr pkt); void advanceInst(Fault fault); /** @@ -212,7 +347,7 @@ class TimingSimpleCPU : public BaseSimpleCPU private: typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent; - FetchEvent *fetchEvent; + FetchEvent fetchEvent; struct IprEvent : Event { Packet *pkt; diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 93772fbe1..af0bb4490 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -37,9 +37,11 @@ #include "cpu/base.hh" #include "cpu/simple_thread.hh" #include "cpu/thread_context.hh" +#include "params/BaseCPU.hh" #if FULL_SYSTEM #include "arch/kernel_stats.hh" +#include "arch/stacktrace.hh" #include "base/callback.hh" #include "base/cprintf.hh" #include "base/output.hh" @@ -48,11 +50,10 @@ #include "cpu/quiesce_event.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" -#include "arch/stacktrace.hh" #else +#include "mem/translating_port.hh" #include "sim/process.hh" #include "sim/system.hh" -#include "mem/translating_port.hh" #endif using namespace std; @@ -62,7 +63,7 @@ using namespace std; SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, TheISA::ITB *_itb, TheISA::DTB *_dtb, bool use_kernel_stats) - : ThreadState(_cpu, -1, _thread_num), cpu(_cpu), system(_sys), itb(_itb), + : ThreadState(_cpu, _thread_num), cpu(_cpu), system(_sys), itb(_itb), dtb(_dtb) { @@ -72,7 +73,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, regs.clear(); - if (cpu->params->profile) { + if (cpu->params()->profile) { profile = new FunctionProfile(system->kernelSymtab); Callback *cb = new MakeCallback<SimpleThread, @@ -86,16 +87,13 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, profileNode = &dummyNode; profilePC = 3; - if (use_kernel_stats) { + if (use_kernel_stats) kernelStats = new TheISA::Kernel::Statistics(system); - } else { - kernelStats = NULL; - } } #else SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, TheISA::ITB *_itb, TheISA::DTB *_dtb, int _asid) - : ThreadState(_cpu, -1, _thread_num, _process, _asid), + : ThreadState(_cpu, _thread_num, _process, _asid), cpu(_cpu), itb(_itb), dtb(_dtb) { regs.clear(); @@ -106,9 +104,9 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, SimpleThread::SimpleThread() #if FULL_SYSTEM - : ThreadState(NULL, -1, -1) + : ThreadState(NULL, -1) #else - : ThreadState(NULL, -1, -1, NULL, -1) + : ThreadState(NULL, -1, NULL, -1) #endif { tc = new ProxyThreadContext<SimpleThread>(this); @@ -180,18 +178,20 @@ SimpleThread::copyState(ThreadContext *oldContext) // copy over functional state _status = oldContext->status(); copyArchRegs(oldContext); - cpuId = oldContext->readCpuId(); #if !FULL_SYSTEM funcExeInst = oldContext->readFuncExeInst(); #endif inst = oldContext->getInst(); + + _threadId = oldContext->threadId(); + _contextId = oldContext->contextId(); } void SimpleThread::serialize(ostream &os) { ThreadState::serialize(os); - regs.serialize(os); + regs.serialize(cpu, os); // thread_num and cpu_id are deterministic from the config } @@ -200,7 +200,7 @@ void SimpleThread::unserialize(Checkpoint *cp, const std::string §ion) { ThreadState::unserialize(cp, section); - regs.unserialize(cp, section); + regs.unserialize(cpu, cp, section); // thread_num and cpu_id are deterministic from the config } @@ -222,14 +222,14 @@ SimpleThread::activate(int delay) lastActivate = curTick; // if (status() == ThreadContext::Unallocated) { -// cpu->activateWhenReady(tid); -// return; +// cpu->activateWhenReady(_threadId); +// return; // } _status = ThreadContext::Active; // status() == Suspended - cpu->activateContext(tid, delay); + cpu->activateContext(_threadId, delay); } void @@ -243,14 +243,14 @@ SimpleThread::suspend() /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { + if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } #endif */ _status = ThreadContext::Suspended; - cpu->suspendContext(tid); + cpu->suspendContext(_threadId); } void @@ -260,7 +260,7 @@ SimpleThread::deallocate() return; _status = ThreadContext::Unallocated; - cpu->deallocateContext(tid); + cpu->deallocateContext(_threadId); } void @@ -270,7 +270,7 @@ SimpleThread::halt() return; _status = ThreadContext::Halted; - cpu->haltContext(tid); + cpu->haltContext(_threadId); } @@ -289,26 +289,3 @@ SimpleThread::copyArchRegs(ThreadContext *src_tc) TheISA::copyRegs(src_tc, tc); } -#if FULL_SYSTEM -VirtualPort* -SimpleThread::getVirtPort(ThreadContext *src_tc) -{ - if (!src_tc) - return virtPort; - - VirtualPort *vp = new VirtualPort("tc-vport", src_tc); - connectToMemFunc(vp); - return vp; -} - -void -SimpleThread::delVirtPort(VirtualPort *vp) -{ - if (vp != virtPort) { - vp->removeConn(); - delete vp; - } -} - -#endif - diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index fa80a283a..73929d362 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -34,7 +34,6 @@ #include "arch/isa_traits.hh" #include "arch/regfile.hh" -#include "arch/syscallreturn.hh" #include "arch/tlb.hh" #include "config/full_system.hh" #include "cpu/thread_context.hh" @@ -99,7 +98,7 @@ class SimpleThread : public ThreadState typedef ThreadContext::Status Status; protected: - RegFile regs; // correct-path register context + RegFile regs; // correct-path register context public: // pointer to CPU associated with this SimpleThread @@ -139,7 +138,7 @@ class SimpleThread : public ThreadState /*************************************************************** * SimpleThread functions to provide CPU with access to various - * state, and to provide address translation methods. + * state. **************************************************************/ /** Returns the pointer to this SimpleThread's ThreadContext. Used @@ -148,21 +147,6 @@ class SimpleThread : public ThreadState */ ThreadContext *getTC() { return tc; } - Fault translateInstReq(RequestPtr &req) - { - return itb->translate(req, tc); - } - - Fault translateDataReadReq(RequestPtr &req) - { - return dtb->translate(req, tc, false); - } - - Fault translateDataWriteReq(RequestPtr &req) - { - return dtb->translate(req, tc, true); - } - void demapPage(Addr vaddr, uint64_t asn) { itb->demapPage(vaddr, asn); @@ -197,23 +181,20 @@ class SimpleThread : public ThreadState BaseCPU *getCpuPtr() { return cpu; } - int getThreadNum() { return tid; } - TheISA::ITB *getITBPtr() { return itb; } TheISA::DTB *getDTBPtr() { return dtb; } -#if FULL_SYSTEM System *getSystemPtr() { return system; } +#if FULL_SYSTEM FunctionalPort *getPhysPort() { return physPort; } - /** Return a virtual port. If no thread context is specified then a static - * port is returned. Otherwise a port is created and returned. It must be - * deleted by deleteVirtPort(). */ - VirtualPort *getVirtPort(ThreadContext *tc); - - void delVirtPort(VirtualPort *vp); + /** Return a virtual port. This port cannot be cached locally in an object. + * After a CPU switch it may point to the wrong memory object which could + * mean stale data. + */ + VirtualPort *getVirtPort() { return virtPort; } #endif Status status() const { return _status; } @@ -385,37 +366,11 @@ class SimpleThread : public ThreadState { storeCondFailures = sc_failures; } #if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - assert(i < TheISA::NumArgumentRegs); - return regs.readIntReg(TheISA::flattenIntIndex(getTC(), - TheISA::ArgumentReg[i])); - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - assert(i < TheISA::NumArgumentRegs); - regs.setIntReg(TheISA::flattenIntIndex(getTC(), - TheISA::ArgumentReg[i]), val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - TheISA::setSyscallReturn(return_value, getTC()); - } - void syscall(int64_t callnum) { process->syscall(callnum, tc); } #endif - - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - regs.changeContext(param, val); - } }; diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc index 52a7ede03..01136bda1 100644 --- a/src/cpu/static_inst.cc +++ b/src/cpu/static_inst.cc @@ -40,11 +40,17 @@ StaticInst::DecodeCache StaticInst::decodeCache; StaticInst::AddrDecodeCache StaticInst::addrDecodeCache; StaticInst::cacheElement StaticInst::recentDecodes[2]; +using namespace std; + +StaticInst::~StaticInst() +{ + if (cachedDisassembly) + delete cachedDisassembly; +} + 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; @@ -81,6 +87,37 @@ StaticInstPtr StaticInst::fetchMicroop(MicroPC micropc) { panic("StaticInst::fetchMicroop() called on instruction " - "that is not microcoded."); + "that is not microcoded."); } +Addr +StaticInst::branchTarget(Addr branchPC) const +{ + panic("StaticInst::branchTarget() called on instruction " + "that is not a PC-relative branch."); + M5_DUMMY_RETURN; +} + +Addr +StaticInst::branchTarget(ThreadContext *tc) const +{ + panic("StaticInst::branchTarget() called on instruction " + "that is not an indirect branch."); + M5_DUMMY_RETURN; +} + +Request::Flags +StaticInst::memAccFlags() +{ + panic("StaticInst::memAccFlags called on non-memory instruction"); + return 0; +} + +const string & +StaticInst::disassemble(Addr pc, const SymbolTable *symtab) const +{ + if (!cachedDisassembly) + cachedDisassembly = new string(generateDisassembly(pc, symtab)); + + return *cachedDisassembly; +} diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index ceda78d90..cb32f2333 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -42,7 +42,6 @@ #include "base/misc.hh" #include "base/refcnt.hh" #include "cpu/op_class.hh" -#include "cpu/o3/dyn_inst.hh" #include "sim/faults.hh" #include "sim/host.hh" @@ -54,8 +53,11 @@ class ThreadContext; class DynInst; class Packet; -template <class Impl> -class OzoneDynInst; +class O3CPUImpl; +template <class Impl> class BaseO3DynInst; +typedef BaseO3DynInst<O3CPUImpl> O3DynInst; +template <class Impl> class OzoneDynInst; +class InOrderDynInst; class CheckerCPU; class FastCPU; @@ -69,7 +71,27 @@ namespace Trace { class InstRecord; } -typedef uint32_t MicroPC; +typedef uint16_t MicroPC; + +static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1); + +static inline MicroPC +romMicroPC(MicroPC upc) +{ + return upc | MicroPCRomBit; +} + +static inline MicroPC +normalMicroPC(MicroPC upc) +{ + return upc & ~MicroPCRomBit; +} + +static inline bool +isRomMicroPC(MicroPC upc) +{ + return MicroPCRomBit & upc; +} /** * Base, ISA-independent static instruction class. @@ -105,38 +127,39 @@ class StaticInstBase : public RefCounted /// implement this behavior via the execute() methods. /// enum Flags { - IsNop, ///< Is a no-op (no effect at all). + IsNop, ///< Is a no-op (no effect at all). - IsInteger, ///< References integer regs. - IsFloating, ///< References FP regs. + 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. + IsMemRef, ///< References memory (load, store, or prefetch). + IsLoad, ///< Reads from memory (load or prefetch). + IsStore, ///< Writes to memory. IsStoreConditional, ///< Store conditional instruction. IsIndexed, ///< Accesses memory with an indexed address computation - IsInstPrefetch, ///< Instruction-cache prefetch. - IsDataPrefetch, ///< Data-cache prefetch. + 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. + 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. + IsThreadSync, ///< Thread synchronization operation. - IsSerializing, ///< Serializes pipeline: won't execute until all + IsSerializing, ///< Serializes pipeline: won't execute until all /// older instructions have committed. IsSerializeBefore, IsSerializeAfter, - IsMemBarrier, ///< Is a memory barrier - IsWriteBarrier, ///< Is a write barrier + IsMemBarrier, ///< Is a memory barrier + IsWriteBarrier, ///< Is a write barrier + IsReadBarrier, ///< Is a read barrier IsERET, /// <- Causes the IFU to stall (MIPS ISA) IsNonSpeculative, ///< Should not be executed speculatively @@ -150,12 +173,12 @@ class StaticInstBase : public RefCounted //Flags for microcode IsMacroop, ///< Is a macroop containing microops - IsMicroop, ///< Is a microop - IsDelayedCommit, ///< This microop doesn't commit right away - IsLastMicroop, ///< This microop ends a microop sequence - IsFirstMicroop, ///< This microop begins a microop sequence + IsMicroop, ///< Is a microop + IsDelayedCommit, ///< This microop doesn't commit right away + IsLastMicroop, ///< This microop ends a microop sequence + IsFirstMicroop, ///< This microop begins a microop sequence //This flag doesn't do anything yet - IsMicroBranch, ///< This microop branches within the microcode for a macroop + IsMicroBranch, ///< This microop branches within the microcode for a macroop IsDspOp, NumFlags @@ -215,26 +238,26 @@ class StaticInstBase : public RefCounted /// of the individual flags. //@{ - bool isNop() const { return flags[IsNop]; } + 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 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 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 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 isCondCtrl() const { return flags[IsCondControl]; } + bool isUncondCtrl() const { return flags[IsUncondControl]; } bool isCondDelaySlot() const { return flags[IsCondDelaySlot]; } bool isThreadSync() const { return flags[IsThreadSync]; } @@ -287,8 +310,8 @@ class StaticInst : public StaticInstBase typedef TheISA::RegIndex RegIndex; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs }; @@ -360,12 +383,7 @@ class StaticInst : public StaticInstBase { } public: - - virtual ~StaticInst() - { - if (cachedDisassembly) - delete cachedDisassembly; - } + virtual ~StaticInst(); /** * The execute() signatures are auto-generated by scons based on the @@ -384,12 +402,7 @@ class StaticInst : public StaticInstBase * 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."); - M5_DUMMY_RETURN - } + virtual Addr branchTarget(Addr branchPC) const; /** * Return the target address for an indirect branch (jump). The @@ -398,12 +411,7 @@ class StaticInst : public StaticInstBase * execute the branch in question. Invalid if not an indirect * branch (i.e. isIndirectCtrl() should be true). */ - virtual Addr branchTarget(ThreadContext *tc) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not an indirect branch."); - M5_DUMMY_RETURN - } + virtual Addr branchTarget(ThreadContext *tc) const; /** * Return true if the instruction is a control transfer, and if so, @@ -411,6 +419,8 @@ class StaticInst : public StaticInstBase */ bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const; + virtual Request::Flags memAccFlags(); + /** * Return string representation of disassembled instruction. * The default version of this function will call the internal @@ -419,14 +429,7 @@ class StaticInst : public StaticInstBase * 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; - } + const SymbolTable *symtab = 0) const; /// Decoded instruction cache type. /// For now we're using a generic hash_map; this seems to work @@ -458,13 +461,13 @@ class StaticInst : public StaticInstBase /// A cache of decoded instruction objects from addresses. static AddrDecodeCache addrDecodeCache; - struct cacheElement { + struct cacheElement + { Addr page_addr; AddrDecodePage *decodePage; - cacheElement() - :decodePage(NULL) { } - } ; + cacheElement() : decodePage(NULL) { } + }; /// An array of recently decoded instructions. // might not use an array if there is only two elements @@ -493,7 +496,7 @@ class StaticInst : public StaticInstBase /// @retval A pointer to the corresponding StaticInst object. //This is defined as inlined below. static StaticInstPtr searchCache(ExtMachInst mach_inst, Addr addr, - AddrDecodePage * decodePage); + AddrDecodePage *decodePage); }; typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; @@ -547,7 +550,8 @@ class AddrDecodePage public: /// Constructor - AddrDecodePage() { + AddrDecodePage() + { lowerMask = TheISA::PageBytes - 1; memset(valid, 0, TheISA::PageBytes); } @@ -557,7 +561,8 @@ class AddrDecodePage /// related to the address /// @param mach_inst The binary instruction to check /// @param addr The address containing the instruction - inline bool decoded(ExtMachInst mach_inst, Addr addr) + bool + decoded(ExtMachInst mach_inst, Addr addr) { return (valid[addr & lowerMask] && (instructions[addr & lowerMask]->machInst == mach_inst)); @@ -567,19 +572,22 @@ class AddrDecodePage /// to check if the instruction is valid. /// @param addr The address of the instruction. /// @retval A pointer to the corresponding StaticInst object. - inline StaticInstPtr getInst(Addr addr) - { return instructions[addr & lowerMask]; } + StaticInstPtr + getInst(Addr addr) + { + return instructions[addr & lowerMask]; + } /// Inserts a pointer to a StaticInst object into the list of decoded /// instructions on the page. /// @param addr The address of the instruction. /// @param si A pointer to the corresponding StaticInst object. - inline void insert(Addr addr, StaticInstPtr &si) + void + insert(Addr addr, StaticInstPtr &si) { instructions[addr & lowerMask] = si; valid[addr & lowerMask] = true; } - }; @@ -628,7 +636,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr) } // creates a new object for a page of decoded instructions - AddrDecodePage * decodePage = new AddrDecodePage; + AddrDecodePage *decodePage = new AddrDecodePage; addrDecodeCache[page_addr] = decodePage; updateCache(page_addr, decodePage); return searchCache(mach_inst, addr, decodePage); @@ -636,7 +644,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr) inline StaticInstPtr StaticInst::searchCache(ExtMachInst mach_inst, Addr addr, - AddrDecodePage * decodePage) + AddrDecodePage *decodePage) { DecodeCache::iterator iter = decodeCache.find(mach_inst); if (iter != decodeCache.end()) { diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc index 10c94027d..ab105a435 100644 --- a/src/cpu/thread_context.cc +++ b/src/cpu/thread_context.cc @@ -74,8 +74,15 @@ ThreadContext::compare(ThreadContext *one, ThreadContext *two) if (npc1 != npc2) panic("NPCs doesn't match, one: %#x, two: %#x", npc1, npc2); - int id1 = one->readCpuId(); - int id2 = two->readCpuId(); + int id1 = one->cpuId(); + int id2 = two->cpuId(); if (id1 != id2) panic("CPU ids don't match, one: %d, two: %d", id1, id2); + + id1 = one->contextId(); + id2 = two->contextId(); + if (id1 != id2) + panic("Context ids don't match, one: %d, two: %d", id1, id2); + + } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index cf51c1637..700f1571e 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -38,7 +38,6 @@ #include "sim/faults.hh" #include "sim/host.hh" #include "sim/serialize.hh" -#include "sim/syscallreturn.hh" #include "sim/byteswap.hh" // @todo: Figure out a more architecture independent way to obtain the ITB and @@ -115,26 +114,30 @@ class ThreadContext virtual BaseCPU *getCpuPtr() = 0; - virtual void setCpuId(int id) = 0; + virtual int cpuId() = 0; - virtual int readCpuId() = 0; + virtual int threadId() = 0; + + virtual void setThreadId(int id) = 0; + + virtual int contextId() = 0; + + virtual void setContextId(int id) = 0; virtual TheISA::ITB *getITBPtr() = 0; virtual TheISA::DTB *getDTBPtr() = 0; -#if FULL_SYSTEM virtual System *getSystemPtr() = 0; +#if FULL_SYSTEM virtual TheISA::Kernel::Statistics *getKernelStats() = 0; virtual FunctionalPort *getPhysPort() = 0; - virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0; - - virtual void delVirtPort(VirtualPort *vp) = 0; + virtual VirtualPort *getVirtPort() = 0; - virtual void connectMemPorts() = 0; + virtual void connectMemPorts(ThreadContext *tc) = 0; #else virtual TranslatingPort *getMemPort() = 0; @@ -181,8 +184,6 @@ class ThreadContext 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; @@ -256,13 +257,6 @@ class ThreadContext 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; - // Same with st cond failures. virtual Counter readFuncExeInst() = 0; @@ -274,9 +268,6 @@ class ThreadContext virtual int exit() { return 1; }; #endif - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) = 0; - /** function to compare two thread contexts (for debugging) */ static void compare(ThreadContext *one, ThreadContext *two); }; @@ -305,27 +296,31 @@ class ProxyThreadContext : public ThreadContext BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); } - void setCpuId(int id) { actualTC->setCpuId(id); } + int cpuId() { return actualTC->cpuId(); } + + int threadId() { return actualTC->threadId(); } - int readCpuId() { return actualTC->readCpuId(); } + void setThreadId(int id) { return actualTC->setThreadId(id); } + + int contextId() { return actualTC->contextId(); } + + void setContextId(int id) { actualTC->setContextId(id); } TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } TheISA::DTB *getDTBPtr() { return actualTC->getDTBPtr(); } -#if FULL_SYSTEM System *getSystemPtr() { return actualTC->getSystemPtr(); } +#if FULL_SYSTEM TheISA::Kernel::Statistics *getKernelStats() { return actualTC->getKernelStats(); } FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return actualTC->getVirtPort(tc); } - - void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); } + VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } - void connectMemPorts() { actualTC->connectMemPorts(); } + void connectMemPorts(ThreadContext *tc) { actualTC->connectMemPorts(tc); } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } @@ -371,9 +366,6 @@ class ProxyThreadContext : public ThreadContext void profileClear() { return actualTC->profileClear(); } void profileSample() { return actualTC->profileSample(); } #endif - - int getThreadNum() { return actualTC->getThreadNum(); } - // @todo: Do I need this? MachInst getInst() { return actualTC->getInst(); } @@ -433,7 +425,7 @@ class ProxyThreadContext : public ThreadContext uint64_t readNextMicroPC() { return actualTC->readMicroPC(); } - void setNextMicroPC(uint64_t val) { actualTC->setMicroPC(val); } + void setNextMicroPC(uint64_t val) { actualTC->setNextMicroPC(val); } MiscReg readMiscRegNoEffect(int misc_reg) { return actualTC->readMiscRegNoEffect(misc_reg); } @@ -457,26 +449,11 @@ class ProxyThreadContext : public ThreadContext bool misspeculating() { return actualTC->misspeculating(); } #if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { actualTC->setSyscallArg(i, val); } - - void setSyscallReturn(SyscallReturn return_value) - { actualTC->setSyscallReturn(return_value); } - void syscall(int64_t callnum) { actualTC->syscall(callnum); } Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif - - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - actualTC->changeRegFileContext(param, val); - } }; #endif diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index be8f822f2..b0e719ddf 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -43,15 +43,15 @@ #endif #if FULL_SYSTEM -ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid) - : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), +ThreadState::ThreadState(BaseCPU *cpu, int _tid) + : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0), profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL), - physPort(NULL), virtPort(NULL), + kernelStats(NULL), physPort(NULL), virtPort(NULL), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #else -ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, +ThreadState::ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid) - : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), + : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0), port(NULL), process(_process), asid(_asid), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #endif @@ -105,7 +105,7 @@ ThreadState::unserialize(Checkpoint *cp, const std::string §ion) Tick quiesceEndTick; UNSERIALIZE_SCALAR(quiesceEndTick); if (quiesceEndTick) - quiesceEvent->schedule(quiesceEndTick); + baseCpu->schedule(quiesceEvent, quiesceEndTick); if (kernelStats) kernelStats->unserialize(cp, section); #endif @@ -113,10 +113,10 @@ ThreadState::unserialize(Checkpoint *cp, const std::string §ion) #if FULL_SYSTEM void -ThreadState::connectMemPorts() +ThreadState::connectMemPorts(ThreadContext *tc) { connectPhysPort(); - connectVirtPort(); + connectVirtPort(tc); } void @@ -129,12 +129,12 @@ ThreadState::connectPhysPort() physPort->removeConn(); else physPort = new FunctionalPort(csprintf("%s-%d-funcport", - baseCpu->name(), tid)); + baseCpu->name(), _threadId)); connectToMemFunc(physPort); } void -ThreadState::connectVirtPort() +ThreadState::connectVirtPort(ThreadContext *tc) { // @todo: For now this disregards any older port that may have // already existed. Fix this memory leak once the bus port IDs @@ -143,7 +143,7 @@ ThreadState::connectVirtPort() virtPort->removeConn(); else virtPort = new VirtualPort(csprintf("%s-%d-vport", - baseCpu->name(), tid)); + baseCpu->name(), _threadId), tc); connectToMemFunc(virtPort); } @@ -169,7 +169,7 @@ ThreadState::getMemPort() return port; /* Use this port to for syscall emulation writes to memory. */ - port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), tid), + port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), _threadId), process, TranslatingPort::NextPage); connectToMemFunc(port); diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 4f878db1f..99f0c2a87 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -34,6 +34,7 @@ #include "arch/types.hh" #include "cpu/profile.hh" #include "cpu/thread_context.hh" +#include "cpu/base.hh" #if !FULL_SYSTEM #include "mem/mem_object.hh" @@ -51,7 +52,6 @@ namespace TheISA { }; #endif -class BaseCPU; class Checkpoint; class Port; class TranslatingPort; @@ -66,9 +66,9 @@ struct ThreadState { typedef ThreadContext::Status Status; #if FULL_SYSTEM - ThreadState(BaseCPU *cpu, int _cpuId, int _tid); + ThreadState(BaseCPU *cpu, int _tid); #else - ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, + ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid); #endif @@ -78,24 +78,26 @@ struct ThreadState { void unserialize(Checkpoint *cp, const std::string §ion); - void setCpuId(int id) { cpuId = id; } + int cpuId() { return baseCpu->cpuId(); } - int readCpuId() { return cpuId; } + int contextId() { return _contextId; } - void setTid(int id) { tid = id; } + void setContextId(int id) { _contextId = id; } - int readTid() { return tid; } + void setThreadId(int id) { _threadId = id; } + + int threadId() { return _threadId; } Tick readLastActivate() { return lastActivate; } Tick readLastSuspend() { return lastSuspend; } #if FULL_SYSTEM - void connectMemPorts(); + void connectMemPorts(ThreadContext *tc); void connectPhysPort(); - void connectVirtPort(); + void connectVirtPort(ThreadContext *tc); void dumpFuncProfile(); @@ -111,9 +113,7 @@ struct ThreadState { void setPhysPort(FunctionalPort *port) { physPort = port; } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; } - - void setVirtPort(VirtualPort *port) { virtPort = port; } + VirtualPort *getVirtPort() { return virtPort; } #else Process *getProcessPtr() { return process; } @@ -155,9 +155,9 @@ struct ThreadState { /** Number of instructions committed. */ Counter numInst; /** Stat for number instructions committed. */ - Stats::Scalar<> numInsts; + Stats::Scalar numInsts; /** Stat for number of memory references. */ - Stats::Scalar<> numMemRefs; + Stats::Scalar numMemRefs; /** Number of simulated loads, used for tracking events based on * the number of loads committed. @@ -173,12 +173,11 @@ struct ThreadState { // Pointer to the base CPU. BaseCPU *baseCpu; - // 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 cpuId; + // system wide HW context id + int _contextId; // Index of hardware thread context on the CPU that this represents. - int tid; + int _threadId; public: /** Last time activate was called on this thread. */ @@ -201,7 +200,7 @@ struct ThreadState { FunctionalPort *physPort; /** A functional port, outgoing only, for functional accesse to virtual - * addresses. That doen't require execution context information */ + * addresses. */ VirtualPort *virtPort; #else TranslatingPort *port; |