Adding gem5 source to svn.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1819 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
78
simulators/gem5/src/cpu/inorder/InOrderCPU.py
Normal file
78
simulators/gem5/src/cpu/inorder/InOrderCPU.py
Normal file
@ -0,0 +1,78 @@
|
||||
# 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 BaseCPU import BaseCPU
|
||||
|
||||
class ThreadModel(Enum):
|
||||
vals = ['Single', 'SMT', 'SwitchOnCacheMiss']
|
||||
|
||||
class InOrderCPU(BaseCPU):
|
||||
type = 'InOrderCPU'
|
||||
activity = Param.Unsigned(0, "Initial count")
|
||||
|
||||
threadModel = Param.ThreadModel('SMT', "Multithreading model (SE-MODE only)")
|
||||
|
||||
cachePorts = Param.Unsigned(2, "Cache Ports")
|
||||
stageWidth = Param.Unsigned(4, "Stage width")
|
||||
|
||||
fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)")
|
||||
memBlockSize = Param.Unsigned(64, "Memory Block Size")
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
35
simulators/gem5/src/cpu/inorder/InOrderTrace.py
Normal file
35
simulators/gem5/src/cpu/inorder/InOrderTrace.py
Normal file
@ -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'
|
||||
90
simulators/gem5/src/cpu/inorder/SConscript
Normal file
90
simulators/gem5/src/cpu/inorder/SConscript
Normal file
@ -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')
|
||||
|
||||
DebugFlag('ResReqCount')
|
||||
DebugFlag('InOrderStage')
|
||||
DebugFlag('InOrderStall')
|
||||
DebugFlag('InOrderCPU')
|
||||
DebugFlag('RegDepMap')
|
||||
DebugFlag('InOrderDynInst')
|
||||
DebugFlag('Resource')
|
||||
DebugFlag('InOrderAGEN')
|
||||
DebugFlag('InOrderFetchSeq')
|
||||
DebugFlag('InOrderTLB')
|
||||
DebugFlag('InOrderCachePort')
|
||||
DebugFlag('InOrderBPred')
|
||||
DebugFlag('InOrderDecode')
|
||||
DebugFlag('InOrderExecute')
|
||||
DebugFlag('InOrderInstBuffer')
|
||||
DebugFlag('InOrderUseDef')
|
||||
DebugFlag('InOrderMDU')
|
||||
DebugFlag('InOrderGraduation')
|
||||
DebugFlag('ThreadModel')
|
||||
DebugFlag('RefCount')
|
||||
DebugFlag('AddrDep')
|
||||
DebugFlag('SkedCache')
|
||||
|
||||
CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
|
||||
'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred',
|
||||
'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef',
|
||||
'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource',
|
||||
'InOrderStall','ThreadModel', 'AddrDep'])
|
||||
|
||||
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/fetch_unit.cc')
|
||||
Source('resources/use_def.cc')
|
||||
Source('resources/decode_unit.cc')
|
||||
Source('resources/inst_buffer.cc')
|
||||
Source('resources/graduation_unit.cc')
|
||||
Source('resources/fetch_seq_unit.cc')
|
||||
Source('resources/mult_div_unit.cc')
|
||||
Source('resource_pool.cc')
|
||||
Source('resource_sked.cc')
|
||||
Source('reg_dep_map.cc')
|
||||
Source('thread_state.cc')
|
||||
Source('thread_context.cc')
|
||||
Source('cpu.cc')
|
||||
|
||||
36
simulators/gem5/src/cpu/inorder/SConsopts
Normal file
36
simulators/gem5/src/cpu/inorder/SConsopts
Normal file
@ -0,0 +1,36 @@
|
||||
# -*- 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('*')
|
||||
|
||||
CpuModel('InOrderCPU', 'inorder_cpu_exec.cc',
|
||||
'#include "cpu/inorder/inorder_dyn_inst.hh"',
|
||||
{ 'CPU_exec_context': 'InOrderDynInst' },
|
||||
default=True)
|
||||
85
simulators/gem5/src/cpu/inorder/comm.hh
Normal file
85
simulators/gem5/src/cpu/inorder/comm.hh
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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/isa_traits.hh"
|
||||
#include "base/types.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
|
||||
/** Struct that defines the information passed from in between stages */
|
||||
/** This information mainly goes forward through the pipeline. */
|
||||
struct InterStageStruct {
|
||||
//@todo: probably should make this a list since the amount of
|
||||
// instructions that get passed forward per cycle is
|
||||
// really dependent on issue width, CPI, etc.
|
||||
std::vector<ThePipeline::DynInstPtr> insts;
|
||||
|
||||
// Add any information that needs to be passed forward to stages
|
||||
// below ...
|
||||
};
|
||||
|
||||
/** Struct that defines all backwards communication. */
|
||||
struct TimeStruct {
|
||||
struct StageComm {
|
||||
bool squash;
|
||||
InstSeqNum doneSeqNum;
|
||||
|
||||
bool uncached;
|
||||
ThePipeline::DynInstPtr uncachedLoad;
|
||||
|
||||
StageComm()
|
||||
: squash(false), doneSeqNum(0), uncached(false), uncachedLoad(NULL)
|
||||
{ }
|
||||
};
|
||||
|
||||
StageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads];
|
||||
bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads];
|
||||
bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads];
|
||||
|
||||
TimeStruct()
|
||||
{
|
||||
for (int i = 0; i < ThePipeline::NumStages; i++) {
|
||||
for (int j = 0; j < ThePipeline::MaxThreads; j++) {
|
||||
stageBlock[i][j] = false;
|
||||
stageUnblock[i][j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_COMM_HH__
|
||||
1794
simulators/gem5/src/cpu/inorder/cpu.cc
Normal file
1794
simulators/gem5/src/cpu/inorder/cpu.cc
Normal file
File diff suppressed because it is too large
Load Diff
934
simulators/gem5/src/cpu/inorder/cpu.hh
Normal file
934
simulators/gem5/src/cpu/inorder/cpu.hh
Normal file
@ -0,0 +1,934 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 "arch/registers.hh"
|
||||
#include "arch/types.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "base/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_stage.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "cpu/inorder/thread_state.hh"
|
||||
#include "cpu/o3/dep_graph.hh"
|
||||
#include "cpu/o3/rename_map.hh"
|
||||
#include "cpu/activity.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class CacheUnit;
|
||||
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::RegIndex RegIndex;
|
||||
|
||||
//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);
|
||||
/* Destructor */
|
||||
~InOrderCPU();
|
||||
|
||||
/** Return a reference to the data port. */
|
||||
virtual CpuPort &getDataPort() { return dataPort; }
|
||||
|
||||
/** Return a reference to the instruction port. */
|
||||
virtual CpuPort &getInstPort() { return instPort; }
|
||||
|
||||
/** CPU ID */
|
||||
int cpu_id;
|
||||
|
||||
// SE Mode ASIDs
|
||||
ThreadID asid[ThePipeline::MaxThreads];
|
||||
|
||||
/** Type of core that this is */
|
||||
std::string coreType;
|
||||
|
||||
// Only need for SE MODE
|
||||
enum ThreadModel {
|
||||
Single,
|
||||
SMT,
|
||||
SwitchOnCacheMiss
|
||||
};
|
||||
|
||||
ThreadModel threadModel;
|
||||
|
||||
int readCpuId() { return cpu_id; }
|
||||
|
||||
void setCpuId(int val) { cpu_id = val; }
|
||||
|
||||
Params *cpu_params;
|
||||
|
||||
public:
|
||||
enum Status {
|
||||
Running,
|
||||
Idle,
|
||||
Halted,
|
||||
Blocked,
|
||||
SwitchedOut
|
||||
};
|
||||
|
||||
/** Overall CPU status. */
|
||||
Status _status;
|
||||
private:
|
||||
|
||||
/**
|
||||
* CachePort class for the in-order CPU, interacting with a
|
||||
* specific CacheUnit in the pipeline.
|
||||
*/
|
||||
class CachePort : public CpuPort
|
||||
{
|
||||
|
||||
private:
|
||||
/** Pointer to cache unit */
|
||||
CacheUnit *cacheUnit;
|
||||
|
||||
public:
|
||||
/** Default constructor. */
|
||||
CachePort(CacheUnit *_cacheUnit);
|
||||
|
||||
protected:
|
||||
|
||||
/** Timing version of receive */
|
||||
bool recvTimingResp(PacketPtr pkt);
|
||||
|
||||
/** Handles doing a retry of a failed timing request. */
|
||||
void recvRetry();
|
||||
|
||||
/** Ignoring snoops for now. */
|
||||
void recvTimingSnoopReq(PacketPtr pkt) { }
|
||||
};
|
||||
|
||||
/** 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() const;
|
||||
};
|
||||
|
||||
/** The tick event used for scheduling CPU ticks. */
|
||||
TickEvent tickEvent;
|
||||
|
||||
/** Schedule tick event, regardless of its current state. */
|
||||
void scheduleTickEvent(int delay)
|
||||
{
|
||||
assert(!tickEvent.scheduled() || tickEvent.squashed());
|
||||
reschedule(&tickEvent, nextCycle(curTick() + ticks(delay)), true);
|
||||
}
|
||||
|
||||
/** 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,
|
||||
ActivateNextReadyThread,
|
||||
DeactivateThread,
|
||||
HaltThread,
|
||||
SuspendThread,
|
||||
Trap,
|
||||
Syscall,
|
||||
SquashFromMemStall,
|
||||
UpdatePCs,
|
||||
NumCPUEvents
|
||||
};
|
||||
|
||||
static std::string eventNames[NumCPUEvents];
|
||||
|
||||
enum CPUEventPri {
|
||||
InOrderCPU_Pri = Event::CPU_Tick_Pri,
|
||||
Syscall_Pri = Event::CPU_Tick_Pri + 9,
|
||||
ActivateNextReadyThread_Pri = Event::CPU_Tick_Pri + 10
|
||||
};
|
||||
|
||||
/** Define CPU Event */
|
||||
class CPUEvent : public Event
|
||||
{
|
||||
protected:
|
||||
InOrderCPU *cpu;
|
||||
|
||||
public:
|
||||
CPUEventType cpuEventType;
|
||||
ThreadID tid;
|
||||
DynInstPtr inst;
|
||||
Fault fault;
|
||||
unsigned vpe;
|
||||
short syscall_num;
|
||||
|
||||
public:
|
||||
/** Constructs a CPU event. */
|
||||
CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault,
|
||||
ThreadID _tid, DynInstPtr inst, CPUEventPri event_pri);
|
||||
|
||||
/** Set Type of Event To Be Scheduled */
|
||||
void setEvent(CPUEventType e_type, Fault _fault, ThreadID _tid,
|
||||
DynInstPtr _inst)
|
||||
{
|
||||
fault = _fault;
|
||||
cpuEventType = e_type;
|
||||
tid = _tid;
|
||||
inst = _inst;
|
||||
vpe = 0;
|
||||
}
|
||||
|
||||
/** Processes a CPU event. */
|
||||
void process();
|
||||
|
||||
/** Returns the description of the CPU event. */
|
||||
const char *description() const;
|
||||
|
||||
/** Schedule Event */
|
||||
void scheduleEvent(int delay);
|
||||
|
||||
/** Unschedule This Event */
|
||||
void unscheduleEvent();
|
||||
};
|
||||
|
||||
/** Schedule a CPU Event */
|
||||
void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, ThreadID tid,
|
||||
DynInstPtr inst, unsigned delay = 0,
|
||||
CPUEventPri event_pri = InOrderCPU_Pri);
|
||||
|
||||
public:
|
||||
|
||||
/** Width (processing bandwidth) of each stage */
|
||||
int stageWidth;
|
||||
|
||||
/** Interface between the CPU and CPU resources. */
|
||||
ResourcePool *resPool;
|
||||
|
||||
/** Instruction used to signify that there is no *real* instruction in
|
||||
buffer slot */
|
||||
DynInstPtr dummyInst[ThePipeline::MaxThreads];
|
||||
DynInstPtr dummyBufferInst;
|
||||
DynInstPtr dummyReqInst;
|
||||
DynInstPtr dummyTrapInst[ThePipeline::MaxThreads];
|
||||
|
||||
/** Used by resources to signify a denied access to a resource. */
|
||||
ResourceRequest *dummyReq[ThePipeline::MaxThreads];
|
||||
|
||||
/** The Pipeline Stages for the CPU */
|
||||
PipelineStage *pipelineStage[ThePipeline::NumStages];
|
||||
|
||||
/** Program Counters */
|
||||
TheISA::PCState pc[ThePipeline::MaxThreads];
|
||||
|
||||
/** Last Committed PC */
|
||||
TheISA::PCState lastCommittedPC[ThePipeline::MaxThreads];
|
||||
|
||||
/** The Register File for the CPU */
|
||||
union {
|
||||
FloatReg f[ThePipeline::MaxThreads][TheISA::NumFloatRegs];
|
||||
FloatRegBits i[ThePipeline::MaxThreads][TheISA::NumFloatRegs];
|
||||
} floatRegs;
|
||||
TheISA::IntReg intRegs[ThePipeline::MaxThreads][TheISA::NumIntRegs];
|
||||
|
||||
/** ISA state */
|
||||
TheISA::ISA isa[ThePipeline::MaxThreads];
|
||||
|
||||
/** Dependency Tracker for Integer & Floating Point Regs */
|
||||
RegDepMap archRegDepMap[ThePipeline::MaxThreads];
|
||||
|
||||
/** Register Types Used in Dependency Tracking */
|
||||
enum RegType { IntType, FloatType, MiscType, NumRegTypes};
|
||||
|
||||
/** Global communication structure */
|
||||
TimeBuffer<TimeStruct> timeBuffer;
|
||||
|
||||
/** Communication structure that sits in between pipeline stages */
|
||||
StageQueue *stageQueue[ThePipeline::NumStages-1];
|
||||
|
||||
TheISA::TLB *getITBPtr();
|
||||
TheISA::TLB *getDTBPtr();
|
||||
|
||||
TheISA::Decoder *getDecoderPtr(unsigned tid);
|
||||
|
||||
/** Accessor Type for the SkedCache */
|
||||
typedef uint32_t SkedID;
|
||||
|
||||
/** Cache of Instruction Schedule using the instruction's name as a key */
|
||||
static m5::hash_map<SkedID, ThePipeline::RSkedPtr> skedCache;
|
||||
|
||||
typedef m5::hash_map<SkedID, ThePipeline::RSkedPtr>::iterator SkedCacheIt;
|
||||
|
||||
/** Initialized to last iterator in map, signifying a invalid entry
|
||||
on map searches
|
||||
*/
|
||||
SkedCacheIt endOfSkedIt;
|
||||
|
||||
ThePipeline::RSkedPtr frontEndSked;
|
||||
ThePipeline::RSkedPtr faultSked;
|
||||
|
||||
/** Add a new instruction schedule to the schedule cache */
|
||||
void addToSkedCache(DynInstPtr inst, ThePipeline::RSkedPtr inst_sked)
|
||||
{
|
||||
SkedID sked_id = genSkedID(inst);
|
||||
assert(skedCache.find(sked_id) == skedCache.end());
|
||||
skedCache[sked_id] = inst_sked;
|
||||
}
|
||||
|
||||
|
||||
/** Find a instruction schedule */
|
||||
ThePipeline::RSkedPtr lookupSked(DynInstPtr inst)
|
||||
{
|
||||
SkedID sked_id = genSkedID(inst);
|
||||
SkedCacheIt lookup_it = skedCache.find(sked_id);
|
||||
|
||||
if (lookup_it != endOfSkedIt) {
|
||||
return (*lookup_it).second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t INST_OPCLASS = 26;
|
||||
static const uint8_t INST_LOAD = 25;
|
||||
static const uint8_t INST_STORE = 24;
|
||||
static const uint8_t INST_CONTROL = 23;
|
||||
static const uint8_t INST_NONSPEC = 22;
|
||||
static const uint8_t INST_DEST_REGS = 18;
|
||||
static const uint8_t INST_SRC_REGS = 14;
|
||||
static const uint8_t INST_SPLIT_DATA = 13;
|
||||
|
||||
inline SkedID genSkedID(DynInstPtr inst)
|
||||
{
|
||||
SkedID id = 0;
|
||||
id = (inst->opClass() << INST_OPCLASS) |
|
||||
(inst->isLoad() << INST_LOAD) |
|
||||
(inst->isStore() << INST_STORE) |
|
||||
(inst->isControl() << INST_CONTROL) |
|
||||
(inst->isNonSpeculative() << INST_NONSPEC) |
|
||||
(inst->numDestRegs() << INST_DEST_REGS) |
|
||||
(inst->numSrcRegs() << INST_SRC_REGS) |
|
||||
(inst->splitInst << INST_SPLIT_DATA);
|
||||
return id;
|
||||
}
|
||||
|
||||
ThePipeline::RSkedPtr createFrontEndSked();
|
||||
ThePipeline::RSkedPtr createFaultSked();
|
||||
ThePipeline::RSkedPtr createBackEndSked(DynInstPtr inst);
|
||||
|
||||
class StageScheduler {
|
||||
private:
|
||||
ThePipeline::RSkedPtr rsked;
|
||||
int stageNum;
|
||||
int nextTaskPriority;
|
||||
|
||||
public:
|
||||
StageScheduler(ThePipeline::RSkedPtr _rsked, int stage_num)
|
||||
: rsked(_rsked), stageNum(stage_num),
|
||||
nextTaskPriority(0)
|
||||
{ }
|
||||
|
||||
void needs(int unit, int request) {
|
||||
rsked->push(new ScheduleEntry(
|
||||
stageNum, nextTaskPriority++, unit, request
|
||||
));
|
||||
}
|
||||
|
||||
void needs(int unit, int request, int param) {
|
||||
rsked->push(new ScheduleEntry(
|
||||
stageNum, nextTaskPriority++, unit, request, param
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/** Data port. Note that it has to appear after the resPool. */
|
||||
CachePort dataPort;
|
||||
|
||||
/** Instruction port. Note that it has to appear after the resPool. */
|
||||
CachePort instPort;
|
||||
|
||||
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();
|
||||
|
||||
/** HW return from error interrupt. */
|
||||
Fault hwrei(ThreadID tid);
|
||||
|
||||
bool simPalCheck(int palFunc, ThreadID tid);
|
||||
|
||||
void checkForInterrupts();
|
||||
|
||||
/** 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"); }
|
||||
|
||||
/** Check if this address is a valid instruction address. */
|
||||
bool validInstAddr(Addr addr) { return true; }
|
||||
|
||||
/** Check if this address is a valid data address. */
|
||||
bool validDataAddr(Addr addr) { return true; }
|
||||
|
||||
/** Schedule a syscall on the CPU */
|
||||
void syscallContext(Fault fault, ThreadID tid, DynInstPtr inst,
|
||||
int delay = 0);
|
||||
|
||||
/** Executes a syscall.*/
|
||||
void syscall(int64_t callnum, ThreadID tid);
|
||||
|
||||
/** Schedule a trap on the CPU */
|
||||
void trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0);
|
||||
|
||||
/** Perform trap to Handle Given Fault */
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
/** Schedule thread activation on the CPU */
|
||||
void activateContext(ThreadID tid, int delay = 0);
|
||||
|
||||
/** Add Thread to Active Threads List. */
|
||||
void activateThread(ThreadID tid);
|
||||
|
||||
/** Activate Thread In Each Pipeline Stage */
|
||||
void activateThreadInPipeline(ThreadID tid);
|
||||
|
||||
/** Schedule Thread Activation from Ready List */
|
||||
void activateNextReadyContext(int delay = 0);
|
||||
|
||||
/** Add Thread From Ready List to Active Threads List. */
|
||||
void activateNextReadyThread();
|
||||
|
||||
/** Schedule a thread deactivation on the CPU */
|
||||
void deactivateContext(ThreadID tid, int delay = 0);
|
||||
|
||||
/** Remove from Active Thread List */
|
||||
void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Schedule a thread suspension on the CPU */
|
||||
void suspendContext(ThreadID tid);
|
||||
|
||||
/** Suspend Thread, Remove from Active Threads List, Add to Suspend List */
|
||||
void suspendThread(ThreadID tid);
|
||||
|
||||
/** Schedule a thread halt on the CPU */
|
||||
void haltContext(ThreadID tid);
|
||||
|
||||
/** Halt Thread, Remove from Active Thread List, Place Thread on Halted
|
||||
* Threads List
|
||||
*/
|
||||
void haltThread(ThreadID tid);
|
||||
|
||||
/** squashFromMemStall() - sets up a squash event
|
||||
* squashDueToMemStall() - squashes pipeline
|
||||
* @note: maybe squashContext/squashThread would be better?
|
||||
*/
|
||||
void squashFromMemStall(DynInstPtr inst, ThreadID tid, int delay = 0);
|
||||
void squashDueToMemStall(int stage_num, InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
void removePipelineStalls(ThreadID tid);
|
||||
void squashThreadInPipeline(ThreadID tid);
|
||||
void squashBehindMemStall(int stage_num, InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
PipelineStage* getPipeStage(int stage_num);
|
||||
|
||||
int
|
||||
contextId()
|
||||
{
|
||||
hack_once("return a bogus context id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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(ThreadID tid)
|
||||
{ return globalSeqNum[tid]++; }
|
||||
|
||||
/** Get the current instruction sequence number, and increment it. */
|
||||
InstSeqNum nextInstSeqNum(ThreadID tid)
|
||||
{ return globalSeqNum[tid]; }
|
||||
|
||||
/** Increment Instruction Sequence Number */
|
||||
void incrInstSeqNum(ThreadID tid)
|
||||
{ globalSeqNum[tid]++; }
|
||||
|
||||
/** Set Instruction Sequence Number */
|
||||
void setInstSeqNum(ThreadID tid, InstSeqNum seq_num)
|
||||
{
|
||||
globalSeqNum[tid] = seq_num;
|
||||
}
|
||||
|
||||
/** Get & Update Next Event Number */
|
||||
InstSeqNum getNextEventNum()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
return cpuEventNum++;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Register file accessors */
|
||||
uint64_t readIntReg(RegIndex reg_idx, ThreadID tid);
|
||||
|
||||
FloatReg readFloatReg(RegIndex reg_idx, ThreadID tid);
|
||||
|
||||
FloatRegBits readFloatRegBits(RegIndex reg_idx, ThreadID tid);
|
||||
|
||||
void setIntReg(RegIndex reg_idx, uint64_t val, ThreadID tid);
|
||||
|
||||
void setFloatReg(RegIndex reg_idx, FloatReg val, ThreadID tid);
|
||||
|
||||
void setFloatRegBits(RegIndex reg_idx, FloatRegBits val, ThreadID tid);
|
||||
|
||||
RegType inline getRegType(RegIndex reg_idx)
|
||||
{
|
||||
if (reg_idx < TheISA::FP_Base_DepTag)
|
||||
return IntType;
|
||||
else if (reg_idx < TheISA::Ctrl_Base_DepTag)
|
||||
return FloatType;
|
||||
else
|
||||
return MiscType;
|
||||
}
|
||||
|
||||
RegIndex flattenRegIdx(RegIndex reg_idx, RegType ®_type, ThreadID tid);
|
||||
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscRegNoEffect(int misc_reg, ThreadID tid = 0);
|
||||
|
||||
/** Reads a misc. register, including any side effects the read
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
MiscReg readMiscReg(int misc_reg, ThreadID tid = 0);
|
||||
|
||||
/** Sets a miscellaneous register. */
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val,
|
||||
ThreadID 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, ThreadID tid = 0);
|
||||
|
||||
/** Reads a int/fp/misc reg. from another thread depending on ISA-defined
|
||||
* target thread
|
||||
*/
|
||||
uint64_t readRegOtherThread(unsigned misc_reg,
|
||||
ThreadID tid = InvalidThreadID);
|
||||
|
||||
/** Sets a int/fp/misc reg. from another thread depending on an ISA-defined
|
||||
* target thread
|
||||
*/
|
||||
void setRegOtherThread(unsigned misc_reg, const MiscReg &val,
|
||||
ThreadID tid);
|
||||
|
||||
/** Reads the commit PC of a specific thread. */
|
||||
TheISA::PCState
|
||||
pcState(ThreadID tid)
|
||||
{
|
||||
return pc[tid];
|
||||
}
|
||||
|
||||
/** Sets the commit PC of a specific thread. */
|
||||
void
|
||||
pcState(const TheISA::PCState &newPC, ThreadID tid)
|
||||
{
|
||||
pc[tid] = newPC;
|
||||
}
|
||||
|
||||
Addr instAddr(ThreadID tid) { return pc[tid].instAddr(); }
|
||||
Addr nextInstAddr(ThreadID tid) { return pc[tid].nextInstAddr(); }
|
||||
MicroPC microPC(ThreadID tid) { return pc[tid].microPC(); }
|
||||
|
||||
/** Function to add instruction onto the head of the list of the
|
||||
* instructions. Used when new instructions are fetched.
|
||||
*/
|
||||
ListIt addInst(DynInstPtr inst);
|
||||
|
||||
/** Find instruction on instruction list */
|
||||
ListIt findInst(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Function to tell the CPU that an instruction has completed. */
|
||||
void instDone(DynInstPtr inst, ThreadID 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,ThreadID tid);
|
||||
|
||||
/** Removes the instruction pointed to by the iterator. */
|
||||
inline void squashInstIt(const ListIt inst_it, ThreadID tid);
|
||||
|
||||
/** Cleans up all instructions on the instruction remove list. */
|
||||
void cleanUpRemovedInsts();
|
||||
|
||||
/** Cleans up all events 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, Addr addr,
|
||||
uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
/** Forwards an instruction write. to the appropriate data
|
||||
* resource (indexes into Resource Pool thru "dataPortIdx")
|
||||
*/
|
||||
Fault write(DynInstPtr inst, uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *write_res = NULL);
|
||||
|
||||
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;
|
||||
|
||||
bool trapPending[ThePipeline::MaxThreads];
|
||||
|
||||
/** 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<ThreadID> fetchPriorityList;
|
||||
|
||||
protected:
|
||||
/** Active Threads List */
|
||||
std::list<ThreadID> activeThreads;
|
||||
|
||||
/** Ready Threads List */
|
||||
std::list<ThreadID> readyThreads;
|
||||
|
||||
/** Suspended Threads List */
|
||||
std::list<ThreadID> suspendedThreads;
|
||||
|
||||
/** Halted Threads List */
|
||||
std::list<ThreadID> haltedThreads;
|
||||
|
||||
/** Thread Status Functions */
|
||||
bool isThreadActive(ThreadID tid);
|
||||
bool isThreadReady(ThreadID tid);
|
||||
bool isThreadSuspended(ThreadID 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:
|
||||
/** Number of Active Threads in the CPU */
|
||||
ThreadID numActiveThreads() { return activeThreads.size(); }
|
||||
|
||||
/** Thread id of active thread
|
||||
* Only used for SwitchOnCacheMiss model.
|
||||
* Assumes only 1 thread active
|
||||
*/
|
||||
ThreadID activeThreadId()
|
||||
{
|
||||
if (numActiveThreads() > 0)
|
||||
return activeThreads.front();
|
||||
else
|
||||
return InvalidThreadID;
|
||||
}
|
||||
|
||||
|
||||
/** 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();
|
||||
|
||||
virtual void wakeup();
|
||||
|
||||
/* 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(ThreadID tid = 0)
|
||||
{
|
||||
return thread[tid]->getTC();
|
||||
}
|
||||
|
||||
/** Count the Total Instructions Committed in the CPU. */
|
||||
virtual Counter totalInsts() const
|
||||
{
|
||||
Counter total(0);
|
||||
|
||||
for (ThreadID tid = 0; tid < (ThreadID)thread.size(); tid++)
|
||||
total += thread[tid]->numInst;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Count the Total Ops Committed in the CPU. */
|
||||
virtual Counter totalOps() const
|
||||
{
|
||||
Counter total(0);
|
||||
|
||||
for (ThreadID tid = 0; tid < (ThreadID)thread.size(); tid++)
|
||||
total += thread[tid]->numOp;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Pointer to the system. */
|
||||
System *system;
|
||||
|
||||
/** The global sequence number counter. */
|
||||
InstSeqNum globalSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
#ifdef DEBUG
|
||||
/** The global event number counter. */
|
||||
InstSeqNum cpuEventNum;
|
||||
|
||||
/** Number of resource requests active in CPU **/
|
||||
unsigned resReqCount;
|
||||
#endif
|
||||
|
||||
Addr lockAddr;
|
||||
|
||||
/** Temporary fix for the lock flag, works in the UP case. */
|
||||
bool lockFlag;
|
||||
|
||||
/** Counter of how many stages have completed draining */
|
||||
int drainCount;
|
||||
|
||||
/** Pointers to all of the threads in the CPU. */
|
||||
std::vector<Thread *> thread;
|
||||
|
||||
/** Whether or not the CPU should defer its registration. */
|
||||
bool deferRegistration;
|
||||
|
||||
/** Per-Stage Instruction Tracing */
|
||||
bool stageTracing;
|
||||
|
||||
/** The cycle that the CPU was last running, used for statistics. */
|
||||
Tick lastRunningCycle;
|
||||
|
||||
void updateContextSwitchStats();
|
||||
unsigned instsPerSwitch;
|
||||
Stats::Average instsPerCtxtSwitch;
|
||||
Stats::Scalar numCtxtSwitches;
|
||||
|
||||
/** 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 or no
|
||||
* stages active.
|
||||
*/
|
||||
Stats::Scalar idleCycles;
|
||||
|
||||
/** Stat for total number of cycles the CPU is active. */
|
||||
Stats::Scalar runCycles;
|
||||
|
||||
/** Percentage of cycles a stage was active */
|
||||
Stats::Formula activity;
|
||||
|
||||
/** Instruction Mix Stats */
|
||||
Stats::Scalar comLoads;
|
||||
Stats::Scalar comStores;
|
||||
Stats::Scalar comBranches;
|
||||
Stats::Scalar comNops;
|
||||
Stats::Scalar comNonSpec;
|
||||
Stats::Scalar comInts;
|
||||
Stats::Scalar comFloats;
|
||||
|
||||
/** Stat for the number of committed instructions per thread. */
|
||||
Stats::Vector committedInsts;
|
||||
|
||||
/** Stat for the number of committed ops per thread. */
|
||||
Stats::Vector committedOps;
|
||||
|
||||
/** 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__
|
||||
279
simulators/gem5/src/cpu/inorder/first_stage.cc
Normal file
279
simulators/gem5/src/cpu/inorder/first_stage.cc
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/InOrderStage.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(ThreadID 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, ThreadID 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 (!skidBuffer[tid].empty()) {
|
||||
if (skidBuffer[tid].front()->seqNum <= squash_seq_num) {
|
||||
DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because "
|
||||
"it's <= squashing seqNum %i.\n",
|
||||
tid,
|
||||
skidBuffer[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,
|
||||
skidBuffer[tid].size());
|
||||
break;
|
||||
}
|
||||
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] "
|
||||
"PC %s.\n", tid, skidBuffer[tid].front()->seqNum,
|
||||
skidBuffer[tid].front()->pc);
|
||||
skidBuffer[tid].pop_front();
|
||||
}
|
||||
|
||||
// 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::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
// Need to preserve the stalling instruction in first-stage
|
||||
// since the squash() from first stage also removes
|
||||
// the instruction from the CPU (removeInstsUntil). If that
|
||||
// functionality gets changed then you can move this offset.
|
||||
// (stalling instruction = seq_num + 1)
|
||||
squash(seq_num+1, tid);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FirstStage::processStage(bool &status_change)
|
||||
{
|
||||
list<ThreadID>::iterator threads = activeThreads->begin();
|
||||
|
||||
//Check stall and squash signals.
|
||||
while (threads != activeThreads->end()) {
|
||||
ThreadID tid = *threads++;
|
||||
status_change = checkSignalsAndUpdate(tid) || status_change;
|
||||
}
|
||||
|
||||
while (instsProcessed < stageWidth) {
|
||||
ThreadID tid = getFetchingThread(fetchPolicy);
|
||||
|
||||
if (tid >= 0) {
|
||||
DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
|
||||
processThread(status_change, tid);
|
||||
DPRINTF(InOrderStage, "Done Processing [tid:%i]\n",tid);
|
||||
} else {
|
||||
DPRINTF(InOrderStage, "No more threads to fetch from.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (instsProcessed > 0) {
|
||||
++runCycles;
|
||||
idle = false;
|
||||
} else {
|
||||
++idleCycles;
|
||||
idle = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@TODO: Note in documentation, that when you make a pipeline stage change,
|
||||
//then make sure you change the first stage too
|
||||
void
|
||||
FirstStage::processInsts(ThreadID tid)
|
||||
{
|
||||
bool all_reqs_completed = true;
|
||||
|
||||
for (int insts_fetched = instsProcessed;
|
||||
insts_fetched < stageWidth;
|
||||
insts_fetched++) {
|
||||
|
||||
DynInstPtr inst;
|
||||
bool new_inst = false;
|
||||
|
||||
if (!skidBuffer[tid].empty()) {
|
||||
inst = skidBuffer[tid].front();
|
||||
} else {
|
||||
// Get new instruction.
|
||||
new_inst = true;
|
||||
|
||||
inst = new InOrderDynInst(cpu,
|
||||
cpu->thread[tid],
|
||||
cpu->nextInstSeqNum(tid),
|
||||
tid,
|
||||
tid);
|
||||
|
||||
#if TRACING_ON
|
||||
inst->traceData =
|
||||
tracer->getInstRecord(ThePipeline::NumStages,
|
||||
cpu->stageTracing,
|
||||
cpu->thread[tid]->getTC());
|
||||
|
||||
#else
|
||||
inst->traceData = NULL;
|
||||
#endif // TRACING_ON
|
||||
|
||||
// Add instruction to the CPU's list of instructions.
|
||||
inst->setInstListIt(cpu->addInst(inst));
|
||||
|
||||
// Create Front-End Resource Schedule For Instruction
|
||||
inst->setFrontSked(cpu->frontEndSked);
|
||||
}
|
||||
|
||||
int reqs_processed = 0;
|
||||
all_reqs_completed = processInstSchedule(inst, reqs_processed);
|
||||
|
||||
// If the instruction isnt squashed & we've completed one request
|
||||
// Then we can officially count this instruction toward the stage's
|
||||
// bandwidth count
|
||||
if (reqs_processed > 0)
|
||||
instsProcessed++;
|
||||
|
||||
if (!all_reqs_completed || !sendInstToNextStage(inst)) {
|
||||
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);
|
||||
skidBuffer[tid].push_back(inst);
|
||||
}
|
||||
block(tid);
|
||||
break;
|
||||
} else if (!skidBuffer[tid].empty()){
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Finished all "
|
||||
"requests for this stage.\n", tid, inst->seqNum);
|
||||
skidBuffer[tid].pop_front();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Record that stage has written to the time buffer for activity
|
||||
// tracking.
|
||||
if (instsProcessed) {
|
||||
wroteToTimeBuffer = true;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadID
|
||||
FirstStage::getFetchingThread(FetchPriority &fetch_priority)
|
||||
{
|
||||
ThreadID num_active_threads = cpu->numActiveThreads();
|
||||
|
||||
if (num_active_threads > 1) {
|
||||
switch (fetch_priority) {
|
||||
case SingleThread:
|
||||
return cpu->activeThreadId();
|
||||
|
||||
case RoundRobin:
|
||||
return roundRobin();
|
||||
|
||||
default:
|
||||
return InvalidThreadID;
|
||||
}
|
||||
} else if (num_active_threads == 1) {
|
||||
ThreadID tid = *activeThreads->begin();
|
||||
|
||||
if (stageStatus[tid] == Running ||
|
||||
stageStatus[tid] == Idle ||
|
||||
stageStatus[tid] == Unblocking) {
|
||||
return tid;
|
||||
} else {
|
||||
return InvalidThreadID;
|
||||
}
|
||||
} else {
|
||||
return InvalidThreadID;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadID
|
||||
FirstStage::roundRobin()
|
||||
{
|
||||
list<ThreadID>::iterator pri_iter = fetchPriorityList->begin();
|
||||
list<ThreadID>::iterator end = fetchPriorityList->end();
|
||||
|
||||
ThreadID high_pri;
|
||||
|
||||
while (pri_iter != end) {
|
||||
high_pri = *pri_iter;
|
||||
|
||||
assert(high_pri <= numThreads);
|
||||
|
||||
if (stageStatus[high_pri] == Running ||
|
||||
stageStatus[high_pri] == Idle ||
|
||||
stageStatus[high_pri] == Unblocking){
|
||||
|
||||
fetchPriorityList->erase(pri_iter);
|
||||
fetchPriorityList->push_back(high_pri);
|
||||
|
||||
return high_pri;
|
||||
}
|
||||
|
||||
pri_iter++;
|
||||
}
|
||||
|
||||
return InvalidThreadID;
|
||||
}
|
||||
94
simulators/gem5/src/cpu/inorder/first_stage.hh
Normal file
94
simulators/gem5/src/cpu/inorder/first_stage.hh
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 "cpu/inorder/comm.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/params.hh"
|
||||
#include "cpu/inorder/pipeline_stage.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/timebuf.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(ThreadID tid);
|
||||
|
||||
/** Squash Instructions Above a Seq. Num */
|
||||
void squash(InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** There are no insts. coming from previous stages, so there is
|
||||
* no need to sort insts here
|
||||
*/
|
||||
void sortInsts() {}
|
||||
|
||||
/** 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<ThreadID> *fetchPriorityList;
|
||||
|
||||
/** Return the next fetching thread */
|
||||
ThreadID getFetchingThread(FetchPriority &fetch_priority);
|
||||
|
||||
/** Return next thread given Round Robin Policy for Thread Fetching */
|
||||
ThreadID roundRobin();
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_FIRST_STAGE_HH__
|
||||
67
simulators/gem5/src/cpu/inorder/inorder_cpu_builder.cc
Normal file
67
simulators/gem5/src/cpu/inorder/inorder_cpu_builder.cc
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 <string>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
InOrderCPU *
|
||||
InOrderCPUParams::create()
|
||||
{
|
||||
ThreadID actual_num_threads;
|
||||
if (FullSystem) {
|
||||
// Full-system only supports a single thread for the moment.
|
||||
actual_num_threads = 1;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
593
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.cc
Normal file
593
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.cc
Normal file
@ -0,0 +1,593 @@
|
||||
/*
|
||||
* 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 <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "base/bigint.hh"
|
||||
#include "base/cp_annotate.hh"
|
||||
#include "base/cprintf.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/InOrderDynInst.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/fault_fwd.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
using namespace ThePipeline;
|
||||
|
||||
InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
|
||||
InOrderThreadState *state,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID tid,
|
||||
unsigned _asid)
|
||||
: seqNum(seq_num), squashSeqNum(0), threadNumber(tid), asid(_asid),
|
||||
virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu),
|
||||
thread(state), fault(NoFault), memData(NULL), loadData(0),
|
||||
storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
|
||||
readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
|
||||
memTime(0), splitMemData(NULL), splitMemReq(NULL), totalSize(0),
|
||||
split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
|
||||
split2ndDataPtr(NULL), split2ndFlags(0), splitInst(false),
|
||||
splitFinishCnt(0), split2ndStoreDataPtr(NULL), splitInstSked(false),
|
||||
inFrontEnd(true), frontSked(NULL), backSked(NULL),
|
||||
squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
|
||||
fetchMemReq(NULL), dataMemReq(NULL), instEffAddr(0), eaCalcDone(false),
|
||||
lqIdx(0), sqIdx(0), onInstList(false)
|
||||
{
|
||||
for(int i = 0; i < MaxInstSrcRegs; i++) {
|
||||
_readySrcRegIdx[i] = false;
|
||||
_srcRegIdx[i] = 0;
|
||||
}
|
||||
|
||||
for(int j = 0; j < MaxInstDestRegs; j++) {
|
||||
_destRegIdx[j] = 0;
|
||||
_prevDestRegIdx[j] = 0;
|
||||
}
|
||||
|
||||
++instcount;
|
||||
DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created."
|
||||
" (active insts: %i)\n", threadNumber, seqNum, instcount);
|
||||
|
||||
}
|
||||
|
||||
int InOrderDynInst::instcount = 0;
|
||||
|
||||
int
|
||||
InOrderDynInst::cpuId()
|
||||
{
|
||||
return cpu->cpuId();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::setStaticInst(StaticInstPtr si)
|
||||
{
|
||||
staticInst = si;
|
||||
|
||||
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()
|
||||
{
|
||||
inFrontEnd = true;
|
||||
|
||||
fetchMemReq = NULL;
|
||||
dataMemReq = NULL;
|
||||
splitMemData = NULL;
|
||||
split2ndAddr = 0;
|
||||
split2ndAccess = false;
|
||||
splitInst = false;
|
||||
splitInstSked = false;
|
||||
splitFinishCnt = 0;
|
||||
|
||||
effAddr = 0;
|
||||
physEffAddr = 0;
|
||||
|
||||
readyRegs = 0;
|
||||
|
||||
nextStage = 0;
|
||||
|
||||
status.reset();
|
||||
|
||||
memAddrReady = false;
|
||||
eaCalcDone = 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
|
||||
if (instcount > 100) {
|
||||
fatal("Number of Active Instructions in CPU is too high. "
|
||||
"(Not Dereferencing Ptrs. Correctly?)\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::resetInstCount()
|
||||
{
|
||||
instcount = 0;
|
||||
}
|
||||
|
||||
|
||||
InOrderDynInst::~InOrderDynInst()
|
||||
{
|
||||
if (traceData)
|
||||
delete traceData;
|
||||
|
||||
if (splitMemData)
|
||||
delete [] splitMemData;
|
||||
|
||||
fault = NoFault;
|
||||
|
||||
--instcount;
|
||||
|
||||
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::calcEA()
|
||||
{
|
||||
this->fault = this->staticInst->eaComp(this, this->traceData);
|
||||
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;
|
||||
}
|
||||
|
||||
Fault
|
||||
InOrderDynInst::memAccess()
|
||||
{
|
||||
return initiateAcc();
|
||||
}
|
||||
|
||||
|
||||
Fault
|
||||
InOrderDynInst::hwrei()
|
||||
{
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
// Can only do a hwrei when in pal mode.
|
||||
if (!(this->instAddr() & 0x3))
|
||||
return new AlphaISA::UnimplementedOpcodeFault;
|
||||
|
||||
// Set the next PC based on the value of the EXC_ADDR IPR.
|
||||
AlphaISA::PCState pc = this->pcState();
|
||||
pc.npc(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
|
||||
this->threadNumber));
|
||||
this->pcState(pc);
|
||||
if (CPA::available()) {
|
||||
ThreadContext *tc = this->cpu->tcBase(this->threadNumber);
|
||||
CPA::cpa()->swAutoBegin(tc, this->nextInstAddr());
|
||||
}
|
||||
|
||||
// Tell CPU to clear any state it needs to if a hwrei is taken.
|
||||
this->cpu->hwrei(this->threadNumber);
|
||||
#endif
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderDynInst::trap(Fault fault)
|
||||
{
|
||||
this->cpu->trap(fault, this->threadNumber, this);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InOrderDynInst::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);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::syscall(int64_t callnum)
|
||||
{
|
||||
if (FullSystem)
|
||||
panic("Syscall emulation isn't available in FS mode.\n");
|
||||
|
||||
syscallNum = callnum;
|
||||
cpu->syscallContext(NoFault, this->threadNumber, this);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::setSquashInfo(unsigned stage_num)
|
||||
{
|
||||
squashingStage = stage_num;
|
||||
|
||||
// If it's a fault, then we need to squash
|
||||
// the faulting instruction too. Squash
|
||||
// functions squash above a seqNum, so we
|
||||
// decrement here for that case
|
||||
if (fault != NoFault) {
|
||||
squashSeqNum = seqNum - 1;
|
||||
return;
|
||||
} else
|
||||
squashSeqNum = seqNum;
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (staticInst && isControl()) {
|
||||
TheISA::PCState nextPC = pc;
|
||||
TheISA::advancePC(nextPC, staticInst);
|
||||
|
||||
// Check to see if we should squash after the
|
||||
// branch or after a branch delay slot.
|
||||
if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
|
||||
squashSeqNum = seqNum + 1;
|
||||
else
|
||||
squashSeqNum = seqNum;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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] [src:%i] Int being set "
|
||||
"to %#x.\n", threadNumber, seqNum, idx, val);
|
||||
instSrc[idx].intVal = val;
|
||||
}
|
||||
|
||||
/** Records an fp register being set to a value. */
|
||||
void
|
||||
InOrderDynInst::setFloatSrc(int idx, FloatReg val)
|
||||
{
|
||||
instSrc[idx].fpVal.f = val;
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FP being set "
|
||||
"to %x, %08f...%08f\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
|
||||
}
|
||||
|
||||
/** Records an fp register being set to an integer value. */
|
||||
void
|
||||
InOrderDynInst::setFloatRegBitsSrc(int idx, FloatRegBits val)
|
||||
{
|
||||
instSrc[idx].fpVal.i = val;
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
|
||||
"to %x, %08f...%x\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
|
||||
}
|
||||
|
||||
/** Reads a integer register. */
|
||||
IntReg
|
||||
InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
|
||||
threadNumber, seqNum, idx, instSrc[idx].intVal);
|
||||
return instSrc[idx].intVal;
|
||||
}
|
||||
|
||||
/** Reads a FP register. */
|
||||
FloatReg
|
||||
InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
|
||||
"as %x, %08f.\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
|
||||
return instSrc[idx].fpVal.f;
|
||||
}
|
||||
|
||||
|
||||
/** Reads a FP register as a integer. */
|
||||
FloatRegBits
|
||||
InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
|
||||
"as %x, %08f.\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
|
||||
return instSrc[idx].fpVal.i;
|
||||
}
|
||||
|
||||
/** 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::readMiscRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
|
||||
" read as %#x.\n", threadNumber, seqNum, idx,
|
||||
instSrc[idx].intVal);
|
||||
return instSrc[idx].intVal;
|
||||
}
|
||||
|
||||
|
||||
/** 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[idx].type = Integer;
|
||||
instResult[idx].res.intVal = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
|
||||
"being set to %#x.\n", threadNumber, seqNum, idx, val);
|
||||
}
|
||||
|
||||
MiscReg
|
||||
InOrderDynInst::readRegOtherThread(unsigned reg_idx, ThreadID 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].type = Integer;
|
||||
instResult[idx].res.intVal = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
|
||||
"being set to %#x (result-tick:%i).\n",
|
||||
threadNumber, seqNum, idx, val, instResult[idx].tick);
|
||||
}
|
||||
|
||||
/** Sets a FP register. */
|
||||
void
|
||||
InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
instResult[idx].type = Float;
|
||||
instResult[idx].res.fpVal.f = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. %i "
|
||||
"being set to %#x, %08f (result-tick:%i).\n",
|
||||
threadNumber, seqNum, idx, val, val, instResult[idx].tick);
|
||||
}
|
||||
|
||||
/** Sets a FP register as a integer. */
|
||||
void
|
||||
InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val)
|
||||
{
|
||||
instResult[idx].type = FloatBits;
|
||||
instResult[idx].res.fpVal.i = val;
|
||||
instResult[idx].tick = curTick();
|
||||
|
||||
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
|
||||
"being set to %#x (result-tick:%i).\n",
|
||||
threadNumber, seqNum, idx, val, instResult[idx].tick);
|
||||
}
|
||||
|
||||
/** 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,
|
||||
ThreadID tid)
|
||||
{
|
||||
if (tid == InvalidThreadID) {
|
||||
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);
|
||||
}
|
||||
|
||||
Fault
|
||||
InOrderDynInst::readMem(Addr addr, uint8_t *data,
|
||||
unsigned size, unsigned flags)
|
||||
{
|
||||
return cpu->read(this, addr, data, size, flags);
|
||||
}
|
||||
|
||||
Fault
|
||||
InOrderDynInst::writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
return cpu->write(this, data, size, addr, flags, res);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderDynInst::dump()
|
||||
{
|
||||
cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
|
||||
cout << staticInst->disassemble(pc.instAddr());
|
||||
cprintf("'\n");
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::dump(std::string &outstring)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "T" << threadNumber << " : " << pc << " "
|
||||
<< staticInst->disassemble(pc.instAddr());
|
||||
|
||||
outstring = s.str();
|
||||
}
|
||||
1060
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.hh
Normal file
1060
simulators/gem5/src/cpu/inorder/inorder_dyn_inst.hh
Normal file
File diff suppressed because it is too large
Load Diff
96
simulators/gem5/src/cpu/inorder/inorder_trace.cc
Normal file
96
simulators/gem5/src/cpu/inorder/inorder_trace.cc
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/inorder_trace.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/ExecEnable.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 (!Debug::ExecEnable)
|
||||
return NULL;
|
||||
|
||||
if (!Trace::enabled)
|
||||
return NULL;
|
||||
|
||||
return new InOrderTraceRecord(num_stages, stage_tracing, tc, 0);
|
||||
}
|
||||
|
||||
InOrderTraceRecord *
|
||||
InOrderTrace::getInstRecord(Tick when, ThreadContext *tc,
|
||||
const StaticInstPtr staticInst, TheISA::PCState _pc,
|
||||
const StaticInstPtr macroStaticInst)
|
||||
{
|
||||
return new InOrderTraceRecord(ThePipeline::NumStages, true, tc, _pc);
|
||||
}
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ExeTracer Simulation Object
|
||||
//
|
||||
Trace::InOrderTrace *
|
||||
InOrderTraceParams::create()
|
||||
{
|
||||
return new Trace::InOrderTrace(this);
|
||||
};
|
||||
|
||||
98
simulators/gem5/src/cpu/inorder/inorder_trace.hh
Normal file
98
simulators/gem5/src/cpu/inorder/inorder_trace.hh
Normal file
@ -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 __CPU_INORDER_INORDER_TRACE_HH__
|
||||
#define __CPU_INORDER_INORDER_TRACE_HH__
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "base/types.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "params/InOrderTrace.hh"
|
||||
#include "sim/insttracer.hh"
|
||||
|
||||
class ThreadContext;
|
||||
|
||||
namespace Trace {
|
||||
|
||||
class InOrderTraceRecord : public ExeTracerRecord
|
||||
{
|
||||
public:
|
||||
InOrderTraceRecord(unsigned num_stages, bool _stage_tracing,
|
||||
ThreadContext *_thread, TheISA::PCState _pc, bool spec = false)
|
||||
: ExeTracerRecord(0, _thread, NULL, _pc, 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(TheISA::PCState _pc) { pc = _pc; }
|
||||
};
|
||||
|
||||
class InOrderTrace : public InstTracer
|
||||
{
|
||||
public:
|
||||
InOrderTrace(const InOrderTraceParams *p) : InstTracer(p)
|
||||
{}
|
||||
|
||||
InOrderTraceRecord *
|
||||
getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc);
|
||||
|
||||
InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
|
||||
const StaticInstPtr staticInst, TheISA::PCState pc,
|
||||
const StaticInstPtr macroStaticInst = NULL);
|
||||
};
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#endif // __CPU_INORDER_INORDER_TRACE_HH__
|
||||
122
simulators/gem5/src/cpu/inorder/params.hh
Normal file
122
simulators/gem5/src/cpu/inorder/params.hh
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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: Korey Sewell
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_PARAMS_HH__
|
||||
#define __CPU_INORDER_PARAMS_HH__
|
||||
|
||||
#include "cpu/base.hh"
|
||||
|
||||
//Forward declarations
|
||||
class FunctionalMemory;
|
||||
class Process;
|
||||
class MemObject;
|
||||
class MemInterface;
|
||||
|
||||
/**
|
||||
* 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 InOrderParams : public BaseCPU::Params
|
||||
{
|
||||
public:
|
||||
|
||||
// Workloads
|
||||
std::vector<Process *> workload;
|
||||
Process *process;
|
||||
|
||||
//
|
||||
// Memory System/Caches
|
||||
//
|
||||
unsigned cachePorts;
|
||||
std::string fetchMemPort;
|
||||
std::string dataMemPort;
|
||||
|
||||
//
|
||||
// Branch predictor (BP & BTB)
|
||||
//
|
||||
std::string predType;
|
||||
unsigned localPredictorSize;
|
||||
unsigned localCtrBits;
|
||||
unsigned localHistoryTableSize;
|
||||
unsigned localHistoryBits;
|
||||
unsigned globalPredictorSize;
|
||||
unsigned globalCtrBits;
|
||||
unsigned globalHistoryBits;
|
||||
unsigned choicePredictorSize;
|
||||
unsigned choiceCtrBits;
|
||||
unsigned BTBEntries;
|
||||
unsigned BTBTagSize;
|
||||
unsigned RASSize;
|
||||
|
||||
// Pipeline Parameters
|
||||
unsigned stageWidth;
|
||||
|
||||
// InOrderCPU Simulation Parameters
|
||||
unsigned instShiftAmt;
|
||||
unsigned activity;
|
||||
unsigned deferRegistration;
|
||||
|
||||
//
|
||||
// Memory Parameters
|
||||
//
|
||||
unsigned memBlockSize;
|
||||
|
||||
//
|
||||
// Multiply Divide Unit
|
||||
//
|
||||
// @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;
|
||||
|
||||
/** Latency & Repeat Rate for 8-bit Divide Insts */
|
||||
unsigned div8Latency;
|
||||
unsigned div8RepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 16-bit Divide Insts */
|
||||
unsigned div16Latency;
|
||||
unsigned div16RepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 24-bit Divide Insts */
|
||||
unsigned div24Latency;
|
||||
unsigned div24RepeatRate;
|
||||
|
||||
/** Latency & Repeat Rate for 32-bit Divide Insts */
|
||||
unsigned div32Latency;
|
||||
unsigned div32RepeatRate;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // _CPU_INORDER_PARAMS_HH__
|
||||
1125
simulators/gem5/src/cpu/inorder/pipeline_stage.cc
Normal file
1125
simulators/gem5/src/cpu/inorder/pipeline_stage.cc
Normal file
File diff suppressed because it is too large
Load Diff
349
simulators/gem5/src/cpu/inorder/pipeline_stage.hh
Normal file
349
simulators/gem5/src/cpu/inorder/pipeline_stage.hh
Normal file
@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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 "cpu/inorder/comm.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "params/InOrderCPU.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*/
|
||||
ThreadID numThreads;
|
||||
|
||||
/** Stage status. */
|
||||
StageStatus _status;
|
||||
|
||||
/** Per-thread status. */
|
||||
ThreadStatus stageStatus[ThePipeline::MaxThreads];
|
||||
|
||||
public:
|
||||
PipelineStage(Params *params, unsigned stage_num);
|
||||
|
||||
virtual ~PipelineStage();
|
||||
|
||||
/** PipelineStage initialization. */
|
||||
void init(Params *params);
|
||||
|
||||
/** Returns the name of stage. */
|
||||
std::string name() const;
|
||||
|
||||
/** Registers statistics. */
|
||||
void regStats();
|
||||
|
||||
/** Sets CPU pointer. */
|
||||
void setCPU(InOrderCPU *cpu_ptr);
|
||||
|
||||
/** 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<ThreadID> *at_ptr);
|
||||
|
||||
bool nextStageQueueValid(int stage_num);
|
||||
|
||||
bool isBlocked(ThreadID 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.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
/** Set a resource stall in the pipeline-stage */
|
||||
void setResStall(ResReqPtr res_req, ThreadID tid);
|
||||
|
||||
/** Unset a resource stall in the pipeline-stage */
|
||||
void unsetResStall(ResReqPtr res_req, ThreadID tid);
|
||||
|
||||
/** Remove all stall signals for a particular thread; */
|
||||
void removeStalls(ThreadID 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.
|
||||
*/
|
||||
void processThread(bool &status_change, ThreadID 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(ThreadID tid);
|
||||
|
||||
/** Process all resources on an instruction's resource schedule */
|
||||
bool processInstSchedule(DynInstPtr inst, int &reqs_processed);
|
||||
|
||||
/** Is there room in the next stage buffer for this instruction? */
|
||||
bool canSendInstToStage(unsigned stage_num);
|
||||
|
||||
/** Send an instruction to the next stage buffer */
|
||||
bool sendInstToNextStage(DynInstPtr inst);
|
||||
|
||||
/** 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. */
|
||||
void updateStatus();
|
||||
|
||||
/** Separates instructions from fetch into individual lists of instructions
|
||||
* sorted by thread.
|
||||
*/
|
||||
void sortInsts();
|
||||
|
||||
/** Reads all stall signals from the backwards communication timebuffer. */
|
||||
void readStallSignals(ThreadID tid);
|
||||
|
||||
/** Checks all input signals and updates stage's status appropriately. */
|
||||
bool checkSignalsAndUpdate(ThreadID tid);
|
||||
|
||||
/** Checks all stall signals, and returns if any are true. */
|
||||
bool checkStall(ThreadID 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.
|
||||
*/
|
||||
bool block(ThreadID tid);
|
||||
|
||||
void blockDueToBuffer(ThreadID 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.
|
||||
*/
|
||||
bool unblock(ThreadID tid);
|
||||
|
||||
|
||||
public:
|
||||
void activateThread(ThreadID tid);
|
||||
|
||||
/** Setup Squashing Information to be passed back thru the pipeline */
|
||||
void setupSquash(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
virtual void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Perform squash of instructions above seq_num */
|
||||
virtual void squash(InstSeqNum squash_num, ThreadID tid);
|
||||
|
||||
/** Squash instructions from stage buffer */
|
||||
void squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void dumpInsts();
|
||||
|
||||
protected:
|
||||
/** CPU interface. */
|
||||
InOrderCPU *cpu;
|
||||
|
||||
Trace::InOrderTrace *tracer;
|
||||
|
||||
/** List of active thread ids */
|
||||
std::list<ThreadID> *activeThreads;
|
||||
|
||||
/** Buffer of instructions switched out to mem-stall.
|
||||
* Only used when using SwitchOnCacheMiss threading model
|
||||
* Used as 1-to-1 mapping between ThreadID and Entry.
|
||||
*/
|
||||
std::vector<DynInstPtr> switchedOutBuffer;
|
||||
std::vector<bool> switchedOutValid;
|
||||
|
||||
/** Instructions that we've processed this tick
|
||||
* NOTE: "Processed" means completed at least 1 instruction request
|
||||
*/
|
||||
unsigned instsProcessed;
|
||||
|
||||
/** Skid buffer between previous stage and this one. */
|
||||
std::list<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];
|
||||
|
||||
/** 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];
|
||||
|
||||
/** Instruction used for squashing branch (used for MIPS) */
|
||||
DynInstPtr squashInst[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;
|
||||
|
||||
bool idle;
|
||||
|
||||
/** Source of possible stalls. */
|
||||
struct Stalls {
|
||||
bool stage[ThePipeline::NumStages];
|
||||
std::vector<ResReqPtr> resources;
|
||||
};
|
||||
|
||||
/** Tracks stage/resource stalls */
|
||||
Stalls stalls[ThePipeline::MaxThreads];
|
||||
|
||||
/** Number of cycles 0 instruction(s) are processed. */
|
||||
Stats::Scalar idleCycles;
|
||||
|
||||
/** Number of cycles 1+ instructions are processed. */
|
||||
Stats::Scalar runCycles;
|
||||
|
||||
/** Percentage of cycles 1+ instructions are processed. */
|
||||
Stats::Formula utilization;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
166
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.cc
Normal file
166
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.cc
Normal file
@ -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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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;
|
||||
}
|
||||
|
||||
};
|
||||
146
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.hh
Normal file
146
simulators/gem5/src/cpu/inorder/pipeline_traits.5stage.hh
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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
|
||||
242
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.cc
Normal file
242
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.cc
Normal file
@ -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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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;
|
||||
}
|
||||
|
||||
};
|
||||
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.hh
Normal file
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.hh
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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 <map>
|
||||
#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 = 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
|
||||
240
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
Normal file
240
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
Normal file
@ -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/resources/resource_list.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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;
|
||||
}
|
||||
|
||||
};
|
||||
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
Normal file
154
simulators/gem5/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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 <map>
|
||||
#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 = 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
|
||||
85
simulators/gem5/src/cpu/inorder/pipeline_traits.hh
Normal file
85
simulators/gem5/src/cpu/inorder/pipeline_traits.hh
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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;
|
||||
class ScheduleEntry;
|
||||
class ResourceSked;
|
||||
|
||||
/* This Namespace contains constants, typedefs, functions and
|
||||
* objects specific to the Pipeline Implementation.
|
||||
*/
|
||||
namespace ThePipeline {
|
||||
// Pipeline Constants
|
||||
const unsigned NumStages = 5;
|
||||
const ThreadID MaxThreads = 1;
|
||||
const unsigned BackEndStartStage = 2;
|
||||
|
||||
// List of Resources The Pipeline Uses
|
||||
enum ResourceId {
|
||||
FetchSeq = 0,
|
||||
ICache,
|
||||
Decode,
|
||||
BPred,
|
||||
FetchBuff,
|
||||
RegManager,
|
||||
AGEN,
|
||||
ExecUnit,
|
||||
MDU,
|
||||
DCache,
|
||||
Grad,
|
||||
FetchBuff2
|
||||
};
|
||||
|
||||
typedef InOrderCPUParams Params;
|
||||
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
|
||||
|
||||
//////////////////////////
|
||||
// RESOURCE SCHEDULING
|
||||
//////////////////////////
|
||||
typedef ResourceSked ResSchedule;
|
||||
typedef ResourceSked* RSkedPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
306
simulators/gem5/src/cpu/inorder/reg_dep_map.cc
Normal file
306
simulators/gem5/src/cpu/inorder/reg_dep_map.cc
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "debug/RegDepMap.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
using namespace ThePipeline;
|
||||
|
||||
RegDepMap::RegDepMap(int size)
|
||||
{
|
||||
regMap.resize(InOrderCPU::NumRegTypes);
|
||||
regMap[InOrderCPU::IntType].resize(NumIntRegs);
|
||||
regMap[InOrderCPU::FloatType].resize(NumFloatRegs);
|
||||
regMap[InOrderCPU::MiscType].resize(NumMiscRegs);
|
||||
}
|
||||
|
||||
RegDepMap::~RegDepMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
string
|
||||
RegDepMap::name()
|
||||
{
|
||||
return cpu->name() + ".RegDepMap";
|
||||
}
|
||||
|
||||
std::string RegDepMap::mapNames[InOrderCPU::NumRegTypes] =
|
||||
{"IntReg", "FloatReg", "MiscReg"};
|
||||
|
||||
void
|
||||
RegDepMap::setCPU(InOrderCPU *_cpu)
|
||||
{
|
||||
cpu = _cpu;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::clear()
|
||||
{
|
||||
for (int i = 0; i < regMap.size(); i++) {
|
||||
for (int j = 0; j < regMap[j].size(); j++)
|
||||
regMap[i][j].clear();
|
||||
regMap[i].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->instName(),
|
||||
dest_regs);
|
||||
|
||||
for (int i = 0; i < dest_regs; i++) {
|
||||
InOrderCPU::RegType reg_type;
|
||||
TheISA::RegIndex raw_idx = inst->destRegIdx(i);
|
||||
TheISA::RegIndex flat_idx = cpu->flattenRegIdx(raw_idx,
|
||||
reg_type,
|
||||
inst->threadNumber);
|
||||
|
||||
DPRINTF(RegDepMap, "[sn:%i] #%i flattened %i to %i.\n",
|
||||
inst->seqNum, i, raw_idx, flat_idx);
|
||||
|
||||
inst->flattenDestReg(i, flat_idx);
|
||||
|
||||
if (flat_idx == TheISA::ZeroReg && reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(RegDepMap, "[sn:%i]: Ignoring Insert-Dependency tracking for "
|
||||
"ISA-ZeroReg (Int. Reg %i).\n", inst->seqNum,
|
||||
flat_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
insert(reg_type, flat_idx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RegDepMap::insert(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
DPRINTF(RegDepMap, "Inserting [sn:%i] onto %s dep. list for "
|
||||
"reg. idx %i.\n", inst->seqNum, mapNames[reg_type],
|
||||
idx);
|
||||
|
||||
regMap[reg_type][idx].push_back(inst);
|
||||
|
||||
inst->setRegDepEntry();
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::remove(DynInstPtr inst)
|
||||
{
|
||||
if (inst->isRegDepEntry()) {
|
||||
int dest_regs = inst->numDestRegs();
|
||||
|
||||
DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map. for "
|
||||
", %s (dest. regs = %i).\n",
|
||||
inst->seqNum,
|
||||
inst->instName(),
|
||||
dest_regs);
|
||||
|
||||
|
||||
for (int i = 0; i < dest_regs; i++) {
|
||||
RegIndex flat_idx = inst->flattenedDestRegIdx(i);
|
||||
InOrderCPU::RegType reg_type = cpu->getRegType(inst->destRegIdx(i));
|
||||
|
||||
// Merge Dyn Inst & CPU Result Types
|
||||
if (flat_idx == TheISA::ZeroReg &&
|
||||
reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(RegDepMap, "[sn:%i]: Ignoring Remove-Dependency tracking for "
|
||||
"ISA-ZeroReg (Int. Reg %i).\n", inst->seqNum,
|
||||
flat_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
remove(reg_type, flat_idx, inst);
|
||||
}
|
||||
|
||||
inst->clearRegDepEntry();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::remove(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][idx].begin();
|
||||
std::list<DynInstPtr>::iterator list_end = regMap[reg_type][idx].end();
|
||||
|
||||
|
||||
while (list_it != list_end) {
|
||||
if((*list_it) == inst) {
|
||||
DPRINTF(RegDepMap, "Removing [sn:%i] from %s dep. list for "
|
||||
"reg. idx %i.\n", inst->seqNum, mapNames[reg_type],
|
||||
idx);
|
||||
regMap[reg_type][idx].erase(list_it);
|
||||
return;
|
||||
}
|
||||
list_it++;
|
||||
}
|
||||
panic("[sn:%i] Did not find entry for %i, type:%i\n", inst->seqNum, idx, reg_type);
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::removeFront(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][idx].begin();
|
||||
|
||||
DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on reg. idx "
|
||||
"%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum);
|
||||
|
||||
assert(list_it != regMap[reg_type][idx].end());
|
||||
|
||||
assert(inst == (*list_it));
|
||||
|
||||
regMap[reg_type][idx].erase(list_it);
|
||||
}
|
||||
|
||||
bool
|
||||
RegDepMap::canRead(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
if (regMap[reg_type][idx].size() == 0)
|
||||
return true;
|
||||
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][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(uint8_t reg_type, unsigned reg_idx, DynInstPtr inst)
|
||||
{
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][reg_idx].begin();
|
||||
std::list<DynInstPtr>::iterator list_end = regMap[reg_type][reg_idx].end();
|
||||
|
||||
DynInstPtr forward_inst = NULL;
|
||||
|
||||
// Look for instruction immediately in front of requestor to supply
|
||||
// data
|
||||
while (list_it != list_end &&
|
||||
(*list_it)->seqNum < inst->seqNum) {
|
||||
forward_inst = (*list_it);
|
||||
list_it++;
|
||||
}
|
||||
|
||||
if (forward_inst) {
|
||||
int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx);
|
||||
assert(dest_reg_idx != -1);
|
||||
|
||||
DPRINTF(RegDepMap, "[sn:%i] Found potential forwarding value for reg %i "
|
||||
" w/ [sn:%i] dest. reg. #%i\n",
|
||||
inst->seqNum, reg_idx, forward_inst->seqNum, dest_reg_idx);
|
||||
|
||||
if (forward_inst->isExecuted() &&
|
||||
forward_inst->readResultTime(dest_reg_idx) < curTick()) {
|
||||
return forward_inst;
|
||||
} else {
|
||||
if (!forward_inst->isExecuted()) {
|
||||
DPRINTF(RegDepMap, "[sn:%i] Can't get value through "
|
||||
"forwarding, [sn:%i] %s has not been executed yet.\n",
|
||||
inst->seqNum, forward_inst->seqNum, forward_inst->instName());
|
||||
} else if (forward_inst->readResultTime(dest_reg_idx) >= curTick()) {
|
||||
DPRINTF(RegDepMap, "[sn:%i] Can't get value through "
|
||||
"forwarding, [sn:%i] executed on tick:%i.\n",
|
||||
inst->seqNum, forward_inst->seqNum,
|
||||
forward_inst->readResultTime(dest_reg_idx));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n",
|
||||
inst->seqNum);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegDepMap::canWrite(uint8_t reg_type, RegIndex idx, DynInstPtr inst)
|
||||
{
|
||||
if (regMap[reg_type][idx].size() == 0)
|
||||
return true;
|
||||
|
||||
std::list<DynInstPtr>::iterator list_it = regMap[reg_type][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;
|
||||
}
|
||||
|
||||
void
|
||||
RegDepMap::dump()
|
||||
{
|
||||
for (int reg_type = 0; reg_type < InOrderCPU::NumRegTypes; reg_type++) {
|
||||
for (int idx=0; idx < regMap.size(); idx++) {
|
||||
if (regMap[idx].size() > 0) {
|
||||
cprintf("Reg #%i (size:%i): ", idx, regMap[reg_type][idx].size());
|
||||
|
||||
std::list<DynInstPtr>::iterator list_it =
|
||||
regMap[reg_type][idx].begin();
|
||||
std::list<DynInstPtr>::iterator list_end =
|
||||
regMap[reg_type][idx].end();
|
||||
|
||||
while (list_it != list_end) {
|
||||
cprintf("[sn:%i] ", (*list_it)->seqNum);
|
||||
list_it++;
|
||||
}
|
||||
cprintf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
simulators/gem5/src/cpu/inorder/reg_dep_map.hh
Normal file
117
simulators/gem5/src/cpu/inorder/reg_dep_map.hh
Normal file
@ -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_REG_DEP_MAP_HH
|
||||
#define CPU_INORDER_REG_DEP_MAP_HH
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
|
||||
class RegDepMap
|
||||
{
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef TheISA::RegIndex RegIndex;
|
||||
typedef uint8_t RegType;
|
||||
|
||||
RegDepMap(int size = TheISA::TotalNumRegs);
|
||||
~RegDepMap();
|
||||
|
||||
static std::string mapNames[];
|
||||
|
||||
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);
|
||||
|
||||
/** Remove all of a instruction's destination registers into map*/
|
||||
void remove(DynInstPtr inst);
|
||||
|
||||
/** Remove Front instruction from a destination register */
|
||||
void removeFront(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Is the current instruction able to read from this
|
||||
* destination register?
|
||||
*/
|
||||
bool canRead(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Is the current instruction able to get a forwarded value from
|
||||
* another instruction for this destination register?
|
||||
*/
|
||||
DynInstPtr canForward(uint8_t reg_type, unsigned reg_idx,
|
||||
DynInstPtr inst);
|
||||
|
||||
/** find an instruction to forward/bypass a value from */
|
||||
DynInstPtr findBypassInst(RegIndex idx);
|
||||
|
||||
/** Is the current instruction able to write to this
|
||||
* destination register?
|
||||
*/
|
||||
bool canWrite(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Size of Dependency of Map */
|
||||
int depSize(RegIndex idx);
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
/** Insert an instruction into a specific destination register index
|
||||
* onto map.
|
||||
*/
|
||||
void insert(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
/** Remove a specific instruction and dest. register index from map */
|
||||
void remove(uint8_t reg_type, RegIndex idx, DynInstPtr inst);
|
||||
|
||||
typedef std::vector<std::list<DynInstPtr> > DepMap;
|
||||
std::vector<DepMap> regMap;
|
||||
|
||||
InOrderCPU *cpu;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
529
simulators/gem5/src/cpu/inorder/resource.cc
Normal file
529
simulators/gem5/src/cpu/inorder/resource.cc
Normal file
@ -0,0 +1,529 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "base/str.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/ExecFaulting.hh"
|
||||
#include "debug/RefCount.hh"
|
||||
#include "debug/ResReqCount.hh"
|
||||
#include "debug/Resource.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),
|
||||
resourceEvent(NULL)
|
||||
{
|
||||
reqs.resize(width);
|
||||
|
||||
// Use to deny a instruction a resource.
|
||||
deniedReq = new ResourceRequest(this);
|
||||
deniedReq->valid = true;
|
||||
}
|
||||
|
||||
Resource::~Resource()
|
||||
{
|
||||
if (resourceEvent) {
|
||||
delete [] resourceEvent;
|
||||
}
|
||||
|
||||
delete deniedReq;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
delete reqs[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Resource::init()
|
||||
{
|
||||
// If the resource has a zero-cycle (no latency)
|
||||
// function, then no reason to have events
|
||||
// that will process them for the right tick
|
||||
if (latency > 0)
|
||||
resourceEvent = new ResourceEvent[width];
|
||||
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
reqs[i] = new ResourceRequest(this);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (resourceEvent) {
|
||||
resourceEvent[slot_idx].init(this, slot_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Resource::name()
|
||||
{
|
||||
return cpu->name() + "." + resName;
|
||||
}
|
||||
|
||||
int
|
||||
Resource::slotsAvail()
|
||||
{
|
||||
return availSlots.size();
|
||||
}
|
||||
|
||||
int
|
||||
Resource::slotsInUse()
|
||||
{
|
||||
return width - availSlots.size();
|
||||
}
|
||||
|
||||
void
|
||||
Resource::freeSlot(int slot_idx)
|
||||
{
|
||||
DPRINTF(Resource, "Deallocating [slot:%i].\n",
|
||||
slot_idx);
|
||||
|
||||
// Put slot number on this resource's free list
|
||||
availSlots.push_back(slot_idx);
|
||||
|
||||
// Invalidate Request & Reset it's flags
|
||||
reqs[slot_idx]->clearRequest();
|
||||
}
|
||||
|
||||
int
|
||||
Resource::findSlot(DynInstPtr inst)
|
||||
{
|
||||
int slot_num = -1;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (reqs[i]->valid &&
|
||||
reqs[i]->getInst()->seqNum == inst->seqNum) {
|
||||
slot_num = reqs[i]->getSlot();
|
||||
}
|
||||
}
|
||||
return slot_num;
|
||||
}
|
||||
|
||||
int
|
||||
Resource::getSlot(DynInstPtr inst)
|
||||
{
|
||||
int slot_num = -1;
|
||||
|
||||
if (slotsAvail() != 0) {
|
||||
slot_num = availSlots[0];
|
||||
|
||||
vector<int>::iterator vect_it = availSlots.begin();
|
||||
|
||||
assert(slot_num == *vect_it);
|
||||
|
||||
availSlots.erase(vect_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 = -1;
|
||||
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) {
|
||||
DPRINTF(Resource, "Allocating [slot:%i] for [tid:%i]: [sn:%i]\n",
|
||||
slot_num, inst->readTid(), inst->seqNum);
|
||||
|
||||
// Get Stage # from Schedule Entry
|
||||
stage_num = inst->curSkedEntry->stageNum;
|
||||
unsigned cmd = inst->curSkedEntry->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());
|
||||
}
|
||||
|
||||
try_request = true;
|
||||
} else {
|
||||
DPRINTF(Resource, "No slot available for [tid:%i]: [sn:%i]\n",
|
||||
inst->readTid(), inst->seqNum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
reqs[slot_num]->setRequest(inst, stage_num, id, slot_num, cmd);
|
||||
return reqs[slot_num];
|
||||
}
|
||||
|
||||
ResReqPtr
|
||||
Resource::findRequest(DynInstPtr inst)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (reqs[i]->valid &&
|
||||
reqs[i]->getInst() == inst) {
|
||||
return reqs[i];
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//@todo: have each resource print out command their executing
|
||||
DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n",
|
||||
reqs[slot_idx]->getTid(), name());
|
||||
reqs[slot_idx]->setCompleted(true);
|
||||
reqs[slot_idx]->done();
|
||||
}
|
||||
|
||||
void
|
||||
Resource::deactivateThread(ThreadID tid)
|
||||
{
|
||||
// In the most basic case, deactivation means squashing everything
|
||||
// from a particular thread
|
||||
DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid, tid);
|
||||
squash(dummy_inst, 0, 0, tid);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
|
||||
{
|
||||
// Squash In Pipeline Stage
|
||||
cpu->pipelineStage[stage_num]->setupSquash(inst, tid);
|
||||
|
||||
// Schedule Squash Through-out Resource Pool
|
||||
cpu->resPool->scheduleEvent(
|
||||
(InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
{
|
||||
//@todo: check squash seq num before squashing. can save time going
|
||||
// through this function.
|
||||
for (int i = 0; i < width; i++) {
|
||||
ResReqPtr req_ptr = reqs[i];
|
||||
DynInstPtr inst = req_ptr->getInst();
|
||||
|
||||
if (req_ptr->valid &&
|
||||
inst->readTid() == tid &&
|
||||
inst->seqNum > squash_seq_num) {
|
||||
|
||||
DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
|
||||
req_ptr->getInst()->readTid(),
|
||||
req_ptr->getInst()->seqNum);
|
||||
|
||||
req_ptr->setSquashed();
|
||||
|
||||
int req_slot_num = req_ptr->getSlot();
|
||||
|
||||
if (latency > 0) {
|
||||
if (resourceEvent[req_slot_num].scheduled())
|
||||
unscheduleEvent(req_slot_num);
|
||||
}
|
||||
|
||||
freeSlot(req_slot_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Resource::squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
{
|
||||
squash(inst, stage_num, squash_seq_num, tid);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::squashThenTrap(int stage_num, DynInstPtr inst)
|
||||
{
|
||||
ThreadID tid = inst->readTid();
|
||||
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
if (inst->traceData) {
|
||||
if (inst->staticInst &&
|
||||
inst->fault != NoFault && DTRACE(ExecFaulting)) {
|
||||
inst->traceData->setStageCycle(stage_num, curTick());
|
||||
inst->traceData->setFetchSeq(inst->seqNum);
|
||||
inst->traceData->dump();
|
||||
}
|
||||
|
||||
delete inst->traceData;
|
||||
inst->traceData = NULL;
|
||||
}
|
||||
|
||||
cpu->trapContext(inst->fault, tid, inst);
|
||||
}
|
||||
|
||||
Tick
|
||||
Resource::ticks(int num_cycles)
|
||||
{
|
||||
return cpu->ticks(num_cycles);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Resource::scheduleExecution(int slot_num)
|
||||
{
|
||||
if (latency >= 1) {
|
||||
scheduleEvent(slot_num, 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",
|
||||
reqs[slot_idx]->inst->readTid(),
|
||||
reqs[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::maxReqCount = 0;
|
||||
|
||||
ResourceRequest::ResourceRequest(Resource *_res)
|
||||
: res(_res), inst(NULL), stagePasses(0), valid(false), doneInResource(false),
|
||||
completed(false), squashed(false), processing(false),
|
||||
memStall(false)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceRequest::~ResourceRequest()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
res->cpu->resReqCount--;
|
||||
DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID,
|
||||
res->cpu->resReqCount);
|
||||
#endif
|
||||
inst = NULL;
|
||||
}
|
||||
|
||||
std::string
|
||||
ResourceRequest::name()
|
||||
{
|
||||
return csprintf("%s[slot:%i]:", res->name(), slotNum);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::setRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num, unsigned _cmd)
|
||||
{
|
||||
valid = true;
|
||||
inst = _inst;
|
||||
stageNum = stage_num;
|
||||
resIdx = res_idx;
|
||||
slotNum = slot_num;
|
||||
cmd = _cmd;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::clearRequest()
|
||||
{
|
||||
valid = false;
|
||||
inst = NULL;
|
||||
stagePasses = 0;
|
||||
completed = false;
|
||||
doneInResource = false;
|
||||
squashed = false;
|
||||
memStall = false;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::freeSlot()
|
||||
{
|
||||
assert(res);
|
||||
|
||||
// Free Slot So Another Instruction Can Use This Resource
|
||||
res->freeSlot(slotNum);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceRequest::done(bool completed)
|
||||
{
|
||||
DPRINTF(Resource, "done with request from "
|
||||
"[sn:%i] [tid:%i].\n",
|
||||
inst->seqNum, inst->readTid());
|
||||
|
||||
setCompleted(completed);
|
||||
|
||||
doneInResource = true;
|
||||
}
|
||||
|
||||
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() const
|
||||
{
|
||||
string desc = resource->name() + "-event:slot[" + to_string(slotIdx)
|
||||
+ "]";
|
||||
|
||||
return desc.c_str();
|
||||
}
|
||||
|
||||
void
|
||||
ResourceEvent::scheduleEvent(int delay)
|
||||
{
|
||||
assert(!scheduled() || squashed());
|
||||
resource->cpu->reschedule(this,
|
||||
curTick() + resource->ticks(delay), true);
|
||||
}
|
||||
414
simulators/gem5/src/cpu/inorder/resource.hh
Normal file
414
simulators/gem5/src/cpu/inorder/resource.hh
Normal file
@ -0,0 +1,414 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/types.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inst_seq.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 CacheRequest;
|
||||
typedef CacheRequest* CacheReqPtr;
|
||||
|
||||
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();
|
||||
|
||||
/** 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(ThreadID tid) { }
|
||||
|
||||
/** Deactivate Thread. Default action is to squash all instructions
|
||||
* from deactivated thread.
|
||||
*/
|
||||
virtual void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Resources that care about thread activation override this. */
|
||||
virtual void suspendThread(ThreadID tid) { }
|
||||
|
||||
/** Will be called the cycle before a context switch. Any bookkeeping
|
||||
* that needs to be kept for that, can be done here
|
||||
*/
|
||||
virtual void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) { }
|
||||
|
||||
/** Resources that care when an instruction has been graduated
|
||||
* can override this
|
||||
*/
|
||||
virtual void instGraduated(InstSeqNum seq_num, ThreadID tid) { }
|
||||
|
||||
/** Post-processsing for Trap Generated from this instruction */
|
||||
virtual void trap(Fault fault, ThreadID tid, DynInstPtr inst) { }
|
||||
|
||||
/** 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*/
|
||||
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 void doCacheAccess(DynInstPtr inst, uint64_t *write_result = NULL,
|
||||
CacheReqPtr split_req = NULL)
|
||||
{ panic("doCacheAccess undefined for %s", name()); }
|
||||
|
||||
/** Setup Squash to be sent out to pipeline and resource pool */
|
||||
void setupSquash(DynInstPtr inst, int stage_num, ThreadID tid);
|
||||
|
||||
/** Squash All Requests After This Seq Num */
|
||||
virtual void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Squash Requests Due to a Memory Stall (By Default, same as "squash" */
|
||||
virtual void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Handle Squash & Trap that occured from an instruction in a resource */
|
||||
void squashThenTrap(int stage_num, DynInstPtr inst);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** */
|
||||
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:
|
||||
/** List of all Requests the Resource is Servicing. Each request
|
||||
represents part of the resource's bandwidth
|
||||
*/
|
||||
std::vector<ResReqPtr> reqs;
|
||||
|
||||
/** 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;
|
||||
};
|
||||
|
||||
class ResourceEvent : public Event
|
||||
{
|
||||
public:
|
||||
/** Pointer to the Resource this is an event for */
|
||||
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() const;
|
||||
|
||||
/** Set slot idx for event */
|
||||
void setSlot(int slot) { slotIdx = slot; }
|
||||
|
||||
/** Schedule resource event, regardless of its current state. */
|
||||
void scheduleEvent(int 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 maxReqCount;
|
||||
|
||||
friend class Resource;
|
||||
|
||||
public:
|
||||
ResourceRequest(Resource *_res);
|
||||
|
||||
virtual ~ResourceRequest();
|
||||
|
||||
std::string name();
|
||||
|
||||
int reqID;
|
||||
|
||||
void setRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num, unsigned _cmd);
|
||||
|
||||
virtual void clearRequest();
|
||||
|
||||
/** Acknowledge that this is a request is done and remove
|
||||
* from resource.
|
||||
*/
|
||||
void done(bool completed = true);
|
||||
|
||||
void freeSlot();
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
// GET RESOURCE REQUEST IDENTIFICATION / INFO
|
||||
//
|
||||
/////////////////////////////////////////////
|
||||
/** Get Resource Index */
|
||||
int getResIdx() { return resIdx; }
|
||||
|
||||
/** Get Slot Number */
|
||||
int getSlot() { return slotNum; }
|
||||
bool hasSlot() { return slotNum >= 0; }
|
||||
|
||||
/** Get Stage Number */
|
||||
int getStageNum() { return stageNum; }
|
||||
|
||||
/** Set/Get Thread Ids */
|
||||
void setTid(ThreadID _tid) { tid = _tid; }
|
||||
ThreadID 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;
|
||||
|
||||
/** Not guaranteed to be set, used for debugging */
|
||||
InstSeqNum seqNum;
|
||||
|
||||
/** Command For This Resource */
|
||||
unsigned cmd;
|
||||
|
||||
short stagePasses;
|
||||
|
||||
bool valid;
|
||||
|
||||
bool doneInResource;
|
||||
|
||||
////////////////////////////////////////
|
||||
//
|
||||
// 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(bool cond = true) { processing = cond; }
|
||||
|
||||
/** Get/Set IsWaiting variables */
|
||||
bool isMemStall() { return memStall; }
|
||||
void setMemStall(bool stall = true) { memStall = stall; }
|
||||
|
||||
protected:
|
||||
/** Resource Identification */
|
||||
ThreadID tid;
|
||||
int stageNum;
|
||||
int resIdx;
|
||||
int slotNum;
|
||||
|
||||
/** Resource Request Status */
|
||||
bool completed;
|
||||
bool squashed;
|
||||
bool processing;
|
||||
|
||||
bool memStall;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_RESOURCE_HH__
|
||||
361
simulators/gem5/src/cpu/inorder/resource_pool.9stage.cc
Normal file
361
simulators/gem5/src/cpu/inorder/resource_pool.9stage.cc
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/resource_list.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
|
||||
: cpu(_cpu), instUnit(NULL), dataUnit(NULL)
|
||||
{
|
||||
//@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("itlb", ITLB, StageWidth, 0, _cpu, params));
|
||||
|
||||
|
||||
// Keep track of the instruction fetch unit so we can easily
|
||||
// provide a pointer to it in the CPU.
|
||||
instUnit = new FetchUnit("icache_port", ICache,
|
||||
StageWidth * MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(instUnit);
|
||||
|
||||
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("dtlb", DTLB, StageWidth, 0, _cpu, params));
|
||||
|
||||
// Keep track of the data load/store unit so we can easily provide
|
||||
// a pointer to it in the CPU.
|
||||
dataUnit = new CacheUnit("dcache_port", DCache,
|
||||
StageWidth * MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(dataUnit);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
ThreadID 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, ThreadID 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->squashSeqNum,
|
||||
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->squashSeqNum,
|
||||
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->squashSeqNum,
|
||||
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, ThreadID 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(ThreadID 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(ThreadID 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, ThreadID 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();
|
||||
}
|
||||
472
simulators/gem5/src/cpu/inorder/resource_pool.cc
Normal file
472
simulators/gem5/src/cpu/inorder/resource_pool.cc
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/resource_list.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/Resource.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
|
||||
: cpu(_cpu), instUnit(NULL), dataUnit(NULL)
|
||||
{
|
||||
//@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);
|
||||
|
||||
int stage_width = cpu->stageWidth;
|
||||
|
||||
// Declare Resource Objects
|
||||
// name - id - bandwidth - latency - CPU - Parameters
|
||||
// --------------------------------------------------
|
||||
resources.push_back(new FetchSeqUnit("fetch_seq_unit", FetchSeq,
|
||||
stage_width * 2, 0, _cpu, params));
|
||||
|
||||
// Keep track of the instruction fetch unit so we can easily
|
||||
// provide a pointer to it in the CPU.
|
||||
instUnit = new FetchUnit("icache_port", ICache,
|
||||
stage_width * 2 + MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(instUnit);
|
||||
|
||||
resources.push_back(new DecodeUnit("decode_unit", Decode,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new BranchPredictor("branch_predictor", BPred,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new InstBuffer("fetch_buffer_t0", FetchBuff, 4,
|
||||
0, _cpu, params));
|
||||
|
||||
resources.push_back(new UseDefUnit("regfile_manager", RegManager,
|
||||
stage_width * 3, 0, _cpu,
|
||||
params));
|
||||
|
||||
resources.push_back(new AGENUnit("agen_unit", AGEN,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new ExecutionUnit("execution_unit", ExecUnit,
|
||||
stage_width, 0, _cpu, params));
|
||||
|
||||
resources.push_back(new MultDivUnit("mult_div_unit", MDU,
|
||||
stage_width * 2,
|
||||
0,
|
||||
_cpu,
|
||||
params));
|
||||
|
||||
// Keep track of the data load/store unit so we can easily provide
|
||||
// a pointer to it in the CPU.
|
||||
dataUnit = new CacheUnit("dcache_port", DCache,
|
||||
stage_width * 2 + MaxThreads, 0, _cpu,
|
||||
params);
|
||||
resources.push_back(dataUnit);
|
||||
|
||||
gradObjects.push_back(BPred);
|
||||
resources.push_back(new GraduationUnit("graduation_unit", Grad,
|
||||
stage_width, 0, _cpu,
|
||||
params));
|
||||
|
||||
resources.push_back(new InstBuffer("fetch_buffer_t1", FetchBuff2, 4,
|
||||
0, _cpu, params));
|
||||
|
||||
}
|
||||
|
||||
ResourcePool::~ResourcePool()
|
||||
{
|
||||
cout << "Deleting resources ..." << endl;
|
||||
|
||||
for (int i=0; i < resources.size(); i++) {
|
||||
DPRINTF(Resource, "Deleting resource: %s.\n", resources[i]->name());
|
||||
|
||||
delete resources[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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::print()
|
||||
{
|
||||
for (int i=0; i < resources.size(); i++) {
|
||||
DPRINTF(InOrderDynInst, "Res:%i %s\n",
|
||||
i, resources[i]->name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
ResourcePool::getResIdx(const ThePipeline::ResourceId &res_id)
|
||||
{
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
if (resources[idx]->getId() == res_id)
|
||||
return idx;
|
||||
}
|
||||
|
||||
// todo: change return value to int and return a -1 here
|
||||
// maybe even have enumerated type
|
||||
// panic for now...
|
||||
panic("Can't find resource idx for: %i\n", res_id);
|
||||
|
||||
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,
|
||||
ThreadID tid)
|
||||
{
|
||||
resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num,
|
||||
tid);
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Trap to all "
|
||||
"resources.\n", tid);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++)
|
||||
resources[idx]->trap(fault, tid, inst);
|
||||
}
|
||||
|
||||
int
|
||||
ResourcePool::slotsAvail(int res_idx)
|
||||
{
|
||||
return resources[res_idx]->slotsAvail();
|
||||
}
|
||||
|
||||
int
|
||||
ResourcePool::slotsInUse(int res_idx)
|
||||
{
|
||||
return resources[res_idx]->slotsInUse();
|
||||
}
|
||||
|
||||
//@todo: split this function and call this version schedulePoolEvent
|
||||
// and use this scheduleEvent for scheduling a specific event on
|
||||
// a resource
|
||||
//@todo: For arguments that arent being used in a ResPoolEvent, a dummyParam
|
||||
// or some typedef can be used to signify what's important info
|
||||
// to the event construction
|
||||
void
|
||||
ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
||||
int delay, int res_idx, ThreadID tid)
|
||||
{
|
||||
assert(delay >= 0);
|
||||
|
||||
Tick when = cpu->nextCycle(curTick() + cpu->ticks(delay));
|
||||
|
||||
switch ((int)e_type)
|
||||
{
|
||||
case ResourcePool::InstGraduated:
|
||||
{
|
||||
DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
|
||||
"Event for tick %i.\n", curTick() + delay);
|
||||
ResPoolEventPri grad_pri = ResGrad_Pri;
|
||||
ResPoolEvent *res_pool_event =
|
||||
new ResPoolEvent(this,
|
||||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->seqNum,
|
||||
inst->readTid(),
|
||||
grad_pri);
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
break;
|
||||
|
||||
case ResourcePool::SquashAll:
|
||||
{
|
||||
DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
|
||||
"tick %i.\n", curTick() + delay);
|
||||
ResPoolEventPri squash_pri = ResSquash_Pri;
|
||||
ResPoolEvent *res_pool_event =
|
||||
new ResPoolEvent(this,
|
||||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->squashSeqNum,
|
||||
inst->readTid(),
|
||||
squash_pri);
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
break;
|
||||
|
||||
case ResourcePool::UpdateAfterContextSwitch:
|
||||
{
|
||||
DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event "
|
||||
"for tick %i.\n",
|
||||
curTick() + delay);
|
||||
ResPoolEvent *res_pool_event = new ResPoolEvent(this,
|
||||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->seqNum,
|
||||
inst->readTid());
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
|
||||
InOrderCPU::eventNames[e_type]);
|
||||
}
|
||||
}
|
||||
|
||||
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, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
|
||||
" starting w/stage %i for all instructions above [sn:%i].\n",
|
||||
tid, stage_num, 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::squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum done_seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
|
||||
" starting w/stage %i for all instructions above [sn:%i].\n",
|
||||
tid, stage_num, done_seq_num);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
|
||||
tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::activateThread(ThreadID tid)
|
||||
{
|
||||
bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
|
||||
cpu->numActiveThreads() < 1 ||
|
||||
cpu->activeThreadId() == tid;
|
||||
|
||||
|
||||
if (do_activate) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
|
||||
"resources.\n", tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::deactivateThread(ThreadID 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::suspendThread(ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all "
|
||||
"resources.\n", tid);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[idx]->suspendThread(tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to "
|
||||
"appropriate resources.\n", tid, seq_num);
|
||||
|
||||
int num_resources = gradObjects.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[gradObjects[idx]]->instGraduated(seq_num, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
|
||||
{
|
||||
DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n",
|
||||
tid);
|
||||
|
||||
int num_resources = resources.size();
|
||||
|
||||
for (int idx = 0; idx < num_resources; idx++) {
|
||||
resources[idx]->updateAfterContextSwitch(inst, tid);
|
||||
}
|
||||
}
|
||||
|
||||
ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
|
||||
InOrderCPU::CPUEventType e_type,
|
||||
DynInstPtr _inst,
|
||||
int stage_num,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID _tid,
|
||||
ResPoolEventPri res_pri)
|
||||
: Event(res_pri), resPool(_resPool),
|
||||
eventType(e_type), inst(_inst), seqNum(seq_num),
|
||||
stageNum(stage_num), tid(_tid)
|
||||
{ }
|
||||
|
||||
|
||||
void
|
||||
ResourcePool::ResPoolEvent::process()
|
||||
{
|
||||
switch ((int)eventType)
|
||||
{
|
||||
|
||||
case ResourcePool::InstGraduated:
|
||||
resPool->instGraduated(seqNum, tid);
|
||||
break;
|
||||
|
||||
case ResourcePool::SquashAll:
|
||||
resPool->squashAll(inst, stageNum, seqNum, tid);
|
||||
break;
|
||||
|
||||
case ResourcePool::UpdateAfterContextSwitch:
|
||||
resPool->updateAfterContextSwitch(inst, tid);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized Event Type");
|
||||
}
|
||||
|
||||
resPool->cpu->cpuEventRemoveList.push(this);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ResourcePool::ResPoolEvent::description() const
|
||||
{
|
||||
return "Resource Pool event";
|
||||
}
|
||||
|
||||
/** Schedule resource event, regardless of its current state. */
|
||||
void
|
||||
ResourcePool::ResPoolEvent::scheduleEvent(int delay)
|
||||
{
|
||||
InOrderCPU *cpu = resPool->cpu;
|
||||
assert(!scheduled() || squashed());
|
||||
cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
|
||||
}
|
||||
|
||||
/** Unschedule resource event, regardless of its current state. */
|
||||
void
|
||||
ResourcePool::ResPoolEvent::unscheduleEvent()
|
||||
{
|
||||
if (scheduled())
|
||||
squash();
|
||||
}
|
||||
250
simulators/gem5/src/cpu/inorder/resource_pool.hh
Normal file
250
simulators/gem5/src/cpu/inorder/resource_pool.hh
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2012 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/params.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class CacheUnit;
|
||||
class Event;
|
||||
class FetchUnit;
|
||||
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,
|
||||
UpdateAfterContextSwitch,
|
||||
Default
|
||||
};
|
||||
|
||||
enum ResPoolEventPri {
|
||||
ResPool_Pri = InOrderCPU::InOrderCPU_Pri - 5,
|
||||
ResGrad_Pri,
|
||||
ResSquash_Pri
|
||||
};
|
||||
|
||||
class ResPoolEvent : public Event
|
||||
{
|
||||
protected:
|
||||
/** Resource Pool */
|
||||
ResourcePool *resPool;
|
||||
|
||||
public:
|
||||
InOrderCPU::CPUEventType eventType;
|
||||
|
||||
DynInstPtr inst;
|
||||
|
||||
InstSeqNum seqNum;
|
||||
|
||||
int stageNum;
|
||||
|
||||
ThreadID tid;
|
||||
|
||||
public:
|
||||
/** Constructs a resource event. */
|
||||
ResPoolEvent(ResourcePool *_resPool,
|
||||
InOrderCPU::CPUEventType e_type,
|
||||
DynInstPtr _inst,
|
||||
int stage_num,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID _tid,
|
||||
ResPoolEventPri res_pri = ResPool_Pri);
|
||||
|
||||
/** Set Type of Event To Be Scheduled */
|
||||
void setEvent(InOrderCPU::CPUEventType e_type,
|
||||
DynInstPtr _inst,
|
||||
int stage_num,
|
||||
InstSeqNum seq_num,
|
||||
ThreadID _tid)
|
||||
{
|
||||
eventType = e_type;
|
||||
inst = _inst;
|
||||
seqNum = seq_num;
|
||||
stageNum = stage_num;
|
||||
tid = _tid;
|
||||
}
|
||||
|
||||
/** Processes a resource event. */
|
||||
void process();
|
||||
|
||||
/** Returns the description of the resource event. */
|
||||
const char *description() const;
|
||||
|
||||
/** 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();
|
||||
|
||||
void print();
|
||||
|
||||
/** Register Statistics in All Resources */
|
||||
void regStats();
|
||||
|
||||
/** Returns a specific resource. */
|
||||
unsigned getResIdx(const ThePipeline::ResourceId &res_id);
|
||||
|
||||
/** Returns a pointer to a resource */
|
||||
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,
|
||||
ThreadID tid);
|
||||
|
||||
/** Squash All Resources in Pool after Done Seq. Num */
|
||||
void squashAll(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum done_seq_num, ThreadID tid);
|
||||
|
||||
/** Squash Resources in Pool after a memory stall
|
||||
* NOTE: Only use during Switch-On-Miss Thread model
|
||||
*/
|
||||
void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum done_seq_num, ThreadID tid);
|
||||
|
||||
/** Activate Thread in all resources */
|
||||
void activateThread(ThreadID tid);
|
||||
|
||||
/** De-Activate Thread in all resources */
|
||||
void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Suspend Thread in all resources */
|
||||
void suspendThread(ThreadID tid);
|
||||
|
||||
/** Broadcast Context Switch Update to all resources */
|
||||
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
/** Broadcast graduation to all resources */
|
||||
void instGraduated(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Broadcast trap to all resources */
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
/** 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, ThreadID 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];
|
||||
|
||||
/**
|
||||
* Get a pointer to the (always present) instruction fetch unit.
|
||||
*
|
||||
* @return the instruction unit
|
||||
*/
|
||||
FetchUnit *getInstUnit() const { return instUnit; }
|
||||
|
||||
/**
|
||||
* Get a pointer to the (always present) data load/store unit.
|
||||
*
|
||||
* @return the data cache unit
|
||||
*/
|
||||
CacheUnit *getDataUnit() const { return dataUnit; }
|
||||
|
||||
private:
|
||||
|
||||
/** The instruction fetch unit. */
|
||||
FetchUnit *instUnit;
|
||||
|
||||
/** The data load/store unit. */
|
||||
CacheUnit *dataUnit;
|
||||
|
||||
std::vector<Resource *> resources;
|
||||
|
||||
/** Resources that need to be updated on an inst. graduation */
|
||||
std::vector<int> gradObjects;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_RESOURCE_HH__
|
||||
233
simulators/gem5/src/cpu/inorder/resource_sked.cc
Normal file
233
simulators/gem5/src/cpu/inorder/resource_sked.cc
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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 <cstdio>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource_sked.hh"
|
||||
#include "debug/SkedCache.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
ResourceSked::ResourceSked()
|
||||
{
|
||||
stages.resize(NumStages);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::init()
|
||||
{
|
||||
assert(!stages[0].empty());
|
||||
|
||||
curSkedEntry = stages[0].begin();
|
||||
}
|
||||
|
||||
int
|
||||
ResourceSked::size()
|
||||
{
|
||||
int total = 0;
|
||||
for (int i = 0; i < stages.size(); i++) {
|
||||
total += stages[i].size();
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceSked::empty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::begin()
|
||||
{
|
||||
int num_stages = stages.size();
|
||||
for (int i = 0; i < num_stages; i++) {
|
||||
if (stages[i].size() > 0)
|
||||
return stages[i].begin();
|
||||
}
|
||||
|
||||
return stages[num_stages - 1].end();
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::end()
|
||||
{
|
||||
int num_stages = stages.size();
|
||||
return stages[num_stages - 1].end();
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::end(int stage_num)
|
||||
{
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::find(int stage_num, int cmd)
|
||||
{
|
||||
SkedIt stage_it = stages[stage_num].begin();
|
||||
SkedIt stage_end = stages[stage_num].end();
|
||||
|
||||
while (stage_it != stage_end) {
|
||||
if ((*stage_it)->cmd == cmd)
|
||||
return stage_it;
|
||||
stage_it++;
|
||||
}
|
||||
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
ScheduleEntry*
|
||||
ResourceSked::top()
|
||||
{
|
||||
assert(size() > 0);
|
||||
|
||||
return *curSkedEntry;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::pop()
|
||||
{
|
||||
int stage_num = (*curSkedEntry)->stageNum;
|
||||
|
||||
stages[stage_num].erase(curSkedEntry);
|
||||
|
||||
if (!stages[stage_num].empty()) {
|
||||
curSkedEntry = stages[stage_num].begin();
|
||||
} else {
|
||||
int next_stage = stage_num + 1;
|
||||
|
||||
while (next_stage < NumStages) {
|
||||
if (stages[next_stage].empty()) {
|
||||
next_stage++;
|
||||
} else {
|
||||
curSkedEntry = stages[next_stage].begin();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::push(ScheduleEntry* sked_entry)
|
||||
{
|
||||
int stage_num = sked_entry->stageNum;
|
||||
assert(stage_num < NumStages);
|
||||
|
||||
SkedIt pri_iter = findIterByPriority(sked_entry, stage_num);
|
||||
|
||||
stages[stage_num].insert(pri_iter, sked_entry);
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::pushBefore(ScheduleEntry* sked_entry, int sked_cmd,
|
||||
int sked_cmd_idx)
|
||||
{
|
||||
|
||||
int stage_num = sked_entry->stageNum;
|
||||
assert(stage_num < NumStages);
|
||||
|
||||
SkedIt pri_iter = findIterByCommand(sked_entry, stage_num,
|
||||
sked_cmd, sked_cmd_idx);
|
||||
|
||||
assert(pri_iter != stages[stage_num].end() &&
|
||||
"Could not find command to insert in front of.");
|
||||
|
||||
stages[stage_num].insert(pri_iter, sked_entry);
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::findIterByPriority(ScheduleEntry* sked_entry, int stage_num)
|
||||
{
|
||||
if (stages[stage_num].empty()) {
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
int priority = sked_entry->priority;
|
||||
|
||||
SkedIt sked_it = stages[stage_num].begin();
|
||||
SkedIt sked_end = stages[stage_num].end();
|
||||
|
||||
while (sked_it != sked_end) {
|
||||
if ((*sked_it)->priority > priority)
|
||||
break;
|
||||
|
||||
sked_it++;
|
||||
}
|
||||
|
||||
return sked_it;
|
||||
}
|
||||
|
||||
ResourceSked::SkedIt
|
||||
ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num,
|
||||
int sked_cmd, int sked_cmd_idx)
|
||||
{
|
||||
if (stages[stage_num].empty()) {
|
||||
return stages[stage_num].end();
|
||||
}
|
||||
|
||||
SkedIt sked_it = stages[stage_num].begin();
|
||||
SkedIt sked_end = stages[stage_num].end();
|
||||
|
||||
while (sked_it != sked_end) {
|
||||
if ((*sked_it)->cmd == sked_cmd &&
|
||||
(sked_cmd_idx != -1) ? (*sked_it)->idx == sked_cmd_idx : true)
|
||||
break;
|
||||
|
||||
sked_it++;
|
||||
}
|
||||
|
||||
return sked_it;
|
||||
}
|
||||
|
||||
void
|
||||
ResourceSked::print()
|
||||
{
|
||||
for (int i = 0; i < stages.size(); i++) {
|
||||
//ccprintf(cerr, "Stage %i\n====\n", i);
|
||||
SkedIt sked_it = stages[i].begin();
|
||||
SkedIt sked_end = stages[i].end();
|
||||
while (sked_it != sked_end) {
|
||||
DPRINTF(SkedCache, "\t stage:%i res:%i cmd:%i idx:%i\n",
|
||||
(*sked_it)->stageNum,
|
||||
(*sked_it)->resNum,
|
||||
(*sked_it)->cmd,
|
||||
(*sked_it)->idx);
|
||||
sked_it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
285
simulators/gem5/src/cpu/inorder/resource_sked.hh
Normal file
285
simulators/gem5/src/cpu/inorder/resource_sked.hh
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 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 __CPU_INORDER_RESOURCE_SKED_HH__
|
||||
#define __CPU_INORDER_RESOURCE_SKED_HH__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
/** ScheduleEntry class represents a single function that an instruction
|
||||
wants to do at any pipeline stage. For example, if an instruction
|
||||
needs to be decoded and do a branch prediction all in one stage
|
||||
then each of those tasks would need it's own ScheduleEntry.
|
||||
|
||||
Each schedule entry corresponds to some resource that the instruction
|
||||
wants to interact with.
|
||||
|
||||
The file pipeline_traits.cc shows how a typical instruction schedule is
|
||||
made up of these schedule entries.
|
||||
*/
|
||||
class ScheduleEntry {
|
||||
public:
|
||||
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)
|
||||
{ }
|
||||
|
||||
/** 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;
|
||||
};
|
||||
|
||||
/** The ResourceSked maintains the complete schedule
|
||||
for an instruction. That schedule includes what
|
||||
resources an instruction wants to acquire at each
|
||||
pipeline stage and is represented by a collection
|
||||
of ScheduleEntry objects (described above) that
|
||||
must be executed in-order.
|
||||
|
||||
In every pipeline stage, the InOrder model will
|
||||
process all entries on the resource schedule for
|
||||
that stage and then send the instruction to the next
|
||||
stage if and only if the instruction successfully
|
||||
completed each ScheduleEntry.
|
||||
*/
|
||||
class ResourceSked {
|
||||
public:
|
||||
typedef std::list<ScheduleEntry*>::iterator SkedIt;
|
||||
typedef std::vector<std::list<ScheduleEntry*> > StageList;
|
||||
|
||||
ResourceSked();
|
||||
|
||||
/** Initializee the current entry pointer to
|
||||
pipeline stage 0 and the 1st schedule entry
|
||||
*/
|
||||
void init();
|
||||
|
||||
/** Goes through the remaining stages on the schedule
|
||||
and sums all the remaining entries left to be
|
||||
processed
|
||||
*/
|
||||
int size();
|
||||
|
||||
/** Is the schedule empty? */
|
||||
bool empty();
|
||||
|
||||
/** Beginning Entry of this schedule */
|
||||
SkedIt begin();
|
||||
|
||||
/** Ending Entry of this schedule */
|
||||
SkedIt end();
|
||||
|
||||
/** Ending Entry of a specified stage */
|
||||
SkedIt end(int stage_num);
|
||||
|
||||
/** Find a schedule entry based on stage and command */
|
||||
SkedIt find(int stage_num, int cmd);
|
||||
|
||||
/** What is the next task for this instruction schedule? */
|
||||
ScheduleEntry* top();
|
||||
|
||||
/** Top() Task is completed, remove it from schedule */
|
||||
void pop();
|
||||
|
||||
/** Add To Schedule based on stage num and priority of
|
||||
Schedule Entry
|
||||
*/
|
||||
void push(ScheduleEntry* sked_entry);
|
||||
|
||||
/** Add Schedule Entry to be in front of another Entry */
|
||||
void pushBefore(ScheduleEntry* sked_entry, int sked_cmd, int sked_cmd_idx);
|
||||
|
||||
/** Print what's left on the instruction schedule */
|
||||
void print();
|
||||
|
||||
StageList *getStages()
|
||||
{
|
||||
return &stages;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Current Schedule Entry Pointer */
|
||||
SkedIt curSkedEntry;
|
||||
|
||||
/** The Stage-by-Stage Resource Schedule:
|
||||
Resized to Number of Stages in the constructor
|
||||
*/
|
||||
StageList stages;
|
||||
|
||||
/** Find a place to insert the instruction using the
|
||||
schedule entries priority
|
||||
*/
|
||||
SkedIt findIterByPriority(ScheduleEntry *sked_entry, int stage_num);
|
||||
|
||||
/** Find a place to insert the instruction using a particular command
|
||||
to look for.
|
||||
*/
|
||||
SkedIt findIterByCommand(ScheduleEntry *sked_entry, int stage_num,
|
||||
int sked_cmd, int sked_cmd_idx = -1);
|
||||
};
|
||||
|
||||
/** Wrapper class around the SkedIt iterator in the Resource Sked so that
|
||||
we can use ++ operator to automatically go to the next available
|
||||
resource schedule entry but otherwise maintain same functionality
|
||||
as a normal iterator.
|
||||
*/
|
||||
class RSkedIt
|
||||
{
|
||||
public:
|
||||
RSkedIt()
|
||||
: curStage(0), numStages(0)
|
||||
{ }
|
||||
|
||||
|
||||
/** init() must be called before the use of any other member
|
||||
in the RSkedIt class.
|
||||
*/
|
||||
void init(ResourceSked* rsked)
|
||||
{
|
||||
stages = rsked->getStages();
|
||||
numStages = stages->size();
|
||||
}
|
||||
|
||||
/* Update the encapsulated "myIt" iterator, but only
|
||||
update curStage/curStage_end if the iterator is valid.
|
||||
The iterator could be invalid in the case where
|
||||
someone is saving the end of a list (i.e. std::list->end())
|
||||
*/
|
||||
RSkedIt operator=(ResourceSked::SkedIt const &rhs)
|
||||
{
|
||||
myIt = rhs;
|
||||
if (myIt != (*stages)[numStages-1].end()) {
|
||||
curStage = (*myIt)->stageNum;
|
||||
curStage_end = (*stages)[curStage].end();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Increment to the next entry in current stage.
|
||||
If no more entries then find the next stage that has
|
||||
resource schedule to complete.
|
||||
If no more stages, then return the end() iterator from
|
||||
the last stage to indicate we are done.
|
||||
*/
|
||||
RSkedIt &operator++(int unused)
|
||||
{
|
||||
if (++myIt == curStage_end) {
|
||||
curStage++;
|
||||
while (curStage < numStages) {
|
||||
if ((*stages)[curStage].empty()) {
|
||||
curStage++;
|
||||
} else {
|
||||
myIt = (*stages)[curStage].begin();
|
||||
curStage_end = (*stages)[curStage].end();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
myIt = (*stages)[numStages - 1].end();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** The "pointer" operator can be used on a RSkedIt and it
|
||||
will use the encapsulated iterator
|
||||
*/
|
||||
ScheduleEntry* operator->()
|
||||
{
|
||||
return *myIt;
|
||||
}
|
||||
|
||||
/** Dereferencing a RSKedIt will access the encapsulated
|
||||
iterator
|
||||
*/
|
||||
ScheduleEntry* operator*()
|
||||
{
|
||||
return *myIt;
|
||||
}
|
||||
|
||||
/** Equality for RSkedIt only compares the "myIt" iterators,
|
||||
as the other members are just ancillary
|
||||
*/
|
||||
bool operator==(RSkedIt const &rhs)
|
||||
{
|
||||
return this->myIt == rhs.myIt;
|
||||
}
|
||||
|
||||
/** Inequality for RSkedIt only compares the "myIt" iterators,
|
||||
as the other members are just ancillary
|
||||
*/
|
||||
bool operator!=(RSkedIt const &rhs)
|
||||
{
|
||||
return this->myIt != rhs.myIt;
|
||||
}
|
||||
|
||||
/* The == and != operator overloads should be sufficient
|
||||
here if need otherwise direct access to the schedule
|
||||
iterator, then this can be used */
|
||||
ResourceSked::SkedIt getIt()
|
||||
{
|
||||
return myIt;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Schedule Iterator that this class is encapsulating */
|
||||
ResourceSked::SkedIt myIt;
|
||||
|
||||
/** Ptr to resource schedule that the 'myIt' iterator
|
||||
belongs to
|
||||
*/
|
||||
ResourceSked::StageList *stages;
|
||||
|
||||
/** The last iterator in the current stage. */
|
||||
ResourceSked::SkedIt curStage_end;
|
||||
|
||||
/** Current Stage that "myIt" refers to. */
|
||||
int curStage;
|
||||
|
||||
/** Number of stages in the "*stages" object. */
|
||||
int numStages;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_RESOURCE_SKED_HH__
|
||||
107
simulators/gem5/src/cpu/inorder/resources/agen_unit.cc
Normal file
107
simulators/gem5/src/cpu/inorder/resources/agen_unit.cc
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "debug/InOrderAGEN.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::regStats()
|
||||
{
|
||||
agens
|
||||
.name(name() + ".agens")
|
||||
.desc("Number of Address Generations");
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
AGENUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* agen_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
#if TRACING_ON
|
||||
ThreadID tid = inst->readTid();
|
||||
#endif
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderAGEN,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
agen_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (agen_req->cmd)
|
||||
{
|
||||
case GenerateAddr:
|
||||
{
|
||||
// Load/Store Instruction
|
||||
if (inst->isMemRef()) {
|
||||
DPRINTF(InOrderAGEN,
|
||||
"[tid:%i] Generating Address for [sn:%i] (%s).\n",
|
||||
tid, seq_num, inst->staticInst->getName());
|
||||
|
||||
inst->fault = inst->calcEA();
|
||||
inst->setMemAddr(inst->getEA());
|
||||
|
||||
DPRINTF(InOrderAGEN,
|
||||
"[tid:%i] [sn:%i] Effective address calculated as: %#x\n",
|
||||
tid, seq_num, inst->getEA());
|
||||
|
||||
if (inst->fault == NoFault) {
|
||||
agen_req->done();
|
||||
} else {
|
||||
fatal("%s encountered while calculating address [sn:%i] %s",
|
||||
inst->fault->name(), seq_num, inst->instName());
|
||||
}
|
||||
|
||||
agens++;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
64
simulators/gem5/src/cpu/inorder/resources/agen_unit.hh
Normal file
64
simulators/gem5/src/cpu/inorder/resources/agen_unit.hh
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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_AGEN_UNIT_HH__
|
||||
#define __CPU_INORDER_AGEN_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/params.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class AGENUnit : public Resource {
|
||||
public:
|
||||
typedef InOrderDynInst::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
AGENUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
enum Command {
|
||||
GenerateAddr
|
||||
};
|
||||
|
||||
virtual void execute(int slot_num);
|
||||
void regStats();
|
||||
|
||||
protected:
|
||||
Stats::Scalar agens;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_DECODE_UNIT_HH__
|
||||
464
simulators/gem5/src/cpu/inorder/resources/bpred_unit.cc
Normal file
464
simulators/gem5/src/cpu/inorder/resources/bpred_unit.cc
Normal file
@ -0,0 +1,464 @@
|
||||
|
||||
/*
|
||||
* 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 "arch/utility.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/bpred_unit.hh"
|
||||
#include "debug/InOrderBPred.hh"
|
||||
#include "debug/Resource.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ThePipeline;
|
||||
|
||||
BPredUnit::BPredUnit(Resource *_res, ThePipeline::Params *params)
|
||||
: res(_res),
|
||||
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);
|
||||
|
||||
instSize = sizeof(TheISA::MachInst);
|
||||
}
|
||||
|
||||
std::string
|
||||
BPredUnit::name()
|
||||
{
|
||||
return res->name();
|
||||
}
|
||||
|
||||
void
|
||||
BPredUnit::regStats()
|
||||
{
|
||||
lookups
|
||||
.name(name() + ".lookups")
|
||||
.desc("Number of BP lookups")
|
||||
;
|
||||
|
||||
condPredicted
|
||||
.name(name() + ".condPredicted")
|
||||
.desc("Number of conditional branches predicted")
|
||||
;
|
||||
|
||||
condIncorrect
|
||||
.name(name() + ".condIncorrect")
|
||||
.desc("Number of conditional branches incorrect")
|
||||
;
|
||||
|
||||
BTBLookups
|
||||
.name(name() + ".BTBLookups")
|
||||
.desc("Number of BTB lookups")
|
||||
;
|
||||
|
||||
BTBHits
|
||||
.name(name() + ".BTBHits")
|
||||
.desc("Number of BTB hits")
|
||||
;
|
||||
|
||||
BTBHitPct
|
||||
.name(name() + ".BTBHitPct")
|
||||
.desc("BTB Hit Percentage")
|
||||
.precision(6);
|
||||
BTBHitPct = (BTBHits / BTBLookups) * 100;
|
||||
|
||||
usedRAS
|
||||
.name(name() + ".usedRAS")
|
||||
.desc("Number of times the RAS was used to get a target.")
|
||||
;
|
||||
|
||||
RASIncorrect
|
||||
.name(name() + ".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, TheISA::PCState &predPC, ThreadID 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;
|
||||
|
||||
int asid = inst->asid;
|
||||
bool pred_taken = false;
|
||||
TheISA::PCState target;
|
||||
|
||||
++lookups;
|
||||
DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
|
||||
"prediction\n", tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(inst->instAddr()),
|
||||
inst->pcState());
|
||||
|
||||
|
||||
void *bp_history = NULL;
|
||||
|
||||
if (inst->isUncondCtrl()) {
|
||||
DPRINTF(InOrderBPred, "[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(InOrderBPred, "[tid:%i] RAS is empty, predicting "
|
||||
"false.\n", tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
} else {
|
||||
++condPredicted;
|
||||
|
||||
pred_taken = BPLookup(predPC.instAddr(), bp_history);
|
||||
}
|
||||
|
||||
PredictorHistory predict_record(inst->seqNum, predPC, 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.
|
||||
TheISA::PCState rasTop = RAS[tid].top();
|
||||
target = TheISA::buildRetPC(inst->pcState(), rasTop);
|
||||
|
||||
// Record the top entry of the RAS, and its index.
|
||||
predict_record.usedRAS = true;
|
||||
predict_record.RASIndex = RAS[tid].topIdx();
|
||||
predict_record.rasTarget = rasTop;
|
||||
|
||||
assert(predict_record.RASIndex < 16);
|
||||
|
||||
RAS[tid].pop();
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: Instruction %s is a return, "
|
||||
"RAS predicted target: %s, RAS index: %i.\n",
|
||||
tid, inst->pcState(), target,
|
||||
predict_record.RASIndex);
|
||||
} else {
|
||||
++BTBLookups;
|
||||
|
||||
if (inst->isCall()) {
|
||||
|
||||
RAS[tid].push(inst->pcState());
|
||||
|
||||
// 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(InOrderBPred, "[tid:%i]: Instruction %s was a call"
|
||||
", adding %s to the RAS index: %i.\n",
|
||||
tid, inst->pcState(), predPC,
|
||||
RAS[tid].topIdx());
|
||||
}
|
||||
|
||||
if (inst->isCall() &&
|
||||
inst->isUncondCtrl() &&
|
||||
inst->isDirectCtrl()) {
|
||||
target = inst->branchTarget();
|
||||
} else if (BTB.valid(predPC.instAddr(), asid)) {
|
||||
++BTBHits;
|
||||
|
||||
// If it's not a return, use the BTB to get the target addr.
|
||||
target = BTB.lookup(predPC.instAddr(), asid);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [asid:%i] Instruction %s "
|
||||
"predicted target is %s.\n",
|
||||
tid, asid, inst->pcState(), target);
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: BTB doesn't have a "
|
||||
"valid entry, predicting false.\n",tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pred_taken) {
|
||||
// Set the PC and the instruction's predicted target.
|
||||
predPC = target;
|
||||
}
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
|
||||
tid, inst->seqNum, predPC);
|
||||
|
||||
predHist[tid].push_front(predict_record);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] pushed onto front of predHist "
|
||||
"...predHist.size(): %i\n",
|
||||
tid, inst->seqNum, predHist[tid].size());
|
||||
|
||||
return pred_taken;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPredUnit::update(const InstSeqNum &done_sn, ThreadID 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.instAddr(),
|
||||
predHist[tid].back().predTaken,
|
||||
predHist[tid].back().bpHistory,
|
||||
false);
|
||||
|
||||
predHist[tid].pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid, ThreadID asid)
|
||||
{
|
||||
History &pred_hist = predHist[tid];
|
||||
|
||||
while (!pred_hist.empty() &&
|
||||
pred_hist.front().seqNum > squashed_sn) {
|
||||
if (pred_hist.front().usedRAS) {
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Restoring top of RAS "
|
||||
"to: %i, target: %s.\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(InOrderBPred, "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 TheISA::PCState &corrTarget,
|
||||
bool actually_taken,
|
||||
ThreadID tid,
|
||||
ThreadID asid)
|
||||
{
|
||||
// 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(InOrderBPred, "[tid:%i]: Squashing from sequence number %i, "
|
||||
"setting target to %s.\n",
|
||||
tid, squashed_sn, corrTarget);
|
||||
|
||||
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()) {
|
||||
HistoryIt hist_it = pred_hist.begin();
|
||||
//HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
|
||||
// squashed_sn);
|
||||
|
||||
//assert(hist_it != pred_hist.end());
|
||||
if (pred_hist.front().seqNum != squashed_sn) {
|
||||
DPRINTF(InOrderBPred, "Front sn %i != Squash sn %i\n",
|
||||
pred_hist.front().seqNum, squashed_sn);
|
||||
|
||||
assert(pred_hist.front().seqNum == squashed_sn);
|
||||
}
|
||||
|
||||
|
||||
if ((*hist_it).usedRAS) {
|
||||
++RASIncorrect;
|
||||
}
|
||||
|
||||
BPUpdate((*hist_it).pc.instAddr(), actually_taken,
|
||||
pred_hist.front().bpHistory, true);
|
||||
|
||||
// only update BTB on branch taken right???
|
||||
if (actually_taken)
|
||||
BTB.update((*hist_it).pc.instAddr(), corrTarget, asid);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: Removing history for [sn:%i] "
|
||||
"PC %s.\n", tid, (*hist_it).seqNum, (*hist_it).pc);
|
||||
|
||||
pred_hist.erase(hist_it);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: predHist.size(): %i\n", tid,
|
||||
predHist[tid].size());
|
||||
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i] pred_hist empty, can't "
|
||||
"update.\n", tid, squashed_sn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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, bool squashed)
|
||||
{
|
||||
if (predictor == Local) {
|
||||
localBP->update(inst_PC, taken, bp_history);
|
||||
} else if (predictor == Tournament) {
|
||||
tournamentBP->update(inst_PC, taken, bp_history, squashed);
|
||||
} 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");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
267
simulators/gem5/src/cpu/inorder/resources/bpred_unit.hh
Normal file
267
simulators/gem5/src/cpu/inorder/resources/bpred_unit.hh
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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__
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/pred/2bit_local.hh"
|
||||
#include "cpu/pred/btb.hh"
|
||||
#include "cpu/pred/ras.hh"
|
||||
#include "cpu/pred/tournament.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
|
||||
/**
|
||||
* 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(Resource *_res, ThePipeline::Params *params);
|
||||
|
||||
std::string name();
|
||||
|
||||
/**
|
||||
* 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 predPC 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,
|
||||
TheISA::PCState &predPC, ThreadID 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, ThreadID 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, ThreadID tid,
|
||||
ThreadID asid = 0);
|
||||
|
||||
/**
|
||||
* 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 corrTarget The correct branch target.
|
||||
* @param actually_taken The correct branch direction.
|
||||
* @param tid The thread id.
|
||||
*/
|
||||
void squash(const InstSeqNum &squashed_sn,
|
||||
const TheISA::PCState &corrTarget, bool actually_taken,
|
||||
ThreadID tid, ThreadID asid = 0);
|
||||
|
||||
/**
|
||||
* @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 instPC, 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.
|
||||
*/
|
||||
TheISA::PCState BTBLookup(Addr instPC)
|
||||
{ return BTB.lookup(instPC, 0); }
|
||||
|
||||
/**
|
||||
* Updates the BP with taken/not taken information.
|
||||
* @param instPC 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.
|
||||
* @param squashed if the branch in question was squashed or not
|
||||
* @todo Make this update flexible enough to handle a global predictor.
|
||||
*/
|
||||
void BPUpdate(Addr instPC, bool taken, void *bp_history, bool squashed);
|
||||
|
||||
/**
|
||||
* 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 instPC, const TheISA::PCState &targetPC)
|
||||
{ BTB.update(instPC, targetPC, 0); }
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
int instSize;
|
||||
Resource *res;
|
||||
|
||||
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 TheISA::PCState &instPC, bool pred_taken,
|
||||
void *bp_history, ThreadID _tid)
|
||||
: seqNum(seq_num), pc(instPC), 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. */
|
||||
TheISA::PCState pc;
|
||||
|
||||
/** The RAS target (only valid if a return). */
|
||||
TheISA::PCState rasTarget;
|
||||
|
||||
/** The RAS index of the instruction (only valid if a call). */
|
||||
unsigned RASIndex;
|
||||
|
||||
/** The thread id. */
|
||||
ThreadID 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;
|
||||
typedef History::iterator HistoryIt;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
Stats::Formula BTBHitPct;
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_BPRED_UNIT_HH__
|
||||
181
simulators/gem5/src/cpu/inorder/resources/branch_predictor.cc
Normal file
181
simulators/gem5/src/cpu/inorder/resources/branch_predictor.cc
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/branch_predictor.hh"
|
||||
#include "debug/InOrderBPred.hh"
|
||||
#include "debug/InOrderStage.hh"
|
||||
#include "debug/Resource.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(this, 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();
|
||||
|
||||
branchPred.regStats();
|
||||
}
|
||||
|
||||
void
|
||||
BranchPredictor::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* bpred_req = reqs[slot_num];
|
||||
DynInstPtr inst = bpred_req->inst;
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderBPred,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
bpred_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inst->isControl()) {
|
||||
DPRINTF(Resource, "Ignoring %s, not a control inst.\n",
|
||||
inst->instName());
|
||||
bpred_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadID tid = inst->readTid();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
switch (bpred_req->cmd)
|
||||
{
|
||||
case PredictBranch:
|
||||
{
|
||||
if (inst->seqNum > cpu->squashSeqNum[tid] &&
|
||||
curTick() == cpu->lastSquashCycle[tid]) {
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, "
|
||||
"skipping prediction \n", tid, inst->seqNum);
|
||||
} else {
|
||||
TheISA::PCState pred_PC = inst->pcState();
|
||||
TheISA::advancePC(pred_PC, inst->staticInst);
|
||||
|
||||
if (inst->isControl()) {
|
||||
// If not, the pred_PC be updated to pc+8
|
||||
// If predicted, the pred_PC will be updated to new target
|
||||
// value
|
||||
bool predict_taken = branchPred.predict(inst, pred_PC, tid);
|
||||
|
||||
if (predict_taken) {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch "
|
||||
"predicted true.\n", tid, seq_num);
|
||||
predictedTaken++;
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch "
|
||||
"predicted false.\n", tid, seq_num);
|
||||
predictedNotTaken++;
|
||||
}
|
||||
|
||||
inst->setBranchPred(predict_taken);
|
||||
}
|
||||
|
||||
//@todo: Check to see how hw_rei is handled here...how does PC,NPC get
|
||||
// updated to compare mispredict against???
|
||||
inst->setPredTarg(pred_PC);
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: %s Predicted PC is "
|
||||
"%s.\n", tid, seq_num, inst->instName(), pred_PC);
|
||||
}
|
||||
|
||||
bpred_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
case UpdatePredictor:
|
||||
{
|
||||
if (inst->seqNum > cpu->squashSeqNum[tid] &&
|
||||
curTick() == cpu->lastSquashCycle[tid]) {
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, "
|
||||
"skipping branch predictor update \n",
|
||||
tid, inst->seqNum);
|
||||
} else {
|
||||
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, ThreadID tid)
|
||||
{
|
||||
InstSeqNum bpred_squash_num = inst->seqNum;
|
||||
DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid,
|
||||
bpred_squash_num);
|
||||
|
||||
// update due to branch resolution
|
||||
if (squash_stage >= ThePipeline::BackEndStartStage) {
|
||||
branchPred.squash(bpred_squash_num,
|
||||
inst->pcState(),
|
||||
inst->pcState().branching(),
|
||||
tid);
|
||||
} else {
|
||||
// update due to predicted taken branch
|
||||
branchPred.squash(bpred_squash_num, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BranchPredictor::instGraduated(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
branchPred.update(seq_num, tid);
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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_BRANCH_PREDICTOR_HH__
|
||||
#define __CPU_INORDER_BRANCH_PREDICTOR_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/bpred_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class BranchPredictor : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
enum Command {
|
||||
PredictBranch,
|
||||
UpdatePredictor
|
||||
};
|
||||
|
||||
public:
|
||||
BranchPredictor(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
void regStats();
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void instGraduated(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
protected:
|
||||
/** List of instructions this resource is currently
|
||||
* processing.
|
||||
*/
|
||||
BPredUnit branchPred;
|
||||
|
||||
int instSize;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RESOURCE STATISTICS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Stats::Scalar predictedTaken;
|
||||
Stats::Scalar predictedNotTaken;
|
||||
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
|
||||
1288
simulators/gem5/src/cpu/inorder/resources/cache_unit.cc
Normal file
1288
simulators/gem5/src/cpu/inorder/resources/cache_unit.cc
Normal file
File diff suppressed because it is too large
Load Diff
268
simulators/gem5/src/cpu/inorder/resources/cache_unit.hh
Normal file
268
simulators/gem5/src/cpu/inorder/resources/cache_unit.hh
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/tlb.hh"
|
||||
#include "base/hashmap.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
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);
|
||||
|
||||
enum Command {
|
||||
InitiateReadData,
|
||||
CompleteReadData,
|
||||
InitiateWriteData,
|
||||
CompleteWriteData,
|
||||
InitSecondSplitRead,
|
||||
InitSecondSplitWrite,
|
||||
CompleteSecondSplitRead,
|
||||
CompleteSecondSplitWrite
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
void init();
|
||||
|
||||
ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num,
|
||||
unsigned cmd);
|
||||
|
||||
ResReqPtr findRequest(DynInstPtr inst);
|
||||
ResReqPtr findRequest(DynInstPtr inst, int idx);
|
||||
|
||||
void requestAgain(DynInstPtr inst, bool &try_request);
|
||||
|
||||
virtual int getSlot(DynInstPtr inst);
|
||||
|
||||
/** Executes one of the commands from the "Command" enum */
|
||||
virtual void execute(int slot_num);
|
||||
|
||||
virtual void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
virtual void squashCacheRequest(CacheReqPtr req_ptr);
|
||||
|
||||
/** After memory request is completedd in the cache, then do final
|
||||
processing to complete the request in the CPU.
|
||||
*/
|
||||
virtual void processCacheCompletion(PacketPtr pkt);
|
||||
|
||||
/** Create request that will interface w/TLB and Memory objects */
|
||||
virtual void setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
|
||||
int acc_size, int flags);
|
||||
|
||||
void finishCacheUnitReq(DynInstPtr inst, CacheRequest *cache_req);
|
||||
|
||||
void buildDataPacket(CacheRequest *cache_req);
|
||||
|
||||
bool processSquash(CacheReqPacket *cache_pkt);
|
||||
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
void recvRetry();
|
||||
|
||||
Fault read(DynInstPtr inst, Addr addr,
|
||||
uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
Fault write(DynInstPtr inst, uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
void doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
|
||||
int flags, TheISA::TLB::Mode tlb_mode);
|
||||
|
||||
/** Read/Write on behalf of an instruction.
|
||||
* curResSlot needs to be a valid value in instruction.
|
||||
*/
|
||||
void doCacheAccess(DynInstPtr inst, uint64_t *write_result=NULL,
|
||||
CacheReqPtr split_req=NULL);
|
||||
|
||||
uint64_t getMemData(Packet *packet);
|
||||
|
||||
void setAddrDependency(DynInstPtr inst);
|
||||
virtual void removeAddrDependency(DynInstPtr inst);
|
||||
|
||||
protected:
|
||||
/** Cache interface. */
|
||||
MasterPort *cachePort;
|
||||
|
||||
bool cachePortBlocked;
|
||||
|
||||
std::list<Addr> addrList[ThePipeline::MaxThreads];
|
||||
|
||||
m5::hash_map<Addr, InstSeqNum> addrMap[ThePipeline::MaxThreads];
|
||||
|
||||
public:
|
||||
int cacheBlkSize;
|
||||
|
||||
int cacheBlkMask;
|
||||
|
||||
/** Align a PC to the start of the Cache block. */
|
||||
Addr cacheBlockAlign(Addr addr)
|
||||
{
|
||||
return (addr & ~(cacheBlkMask));
|
||||
}
|
||||
|
||||
bool tlbBlocked[ThePipeline::MaxThreads];
|
||||
InstSeqNum tlbBlockSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
TheISA::TLB* tlb();
|
||||
TheISA::TLB *_tlb;
|
||||
};
|
||||
|
||||
class CacheUnitEvent : public ResourceEvent {
|
||||
public:
|
||||
const std::string name() const
|
||||
{
|
||||
return "CacheUnitEvent";
|
||||
}
|
||||
|
||||
|
||||
/** Constructs a resource event. */
|
||||
CacheUnitEvent();
|
||||
virtual ~CacheUnitEvent() {}
|
||||
|
||||
/** Processes a resource event. */
|
||||
void process();
|
||||
};
|
||||
|
||||
//@todo: Move into CacheUnit Class for private access to "valid" field
|
||||
class CacheRequest : public ResourceRequest
|
||||
{
|
||||
public:
|
||||
CacheRequest(CacheUnit *cres)
|
||||
: ResourceRequest(cres), memReq(NULL), reqData(NULL),
|
||||
dataPkt(NULL), memAccComplete(false),
|
||||
memAccPending(false), tlbStall(false), splitAccess(false),
|
||||
splitAccessNum(-1), split2ndAccess(false),
|
||||
fetchBufferFill(false)
|
||||
{ }
|
||||
|
||||
virtual ~CacheRequest()
|
||||
{
|
||||
if (reqData && !splitAccess)
|
||||
delete [] reqData;
|
||||
}
|
||||
|
||||
void setRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num,
|
||||
unsigned _cmd, MemCmd::Command pkt_cmd, int idx)
|
||||
{
|
||||
pktCmd = pkt_cmd;
|
||||
instIdx = idx;
|
||||
|
||||
ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num, _cmd);
|
||||
}
|
||||
|
||||
void clearRequest();
|
||||
|
||||
virtual PacketDataPtr getData()
|
||||
{ return reqData; }
|
||||
|
||||
void
|
||||
setMemAccCompleted(bool completed = true)
|
||||
{
|
||||
memAccComplete = completed;
|
||||
}
|
||||
|
||||
bool is2ndSplit()
|
||||
{
|
||||
return split2ndAccess;
|
||||
}
|
||||
|
||||
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;
|
||||
CacheReqPacket *dataPkt;
|
||||
|
||||
bool memAccComplete;
|
||||
bool memAccPending;
|
||||
bool tlbStall;
|
||||
|
||||
bool splitAccess;
|
||||
int splitAccessNum;
|
||||
bool split2ndAccess;
|
||||
int instIdx;
|
||||
|
||||
/** Should we expect block from cache access or fetch buffer? */
|
||||
bool fetchBufferFill;
|
||||
};
|
||||
|
||||
class CacheReqPacket : public Packet
|
||||
{
|
||||
public:
|
||||
CacheReqPacket(CacheRequest *_req,
|
||||
Command _cmd, int _idx = 0)
|
||||
: Packet(&(*_req->memReq), _cmd), cacheReq(_req),
|
||||
instIdx(_idx), hasSlot(false), reqData(NULL), memReq(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CacheRequest *cacheReq;
|
||||
int instIdx;
|
||||
bool hasSlot;
|
||||
PacketDataPtr reqData;
|
||||
RequestPtr memReq;
|
||||
};
|
||||
|
||||
#endif //__CPU_CACHE_UNIT_HH__
|
||||
97
simulators/gem5/src/cpu/inorder/resources/decode_unit.cc
Normal file
97
simulators/gem5/src/cpu/inorder/resources/decode_unit.cc
Normal file
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/decode_unit.hh"
|
||||
#include "debug/InOrderDecode.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "debug/Resource.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 (ThreadID tid = 0; tid < MaxThreads; tid++) {
|
||||
regDepMap[tid] = &cpu->archRegDepMap[tid];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DecodeUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* decode_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
|
||||
switch (decode_req->cmd)
|
||||
{
|
||||
case DecodeInst:
|
||||
{
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
inst->setBackSked(cpu->faultSked);
|
||||
DPRINTF(InOrderDecode,"[tid:%i]: Fault found for instruction [sn:%i]\n",
|
||||
inst->readTid(), inst->seqNum);
|
||||
} else {
|
||||
assert(!inst->staticInst->isMacroop());
|
||||
inst->setBackSked(cpu->createBackEndSked(inst));
|
||||
DPRINTF(InOrderDecode,"Decoded instruction [sn:%i]: %s : 0x%x\n",
|
||||
inst->seqNum, inst->instName(),
|
||||
inst->staticInst->machInst);
|
||||
}
|
||||
|
||||
if (inst->backSked != NULL) {
|
||||
DPRINTF(InOrderDecode,
|
||||
"[tid:%i]: Back End Schedule created for %s [sn:%i].\n",
|
||||
inst->readTid(), inst->instName(), inst->seqNum);
|
||||
decode_req->done();
|
||||
} else {
|
||||
DPRINTF(Resource,
|
||||
"[tid:%i] Static Inst not available to decode.\n",
|
||||
inst->readTid());
|
||||
DPRINTF(Resource,
|
||||
"Unable to create schedule for instruction [sn:%i] \n",
|
||||
inst->seqNum);
|
||||
DPRINTF(InOrderStall, "STALL: \n");
|
||||
decode_req->done(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
65
simulators/gem5/src/cpu/inorder/resources/decode_unit.hh
Normal file
65
simulators/gem5/src/cpu/inorder/resources/decode_unit.hh
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "cpu/inorder/resource.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);
|
||||
|
||||
enum Command {
|
||||
DecodeInst
|
||||
};
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
RegDepMap *regDepMap[ThePipeline::MaxThreads];
|
||||
|
||||
protected:
|
||||
/** @todo: Add Resource Stats Here */
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_DECODE_UNIT_HH__
|
||||
249
simulators/gem5/src/cpu/inorder/resources/execution_unit.cc
Normal file
249
simulators/gem5/src/cpu/inorder/resources/execution_unit.cc
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/execution_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/Fault.hh"
|
||||
#include "debug/InOrderExecute.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "sim/full_system.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),
|
||||
lastExecuteTick(0), lastControlTick(0)
|
||||
{ }
|
||||
|
||||
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).");
|
||||
|
||||
executions
|
||||
.name(name() + ".executions")
|
||||
.desc("Number of Instructions Executed.");
|
||||
|
||||
|
||||
predictedIncorrect
|
||||
.name(name() + ".mispredicted")
|
||||
.desc("Number of Branches Incorrectly Predicted");
|
||||
|
||||
predictedCorrect
|
||||
.name(name() + ".predicted")
|
||||
.desc("Number of Branches Incorrectly Predicted");
|
||||
|
||||
mispredictPct
|
||||
.name(name() + ".mispredictPct")
|
||||
.desc("Percentage of Incorrect Branches Predicts")
|
||||
.precision(6);
|
||||
mispredictPct = (predictedIncorrect /
|
||||
(predictedCorrect + predictedIncorrect)) * 100;
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
ExecutionUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* exec_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderExecute,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
exec_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
Fault fault = NoFault;
|
||||
Tick cur_tick = curTick();
|
||||
unsigned stage_num = exec_req->getStageNum();
|
||||
ThreadID tid = inst->readTid();
|
||||
#if TRACING_ON
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
#endif
|
||||
|
||||
switch (exec_req->cmd)
|
||||
{
|
||||
case ExecuteInst:
|
||||
{
|
||||
if (inst->isNop()) {
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] [PC:%s] Ignoring execution"
|
||||
"of %s.\n", inst->readTid(), seq_num, inst->pcState(),
|
||||
inst->instName());
|
||||
inst->setExecuted();
|
||||
exec_req->done();
|
||||
return;
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%s] %s.\n",
|
||||
inst->readTid(), seq_num, inst->pcState(), inst->instName());
|
||||
}
|
||||
|
||||
if (cur_tick != lastExecuteTick) {
|
||||
lastExecuteTick = cur_tick;
|
||||
}
|
||||
|
||||
//@todo: handle address generation here
|
||||
assert(!inst->isMemRef());
|
||||
|
||||
if (inst->isControl()) {
|
||||
if (lastControlTick == cur_tick) {
|
||||
DPRINTF(InOrderExecute, "Can not Execute More than One Control "
|
||||
"Inst Per Cycle. Blocking Request.\n");
|
||||
exec_req->done(false);
|
||||
return;
|
||||
}
|
||||
lastControlTick = curTick();
|
||||
|
||||
// Evaluate Branch
|
||||
fault = inst->execute();
|
||||
|
||||
// Should unconditional control , pc relative count as an
|
||||
// execution??? Probably not.
|
||||
executions++;
|
||||
|
||||
if (fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
if (inst->mispredicted()) {
|
||||
assert(inst->isControl());
|
||||
|
||||
// Set up Squash Generated By this Misprediction
|
||||
TheISA::PCState pc = inst->pcState();
|
||||
TheISA::advancePC(pc, inst->staticInst);
|
||||
inst->setPredTarg(pc);
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i] Squashing from "
|
||||
"stage %i. Redirecting fetch to %s.\n", tid,
|
||||
inst->seqNum, stage_num, pc);
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
|
||||
" misprediction at %s\n", tid, inst->pcState());
|
||||
|
||||
if (inst->predTaken()) {
|
||||
predictedTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
|
||||
"PC %s ... Mispredicts! "
|
||||
"(Prediction: Taken)\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(
|
||||
inst->instAddr()),
|
||||
inst->pcState());
|
||||
} else {
|
||||
predictedNotTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
|
||||
"PC %s ... Mispredicts! "
|
||||
"(Prediction: Not Taken)\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(
|
||||
inst->instAddr()),
|
||||
inst->pcState());
|
||||
}
|
||||
predictedIncorrect++;
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Prediction"
|
||||
"Correct.\n", inst->readTid(), seq_num);
|
||||
predictedCorrect++;
|
||||
}
|
||||
|
||||
exec_req->done();
|
||||
} else {
|
||||
DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
|
||||
inst->readTid(), inst->seqNum, fault->name());
|
||||
inst->fault = fault;
|
||||
exec_req->done();
|
||||
}
|
||||
} else {
|
||||
// Regular ALU instruction
|
||||
fault = inst->execute();
|
||||
executions++;
|
||||
|
||||
if (fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
#if TRACING_ON
|
||||
for (int didx = 0; didx < inst->numDestRegs(); didx++)
|
||||
if (inst->resultType(didx) == InOrderDynInst::Float ||
|
||||
inst->resultType(didx) == InOrderDynInst::FloatBits ||
|
||||
inst->resultType(didx) == InOrderDynInst::Double)
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Dest result %i "
|
||||
"of FP execution is %08f (%x).\n", inst->readTid(),
|
||||
seq_num, didx, inst->readFloatResult(didx),
|
||||
inst->readFloatBitsResult(didx));
|
||||
else
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Dest result %i "
|
||||
"of Int execution is 0x%x.\n", inst->readTid(),
|
||||
seq_num, didx, inst->readIntResult(didx));
|
||||
#endif
|
||||
|
||||
if (!FullSystem) {
|
||||
// The Syscall might change the PC, so conservatively
|
||||
// squash everything behing it
|
||||
if (inst->isSyscall()) {
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: had a %s "
|
||||
"fault.\n", inst->readTid(), seq_num, fault->name());
|
||||
DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
|
||||
inst->readTid(), inst->seqNum, fault->name());
|
||||
inst->fault = fault;
|
||||
}
|
||||
|
||||
exec_req->done();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
82
simulators/gem5/src/cpu/inorder/resources/execution_unit.hh
Normal file
82
simulators/gem5/src/cpu/inorder/resources/execution_unit.hh
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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_EXECUTION_UNIT_HH__
|
||||
#define __CPU_INORDER_EXECUTION_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
|
||||
class ExecutionUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
enum Command {
|
||||
ExecuteInst
|
||||
};
|
||||
|
||||
public:
|
||||
ExecutionUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
public:
|
||||
void regStats();
|
||||
|
||||
/** 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);
|
||||
|
||||
protected:
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RESOURCE STATISTICS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Stats::Scalar predictedTakenIncorrect;
|
||||
Stats::Scalar predictedNotTakenIncorrect;
|
||||
Stats::Scalar predictedIncorrect;
|
||||
Stats::Scalar predictedCorrect;
|
||||
Stats::Formula mispredictPct;
|
||||
Stats::Scalar executions;
|
||||
Tick lastExecuteTick;
|
||||
Tick lastControlTick;
|
||||
};
|
||||
|
||||
|
||||
#endif //__CPU_INORDER_EXCUTION_UNIT_HH__
|
||||
335
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.cc
Normal file
335
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.cc
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/fetch_seq_unit.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/InOrderFetchSeq.hh"
|
||||
#include "debug/InOrderStall.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 (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = 0;
|
||||
|
||||
//@todo: Use CPU's squashSeqNum here instead of maintaining our own
|
||||
// state
|
||||
squashSeqNum[tid] = (InstSeqNum)-1;
|
||||
lastSquashCycle[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FetchSeqUnit::~FetchSeqUnit()
|
||||
{
|
||||
delete [] resourceEvent;
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::init()
|
||||
{
|
||||
resourceEvent = new FetchSeqEvent[width];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new ResourceRequest(this);
|
||||
}
|
||||
|
||||
initSlots();
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* fs_req = reqs[slot_num];
|
||||
DynInstPtr inst = fs_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = fs_req->getStageNum();
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderFetchSeq,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
fs_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fs_req->cmd)
|
||||
{
|
||||
case AssignNextPC:
|
||||
{
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Current PC is %s\n", tid,
|
||||
pc[tid]);
|
||||
|
||||
if (pcValid[tid]) {
|
||||
inst->pcState(pc[tid]);
|
||||
inst->setMemAddr(pc[tid].instAddr());
|
||||
|
||||
// Advance to next PC (typically PC + 4)
|
||||
pc[tid].advance();
|
||||
|
||||
inst->setSeqNum(cpu->getAndIncrementInstSeq(tid));
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to "
|
||||
"PC %s\n", tid, inst->seqNum, inst->pcState());
|
||||
|
||||
fs_req->done();
|
||||
} else {
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid);
|
||||
fs_req->done(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case UpdateTargetPC:
|
||||
{
|
||||
assert(!inst->isCondDelaySlot() &&
|
||||
"Not Handling Conditional Delay Slot");
|
||||
|
||||
if (inst->isControl()) {
|
||||
if (inst->isReturn() && !inst->predTaken()) {
|
||||
// If it's a return, then we must wait for resolved address.
|
||||
// The Predictor will mark a return a false as "not taken"
|
||||
// if there is no RAS entry
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting block signal "
|
||||
"for stage %i.\n",
|
||||
tid, stage_num);
|
||||
cpu->pipelineStage[stage_num]->
|
||||
toPrevStages->stageBlock[stage_num][tid] = true;
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = stage_num;
|
||||
} else if (inst->predTaken()) {
|
||||
// Taken Control
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
|
||||
"start from stage %i, after [sn:%i].\n",
|
||||
tid, stage_num, inst->squashSeqNum);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from %s (%s) "
|
||||
"stage %i.\n", tid, inst->instName(), inst->pcState(),
|
||||
squash_stage);
|
||||
|
||||
if (lastSquashCycle[tid] == curTick() &&
|
||||
squashSeqNum[tid] <= squash_seq_num) {
|
||||
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] = squash_seq_num;
|
||||
lastSquashCycle[tid] = curTick();
|
||||
|
||||
if (inst->staticInst) {
|
||||
if (inst->fault != NoFault) {
|
||||
// A Trap Caused This Fault and will update the pc state
|
||||
// when done trapping
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i] Blocking due to fault @ "
|
||||
"[sn:%i].%s %s \n", inst->seqNum,
|
||||
inst->instName(), inst->pcState());
|
||||
pcValid[tid] = false;
|
||||
} else {
|
||||
TheISA::PCState nextPC;
|
||||
assert(inst->staticInst);
|
||||
if (inst->isControl()) {
|
||||
nextPC = inst->readPredTarg();
|
||||
|
||||
// If we are already fetching this PC then advance to next PC
|
||||
// =======
|
||||
// This should handle ISAs w/delay slots and annulled delay
|
||||
// slots to figure out which is the next PC to fetch after
|
||||
// a mispredict
|
||||
DynInstPtr bdelay_inst = NULL;
|
||||
ListIt bdelay_it;
|
||||
if (inst->onInstList) {
|
||||
bdelay_it = inst->getInstListIt();
|
||||
bdelay_it++;
|
||||
} else {
|
||||
InstSeqNum branch_delay_num = inst->seqNum + 1;
|
||||
bdelay_it = cpu->findInst(branch_delay_num, tid);
|
||||
}
|
||||
|
||||
if (bdelay_it != cpu->instList[tid].end()) {
|
||||
bdelay_inst = (*bdelay_it);
|
||||
}
|
||||
|
||||
if (bdelay_inst) {
|
||||
if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
|
||||
bdelay_inst->pc = nextPC;
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
DPRINTF(InOrderFetchSeq, "Advanced PC to %s\n", nextPC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextPC = inst->pcState();
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
}
|
||||
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
|
||||
tid, nextPC);
|
||||
pc[tid] = nextPC;
|
||||
|
||||
// Unblock Any Stages Waiting for this information to be updated ...
|
||||
if (!pcValid[tid]) {
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting unblock signal "
|
||||
"for stage %i.\n",
|
||||
tid, pcBlockStage[tid]);
|
||||
|
||||
// Need to use "fromNextStages" instead of "toPrevStages"
|
||||
// because the timebuffer will have already have advanced
|
||||
// in the tick function and this squash function will happen after
|
||||
// the tick
|
||||
cpu->pipelineStage[pcBlockStage[tid]]->
|
||||
fromNextStages->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->pcState(i);
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC: %s.\n",
|
||||
fs_res->pc[i]);
|
||||
|
||||
fs_res->pcValid[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FetchSeqUnit::activateThread(ThreadID tid)
|
||||
{
|
||||
pcValid[tid] = true;
|
||||
|
||||
pc[tid] = cpu->pcState(tid);
|
||||
|
||||
cpu->fetchPriorityList.push_back(tid);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC: %s.\n",
|
||||
tid, pc[tid]);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::deactivateThread(ThreadID tid)
|
||||
{
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = 0;
|
||||
|
||||
squashSeqNum[tid] = (InstSeqNum)-1;
|
||||
lastSquashCycle[tid] = 0;
|
||||
|
||||
list<ThreadID>::iterator thread_it = find(cpu->fetchPriorityList.begin(),
|
||||
cpu->fetchPriorityList.end(),
|
||||
tid);
|
||||
|
||||
if (thread_it != cpu->fetchPriorityList.end())
|
||||
cpu->fetchPriorityList.erase(thread_it);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::suspendThread(ThreadID tid)
|
||||
{
|
||||
deactivateThread(tid);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
pcValid[tid] = true;
|
||||
pc[tid] = cpu->pcState(tid);
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Trap updating to PC: "
|
||||
"%s.\n", tid, pc[tid]);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
|
||||
{
|
||||
pcValid[tid] = true;
|
||||
|
||||
if (cpu->thread[tid]->lastGradIsBranch) {
|
||||
/** This function assumes that the instruction causing the context
|
||||
* switch was right after the branch. Thus, if it's not, then
|
||||
* we are updating incorrectly here
|
||||
*/
|
||||
assert(cpu->nextInstAddr(tid) == inst->instAddr());
|
||||
pc[tid] = cpu->thread[tid]->lastBranchPC;
|
||||
} else {
|
||||
pc[tid] = inst->pcState();
|
||||
}
|
||||
assert(inst->staticInst);
|
||||
advancePC(pc[tid], inst->staticInst);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating PCs due to Context Switch."
|
||||
"Assigning PC: %s.\n", tid, pc[tid]);
|
||||
}
|
||||
104
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.hh
Normal file
104
simulators/gem5/src/cpu/inorder/resources/fetch_seq_unit.hh
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class FetchSeqUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef std::list<DynInstPtr>::iterator ListIt;
|
||||
|
||||
enum Command {
|
||||
AssignNextPC,
|
||||
UpdateTargetPC
|
||||
};
|
||||
|
||||
public:
|
||||
FetchSeqUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
~FetchSeqUnit();
|
||||
|
||||
void init();
|
||||
void activateThread(ThreadID tid);
|
||||
void deactivateThread(ThreadID tid);
|
||||
void suspendThread(ThreadID tid);
|
||||
void execute(int slot_num);
|
||||
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
|
||||
/** Update to correct PC from a squash */
|
||||
void squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Update to correct PC from a trap */
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
protected:
|
||||
unsigned instSize;
|
||||
|
||||
bool pcValid[ThePipeline::MaxThreads];
|
||||
int pcBlockStage[ThePipeline::MaxThreads];
|
||||
|
||||
TheISA::PCState pc[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();
|
||||
~FetchSeqEvent() {}
|
||||
|
||||
/** Processes a resource event. */
|
||||
void process();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
592
simulators/gem5/src/cpu/inorder/resources/fetch_unit.cc
Normal file
592
simulators/gem5/src/cpu/inorder/resources/fetch_unit.cc
Normal file
@ -0,0 +1,592 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/locked_mem.hh"
|
||||
#include "arch/utility.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/cache_unit.hh"
|
||||
#include "cpu/inorder/resources/fetch_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/Activity.hh"
|
||||
#include "debug/InOrderCachePort.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "debug/RefCount.hh"
|
||||
#include "debug/ThreadModel.hh"
|
||||
#include "mem/request.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
using namespace ThePipeline;
|
||||
|
||||
FetchUnit::FetchUnit(string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu,
|
||||
ThePipeline::Params *params)
|
||||
: CacheUnit(res_name, res_id, res_width, res_latency, _cpu, params),
|
||||
instSize(sizeof(TheISA::MachInst)), fetchBuffSize(params->fetchBuffSize)
|
||||
{
|
||||
for (int tid = 0; tid < MaxThreads; tid++)
|
||||
decoder[tid] = new Decoder(NULL);
|
||||
}
|
||||
|
||||
FetchUnit::~FetchUnit()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
while (fetch_it != end_it) {
|
||||
delete (*fetch_it)->block;
|
||||
delete *fetch_it;
|
||||
fetch_it++;
|
||||
}
|
||||
fetchBuffer.clear();
|
||||
|
||||
|
||||
std::list<FetchBlock*>::iterator pend_it = pendingFetch.begin();
|
||||
std::list<FetchBlock*>::iterator pend_end = pendingFetch.end();
|
||||
while (pend_it != pend_end) {
|
||||
if ((*pend_it)->block) {
|
||||
delete (*pend_it)->block;
|
||||
}
|
||||
|
||||
delete *pend_it;
|
||||
pend_it++;
|
||||
}
|
||||
pendingFetch.clear();
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::createMachInst(std::list<FetchBlock*>::iterator fetch_it,
|
||||
DynInstPtr inst)
|
||||
{
|
||||
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
Addr fetch_addr = inst->getMemAddr();
|
||||
unsigned fetch_offset = (fetch_addr - block_addr) / instSize;
|
||||
ThreadID tid = inst->readTid();
|
||||
TheISA::PCState instPC = inst->pcState();
|
||||
|
||||
|
||||
DPRINTF(InOrderCachePort, "Creating instruction [sn:%i] w/fetch data @"
|
||||
"addr:%08p block:%08p\n", inst->seqNum, fetch_addr, block_addr);
|
||||
|
||||
assert((*fetch_it)->valid);
|
||||
|
||||
TheISA::MachInst *fetchInsts =
|
||||
reinterpret_cast<TheISA::MachInst *>((*fetch_it)->block);
|
||||
|
||||
MachInst mach_inst =
|
||||
TheISA::gtoh(fetchInsts[fetch_offset]);
|
||||
|
||||
decoder[tid]->setTC(cpu->thread[tid]->getTC());
|
||||
decoder[tid]->moreBytes(instPC, inst->instAddr(), mach_inst);
|
||||
assert(decoder[tid]->instReady());
|
||||
inst->setStaticInst(decoder[tid]->decode(instPC));
|
||||
inst->pcState(instPC);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::removeAddrDependency(DynInstPtr inst)
|
||||
{
|
||||
inst->unsetMemAddr();
|
||||
}
|
||||
|
||||
ResReqPtr
|
||||
FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
|
||||
int slot_num, unsigned cmd)
|
||||
{
|
||||
ScheduleEntry* sched_entry = *inst->curSkedEntry;
|
||||
CacheRequest* cache_req = dynamic_cast<CacheRequest*>(reqs[slot_num]);
|
||||
|
||||
if (!inst->validMemAddr()) {
|
||||
panic("Mem. Addr. must be set before requesting cache access\n");
|
||||
}
|
||||
|
||||
assert(sched_entry->cmd == InitiateFetch);
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: Fetch request from [sn:%i] for addr %08p\n",
|
||||
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
||||
|
||||
cache_req->setRequest(inst, stage_num, id, slot_num,
|
||||
sched_entry->cmd, MemCmd::ReadReq,
|
||||
inst->curSkedEntry->idx);
|
||||
|
||||
return cache_req;
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
|
||||
int acc_size, int flags)
|
||||
{
|
||||
ThreadID tid = inst->readTid();
|
||||
Addr aligned_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
if (cache_req->memReq == NULL) {
|
||||
cache_req->memReq =
|
||||
new Request(tid, aligned_addr, acc_size, flags,
|
||||
cpu->instMasterId(), inst->instAddr(), cpu->readCpuId(),
|
||||
tid);
|
||||
DPRINTF(InOrderCachePort, "[sn:%i] Created memReq @%x, ->%x\n",
|
||||
inst->seqNum, &cache_req->memReq, cache_req->memReq);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<FetchUnit::FetchBlock*>::iterator
|
||||
FetchUnit::findBlock(std::list<FetchBlock*> &fetch_blocks, int asid,
|
||||
Addr block_addr)
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetch_blocks.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetch_blocks.end();
|
||||
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->asid == asid &&
|
||||
(*fetch_it)->addr == block_addr) {
|
||||
return fetch_it;
|
||||
}
|
||||
|
||||
fetch_it++;
|
||||
}
|
||||
|
||||
return fetch_it;
|
||||
}
|
||||
|
||||
std::list<FetchUnit::FetchBlock*>::iterator
|
||||
FetchUnit::findReplacementBlock()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->cnt == 0) {
|
||||
return fetch_it;
|
||||
} else {
|
||||
DPRINTF(InOrderCachePort, "Block %08p has %i insts pending.\n",
|
||||
(*fetch_it)->addr, (*fetch_it)->cnt);
|
||||
}
|
||||
fetch_it++;
|
||||
}
|
||||
|
||||
return fetch_it;
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::markBlockUsed(std::list<FetchBlock*>::iterator block_it)
|
||||
{
|
||||
// Move block from whatever location it is in fetch buffer
|
||||
// to the back (represents most-recently-used location)
|
||||
if (block_it != fetchBuffer.end()) {
|
||||
FetchBlock *mru_blk = *block_it;
|
||||
fetchBuffer.erase(block_it);
|
||||
fetchBuffer.push_back(mru_blk);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
FetchUnit::blocksInUse()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
|
||||
int cnt = 0;
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->cnt > 0)
|
||||
cnt++;
|
||||
|
||||
fetch_it++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::clearFetchBuffer()
|
||||
{
|
||||
std::list<FetchBlock*>::iterator fetch_it = fetchBuffer.begin();
|
||||
std::list<FetchBlock*>::iterator end_it = fetchBuffer.end();
|
||||
|
||||
while (fetch_it != end_it) {
|
||||
if ((*fetch_it)->block) {
|
||||
delete [] (*fetch_it)->block;
|
||||
}
|
||||
delete *fetch_it;
|
||||
fetch_it++;
|
||||
}
|
||||
fetchBuffer.clear();
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::execute(int slot_num)
|
||||
{
|
||||
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqs[slot_num]);
|
||||
assert(cache_req);
|
||||
|
||||
if (cachePortBlocked && cache_req->cmd == InitiateFetch) {
|
||||
DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n");
|
||||
cache_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DynInstPtr inst = cache_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
int asid = cpu->asid[tid];
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
cacheBlockAlign(inst->getMemAddr()));
|
||||
finishCacheUnitReq(inst, cache_req);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cache_req->cmd)
|
||||
{
|
||||
case InitiateFetch:
|
||||
{
|
||||
// Check to see if we've already got this request buffered
|
||||
// or pending to be buffered
|
||||
bool do_fetch = true;
|
||||
int total_pending = pendingFetch.size() + blocksInUse();
|
||||
|
||||
std::list<FetchBlock*>::iterator pending_it;
|
||||
pending_it = findBlock(pendingFetch, asid, block_addr);
|
||||
if (pending_it != pendingFetch.end()) {
|
||||
(*pending_it)->cnt++;
|
||||
do_fetch = false;
|
||||
|
||||
DPRINTF(InOrderCachePort, "%08p is a pending fetch block "
|
||||
"(pending:%i).\n", block_addr,
|
||||
(*pending_it)->cnt);
|
||||
} else if (total_pending < fetchBuffSize) {
|
||||
std::list<FetchBlock*>::iterator buff_it;
|
||||
buff_it = findBlock(fetchBuffer, asid, block_addr);
|
||||
if (buff_it != fetchBuffer.end()) {
|
||||
(*buff_it)->cnt++;
|
||||
do_fetch = false;
|
||||
|
||||
DPRINTF(InOrderCachePort, "%08p is in fetch buffer "
|
||||
"(pending:%i).\n", block_addr, (*buff_it)->cnt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_fetch) {
|
||||
DPRINTF(InOrderCachePort, "Inst. [sn:%i] marked to be filled "
|
||||
"through fetch buffer.\n", inst->seqNum);
|
||||
cache_req->fetchBufferFill = true;
|
||||
cache_req->setCompleted(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if there is room in the fetchbuffer for this instruction.
|
||||
// If not, block this request.
|
||||
if (total_pending >= fetchBuffSize) {
|
||||
DPRINTF(InOrderCachePort, "No room available in fetch buffer.\n");
|
||||
cache_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
doTLBAccess(inst, cache_req, cacheBlkSize, Request::INST_FETCH, TheISA::TLB::Execute);
|
||||
|
||||
if (inst->fault == NoFault) {
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%u]: Initiating fetch access to %s for "
|
||||
"addr:%#x (block:%#x)\n", tid, name(),
|
||||
cache_req->inst->getMemAddr(), block_addr);
|
||||
|
||||
cache_req->reqData = new uint8_t[cacheBlkSize];
|
||||
|
||||
inst->setCurResSlot(slot_num);
|
||||
|
||||
doCacheAccess(inst);
|
||||
|
||||
if (cache_req->isMemAccPending()) {
|
||||
pendingFetch.push_back(new FetchBlock(asid, block_addr));
|
||||
|
||||
// mark replacement block
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CompleteFetch:
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
|
||||
inst->getMemAddr());
|
||||
finishCacheUnitReq(inst, cache_req);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache_req->fetchBufferFill) {
|
||||
// Block request if it's depending on a previous fetch, but it hasnt made it yet
|
||||
std::list<FetchBlock*>::iterator fetch_it = findBlock(fetchBuffer, asid, block_addr);
|
||||
if (fetch_it == fetchBuffer.end()) {
|
||||
DPRINTF(InOrderCachePort, "%#x not available yet\n",
|
||||
block_addr);
|
||||
cache_req->setCompleted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make New Instruction
|
||||
createMachInst(fetch_it, inst);
|
||||
if (inst->traceData) {
|
||||
inst->traceData->setStaticInst(inst->staticInst);
|
||||
inst->traceData->setPC(inst->pcState());
|
||||
}
|
||||
|
||||
// FetchBuffer Book-Keeping
|
||||
(*fetch_it)->cnt--;
|
||||
assert((*fetch_it)->cnt >= 0);
|
||||
markBlockUsed(fetch_it);
|
||||
|
||||
cache_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache_req->isMemAccComplete()) {
|
||||
if (fetchBuffer.size() >= fetchBuffSize) {
|
||||
// If there is no replacement block, then we'll just have
|
||||
// to wait till that gets cleared before satisfying the fetch
|
||||
// for this instruction
|
||||
std::list<FetchBlock*>::iterator repl_it =
|
||||
findReplacementBlock();
|
||||
if (repl_it == fetchBuffer.end()) {
|
||||
DPRINTF(InOrderCachePort, "Unable to find replacement block"
|
||||
" and complete fetch.\n");
|
||||
cache_req->setCompleted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
delete [] (*repl_it)->block;
|
||||
delete *repl_it;
|
||||
fetchBuffer.erase(repl_it);
|
||||
}
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%i]: Completing Fetch Access for [sn:%i]\n",
|
||||
tid, inst->seqNum);
|
||||
|
||||
// Make New Instruction
|
||||
std::list<FetchBlock*>::iterator fetch_it =
|
||||
findBlock(pendingFetch, asid, block_addr);
|
||||
|
||||
assert(fetch_it != pendingFetch.end());
|
||||
assert((*fetch_it)->valid);
|
||||
|
||||
createMachInst(fetch_it, inst);
|
||||
if (inst->traceData) {
|
||||
inst->traceData->setStaticInst(inst->staticInst);
|
||||
inst->traceData->setPC(inst->pcState());
|
||||
}
|
||||
|
||||
|
||||
// Update instructions waiting on new fetch block
|
||||
FetchBlock *new_block = (*fetch_it);
|
||||
new_block->cnt--;
|
||||
assert(new_block->cnt >= 0);
|
||||
|
||||
// Finally, update FetchBuffer w/Pending Block into the
|
||||
// MRU location
|
||||
pendingFetch.erase(fetch_it);
|
||||
fetchBuffer.push_back(new_block);
|
||||
|
||||
DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(inst->instAddr()));
|
||||
|
||||
inst->unsetMemAddr();
|
||||
|
||||
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->instAddr());
|
||||
cache_req->setCompleted(false);
|
||||
// NOTE: For SwitchOnCacheMiss ThreadModel, we *don't* switch on
|
||||
// fetch miss, but we could ...
|
||||
// cache_req->setMemStall(true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::processCacheCompletion(PacketPtr pkt)
|
||||
{
|
||||
// Cast to correct packet type
|
||||
// @todo: use pkt Sender state here to be consistent with other
|
||||
// cpu models
|
||||
CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
|
||||
assert(cache_pkt);
|
||||
|
||||
DPRINTF(InOrderCachePort, "Finished request for %x\n",
|
||||
cache_pkt->getAddr());
|
||||
|
||||
if (processSquash(cache_pkt))
|
||||
return;
|
||||
|
||||
Addr block_addr = cacheBlockAlign(cache_pkt->cacheReq->
|
||||
getInst()->getMemAddr());
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%u]: [sn:%i]: Waking from fetch access to addr:%#x(phys:%#x), size:%i\n",
|
||||
cache_pkt->cacheReq->getInst()->readTid(),
|
||||
cache_pkt->cacheReq->getInst()->seqNum,
|
||||
block_addr, cache_pkt->getAddr(), cache_pkt->getSize());
|
||||
|
||||
// Cast to correct request type
|
||||
CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
|
||||
findRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx));
|
||||
|
||||
if (!cache_req) {
|
||||
panic("[tid:%u]: [sn:%i]: Can't find slot for fetch access to "
|
||||
"addr. %08p\n", cache_pkt->cacheReq->getInst()->readTid(),
|
||||
cache_pkt->cacheReq->getInst()->seqNum,
|
||||
block_addr);
|
||||
}
|
||||
|
||||
// Get resource request info
|
||||
unsigned stage_num = cache_req->getStageNum();
|
||||
DynInstPtr inst = cache_req->inst;
|
||||
ThreadID tid = cache_req->inst->readTid();
|
||||
short asid = cpu->asid[tid];
|
||||
|
||||
assert(!cache_req->isSquashed());
|
||||
assert(inst->curSkedEntry->cmd == CompleteFetch);
|
||||
|
||||
DPRINTF(InOrderCachePort,
|
||||
"[tid:%u]: [sn:%i]: Processing fetch access for block %#x\n",
|
||||
tid, inst->seqNum, block_addr);
|
||||
|
||||
std::list<FetchBlock*>::iterator pend_it = findBlock(pendingFetch, asid,
|
||||
block_addr);
|
||||
assert(pend_it != pendingFetch.end());
|
||||
|
||||
// Copy Data to pendingFetch queue...
|
||||
(*pend_it)->block = new uint8_t[cacheBlkSize];
|
||||
memcpy((*pend_it)->block, cache_pkt->getPtr<uint8_t>(), cacheBlkSize);
|
||||
(*pend_it)->valid = true;
|
||||
|
||||
cache_req->setMemAccPending(false);
|
||||
cache_req->setMemAccCompleted();
|
||||
|
||||
if (cache_req->isMemStall() &&
|
||||
cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) {
|
||||
DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n",
|
||||
tid);
|
||||
|
||||
cpu->activateContext(tid);
|
||||
|
||||
DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache"
|
||||
"miss.\n", tid);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::squashCacheRequest(CacheReqPtr req_ptr)
|
||||
{
|
||||
DynInstPtr inst = req_ptr->getInst();
|
||||
ThreadID tid = inst->readTid();
|
||||
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
|
||||
int asid = cpu->asid[tid];
|
||||
|
||||
// Check Fetch Buffer (or pending fetch) for this block and
|
||||
// update pending counts
|
||||
std::list<FetchBlock*>::iterator buff_it = findBlock(fetchBuffer,
|
||||
asid,
|
||||
block_addr);
|
||||
if (buff_it != fetchBuffer.end()) {
|
||||
(*buff_it)->cnt--;
|
||||
DPRINTF(InOrderCachePort, "[sn:%i] Removing Pending Access "
|
||||
"for Fetch Buffer block %08p (cnt=%i)\n", inst->seqNum,
|
||||
block_addr, (*buff_it)->cnt);
|
||||
assert((*buff_it)->cnt >= 0);
|
||||
} else {
|
||||
std::list<FetchBlock*>::iterator block_it = findBlock(pendingFetch,
|
||||
asid,
|
||||
block_addr);
|
||||
if (block_it != pendingFetch.end()) {
|
||||
(*block_it)->cnt--;
|
||||
DPRINTF(InOrderCachePort, "[sn:%i] Removing Pending Access "
|
||||
"for Pending Buffer Block %08p (cnt=%i)\n",
|
||||
inst->seqNum,
|
||||
block_addr, (*block_it)->cnt);
|
||||
assert((*block_it)->cnt >= 0);
|
||||
if ((*block_it)->cnt == 0) {
|
||||
if ((*block_it)->block) {
|
||||
delete [] (*block_it)->block;
|
||||
}
|
||||
delete *block_it;
|
||||
pendingFetch.erase(block_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CacheUnit::squashCacheRequest(req_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
//@todo: per thread?
|
||||
decoder[tid]->reset();
|
||||
|
||||
//@todo: squash using dummy inst seq num
|
||||
squash(NULL, NumStages - 1, 0, tid);
|
||||
|
||||
//@todo: make sure no blocks are in use
|
||||
assert(blocksInUse() == 0);
|
||||
assert(pendingFetch.size() == 0);
|
||||
|
||||
//@todo: clear pendingFetch and fetchBuffer
|
||||
clearFetchBuffer();
|
||||
}
|
||||
138
simulators/gem5/src/cpu/inorder/resources/fetch_unit.hh
Normal file
138
simulators/gem5/src/cpu/inorder/resources/fetch_unit.hh
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 __CPU_INORDER_FETCH_UNIT_HH__
|
||||
#define __CPU_INORDER_FETCH_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/decoder.hh"
|
||||
#include "arch/tlb.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/cache_unit.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class FetchUnit : public CacheUnit
|
||||
{
|
||||
public:
|
||||
FetchUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
virtual ~FetchUnit();
|
||||
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef TheISA::ExtMachInst ExtMachInst;
|
||||
|
||||
struct FetchBlock {
|
||||
int asid;
|
||||
Addr addr;
|
||||
uint8_t *block;
|
||||
short cnt;
|
||||
bool valid;
|
||||
|
||||
FetchBlock(int _asid, Addr _addr)
|
||||
: asid(_asid), addr(_addr), block(NULL), cnt(1), valid(false)
|
||||
{ }
|
||||
};
|
||||
|
||||
/** Actions that this resource can take on an instruction */
|
||||
enum Command {
|
||||
InitiateFetch,
|
||||
CompleteFetch
|
||||
};
|
||||
|
||||
|
||||
ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num,
|
||||
unsigned cmd);
|
||||
|
||||
/** Executes one of the commands from the "Command" enum */
|
||||
void execute(int slot_num);
|
||||
|
||||
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
|
||||
|
||||
TheISA::Decoder *decoder[ThePipeline::MaxThreads];
|
||||
|
||||
private:
|
||||
void squashCacheRequest(CacheReqPtr req_ptr);
|
||||
|
||||
void createMachInst(std::list<FetchBlock*>::iterator fetch_it,
|
||||
DynInstPtr inst);
|
||||
|
||||
/** After memory request is completed, then turn the fetched data
|
||||
into an instruction.
|
||||
*/
|
||||
void processCacheCompletion(PacketPtr pkt);
|
||||
|
||||
/** Create request that will interface w/TLB and Memory objects */
|
||||
virtual void setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
|
||||
int acc_size, int flags);
|
||||
|
||||
/** Align a PC to the start of an I-cache block. */
|
||||
Addr cacheBlockAlignPC(Addr addr)
|
||||
{
|
||||
return (addr & ~(cacheBlkMask));
|
||||
}
|
||||
|
||||
void removeAddrDependency(DynInstPtr inst);
|
||||
|
||||
std::list<FetchBlock*>::iterator findReplacementBlock();
|
||||
std::list<FetchBlock*>::iterator findBlock(std::list<FetchBlock*>
|
||||
&fetch_blocks, int asid,
|
||||
Addr block_addr);
|
||||
|
||||
void markBlockUsed(std::list<FetchBlock*>::iterator block_it);
|
||||
|
||||
int blocksInUse();
|
||||
|
||||
void clearFetchBuffer();
|
||||
|
||||
int instSize;
|
||||
|
||||
int fetchBuffSize;
|
||||
|
||||
/** Valid Cache Blocks*/
|
||||
std::list<FetchBlock*> fetchBuffer;
|
||||
|
||||
/** Cache lines that are pending */
|
||||
std::list<FetchBlock*> pendingFetch;
|
||||
};
|
||||
|
||||
#endif //__CPU_FETCH_UNIT_HH__
|
||||
135
simulators/gem5/src/cpu/inorder/resources/graduation_unit.cc
Normal file
135
simulators/gem5/src/cpu/inorder/resources/graduation_unit.cc
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "debug/InOrderGraduation.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)
|
||||
{
|
||||
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
|
||||
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
|
||||
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
|
||||
lastNonSpecTick[tid] = 0;
|
||||
lastFaultTick[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GraduationUnit::execute(int slot_num)
|
||||
{
|
||||
ResourceRequest* grad_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = inst->curSkedEntry->stageNum;
|
||||
Tick cur_tick = curTick();
|
||||
|
||||
//@todo: not the common case, anyway we can move this
|
||||
// check to the stage and just ignore instructions
|
||||
// after?
|
||||
if (lastNonSpecTick[tid] == cur_tick) {
|
||||
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
|
||||
"Only 1 nonspec inst. per cycle can graduate.\n");
|
||||
grad_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//@todo: use trap Pending
|
||||
if (cpu->trapPending[tid]) {
|
||||
//if (lastFaultTick[tid] == cur_tick) {
|
||||
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
|
||||
"Only 1 fault can be handled per tick.\n");
|
||||
grad_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (grad_req->cmd)
|
||||
{
|
||||
case CheckFault:
|
||||
{
|
||||
// Handle Any Faults Before Graduating Instruction
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderGraduation, "[tid:%i]: [sn:%i]: fault %s found for %s\n",
|
||||
tid, inst->seqNum, inst->fault->name(),
|
||||
inst->instName());
|
||||
squashThenTrap(stage_num, inst);
|
||||
lastFaultTick[tid] = cur_tick;
|
||||
grad_req->done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF(InOrderGraduation, "[tid:%i] [sn:%i]: No fault found for %s\n",
|
||||
tid, inst->seqNum, inst->instName());
|
||||
grad_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
case GraduateInst:
|
||||
{
|
||||
DPRINTF(InOrderGraduation,
|
||||
"[tid:%i]:[sn:%i]: Graduating instruction %s.\n",
|
||||
tid, inst->seqNum, inst->staticInst->disassemble(inst->instAddr()));
|
||||
|
||||
// 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.
|
||||
// Maybe it should be, non-spec. insts should block other
|
||||
// non-spec insts because they can potentially be reading
|
||||
// system state that will be changed by the 1st non-spec inst.
|
||||
if (inst->isNonSpeculative()) {
|
||||
*nonSpecInstActive[tid] = false;
|
||||
DPRINTF(InOrderGraduation,
|
||||
"[tid:%i] Non-speculative inst [sn:%i] graduated\n",
|
||||
tid, inst->seqNum);
|
||||
lastNonSpecTick[tid] = cur_tick;
|
||||
}
|
||||
|
||||
if (inst->traceData) {
|
||||
inst->traceData->setStageCycle(stage_num, cur_tick);
|
||||
}
|
||||
|
||||
// Tell CPU that instruction is finished processing
|
||||
cpu->instDone(inst, tid);
|
||||
|
||||
grad_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
|
||||
}
|
||||
67
simulators/gem5/src/cpu/inorder/resources/graduation_unit.hh
Normal file
67
simulators/gem5/src/cpu/inorder/resources/graduation_unit.hh
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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_GRAD_UNIT_HH__
|
||||
#define __CPU_INORDER_GRAD_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class GraduationUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
enum Command {
|
||||
CheckFault,
|
||||
GraduateInst
|
||||
};
|
||||
|
||||
public:
|
||||
GraduationUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu,
|
||||
ThePipeline::Params *params);
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
protected:
|
||||
Tick lastNonSpecTick[ThePipeline::MaxThreads];
|
||||
Tick lastFaultTick[ThePipeline::MaxThreads];
|
||||
bool *nonSpecInstActive[ThePipeline::MaxThreads];
|
||||
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_GRAD_UNIT_HH__
|
||||
241
simulators/gem5/src/cpu/inorder/resources/inst_buffer.cc
Normal file
241
simulators/gem5/src/cpu/inorder/resources/inst_buffer.cc
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/inst_buffer.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "debug/InOrderInstBuffer.hh"
|
||||
#include "debug/Resource.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.")
|
||||
.prereq(instsBypassed);
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
InstBuffer::execute(int slot_idx)
|
||||
{
|
||||
ResReqPtr ib_req = reqs[slot_idx];
|
||||
DynInstPtr inst = ib_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = ib_req->getStageNum();
|
||||
|
||||
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 = 20;
|
||||
RSkedPtr insert_sked = (stage_num >= ThePipeline::BackEndStartStage) ?
|
||||
inst->backSked : inst->frontSked;
|
||||
|
||||
insert_sked->push(new ScheduleEntry(next_stage,
|
||||
stage_pri,
|
||||
id,
|
||||
InstBuffer::InsertInst));
|
||||
|
||||
// Add to schedule: Remove from buffer in next next (bypass)
|
||||
// stage
|
||||
stage_pri = 20;
|
||||
RSkedPtr bypass_sked = (stage_num >= ThePipeline::BackEndStartStage) ?
|
||||
inst->backSked : inst->frontSked;
|
||||
|
||||
bypass_sked->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, inst->seqNum);
|
||||
insert(inst);
|
||||
inserted = true;
|
||||
} else {
|
||||
DPRINTF(InOrderInstBuffer, "[tid:%i]: Denying [sn:%i] request "
|
||||
"because buffer is full.\n", tid, inst->seqNum);
|
||||
|
||||
|
||||
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, inst->seqNum);
|
||||
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(ThreadID tid)
|
||||
{
|
||||
instList.pop_front();
|
||||
}
|
||||
|
||||
ThePipeline::DynInstPtr
|
||||
InstBuffer::top(ThreadID tid)
|
||||
{
|
||||
return instList.front();
|
||||
}
|
||||
|
||||
void
|
||||
InstBuffer::squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID 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);
|
||||
}
|
||||
92
simulators/gem5/src/cpu/inorder/resources/inst_buffer.hh
Normal file
92
simulators/gem5/src/cpu/inorder/resources/inst_buffer.hh
Normal file
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
|
||||
#define __CPU_INORDER_INST_BUFF_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.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);
|
||||
|
||||
void regStats();
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
void insert(DynInstPtr inst);
|
||||
|
||||
void remove(DynInstPtr inst);
|
||||
|
||||
void pop(ThreadID tid);
|
||||
|
||||
DynInstPtr top(ThreadID tid);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID 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__
|
||||
66
simulators/gem5/src/cpu/inorder/resources/mem_dep_unit.hh
Normal file
66
simulators/gem5/src/cpu/inorder/resources/mem_dep_unit.hh
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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_MEM_DEP_UNIT_HH__
|
||||
#define __CPU_INORDER_MEM_DEP_UNIT_HH__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
|
||||
class MemDepUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
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];
|
||||
|
||||
/** @todo: Add Resource Stats Here */
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_GRAD_UNIT_HH__
|
||||
353
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.cc
Normal file
353
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.cc
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/resources/mult_div_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "cpu/op_class.hh"
|
||||
#include "debug/InOrderMDU.hh"
|
||||
#include "debug/Resource.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), lastOpType(No_OpClass)
|
||||
{ }
|
||||
|
||||
void
|
||||
MultDivUnit::regStats()
|
||||
{
|
||||
multiplies
|
||||
.name(name() + ".multiplies")
|
||||
.desc("Number of Multipy Operations Executed");
|
||||
|
||||
divides
|
||||
.name(name() + ".divides")
|
||||
.desc("Number of Divide Operations Executed");
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
MultDivUnit::init()
|
||||
{
|
||||
// Set Up Resource Events to Appropriate Resource BandWidth
|
||||
resourceEvent = new MDUEvent[width];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new ResourceRequest(this);
|
||||
}
|
||||
|
||||
initSlots();
|
||||
}
|
||||
|
||||
//@TODO: Should we push this behavior into base-class to generically
|
||||
// accomodate all multicyle resources?
|
||||
void
|
||||
MultDivUnit::requestAgain(DynInstPtr inst, bool &service_request)
|
||||
{
|
||||
ResReqPtr mult_div_req = findRequest(inst);
|
||||
assert(mult_div_req);
|
||||
|
||||
service_request = true;
|
||||
|
||||
// Check to see if this instruction is requesting the same command
|
||||
// or a different one
|
||||
if (mult_div_req->cmd != inst->curSkedEntry->cmd) {
|
||||
// If different, then update command in the request
|
||||
mult_div_req->cmd = inst->curSkedEntry->cmd;
|
||||
DPRINTF(InOrderMDU,
|
||||
"[tid:%i]: [sn:%i]: Updating the command for this "
|
||||
"instruction\n", inst->readTid(), inst->seqNum);
|
||||
} else {
|
||||
// If same command, just check to see if access was completed
|
||||
// but dont try to re-execute
|
||||
DPRINTF(InOrderMDU,
|
||||
"[tid:%i]: [sn:%i]: requesting this resource again\n",
|
||||
inst->readTid(), inst->seqNum);
|
||||
}
|
||||
}
|
||||
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->curSkedEntry->cmd == reqs[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 = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderMDU,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
mult_div_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF(InOrderMDU, "Executing [sn:%i] ...\n", slot_num);
|
||||
|
||||
switch (mult_div_req->cmd)
|
||||
{
|
||||
case StartMultDiv:
|
||||
{
|
||||
DPRINTF(InOrderMDU, "Start MDU called ...\n");
|
||||
|
||||
OpClass op_class = inst->opClass();
|
||||
if (op_class == IntMultOp) {
|
||||
scheduleEvent(slot_num, multLatency);
|
||||
} else if (op_class == 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;
|
||||
}
|
||||
|
||||
// Allow to pass through to next stage while
|
||||
// event processes
|
||||
mult_div_req->setProcessing();
|
||||
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->isProcessing()) {
|
||||
DPRINTF(InOrderMDU, "Mult/Div finished.\n");
|
||||
mult_div_req->done();
|
||||
} else {
|
||||
mult_div_req->setCompleted(false);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MultDivUnit::exeMulDiv(int slot_num)
|
||||
{
|
||||
ResourceRequest* mult_div_req = reqs[slot_num];
|
||||
DynInstPtr inst = reqs[slot_num]->inst;
|
||||
|
||||
inst->fault = inst->execute();
|
||||
|
||||
if (inst->opClass() == IntMultOp) {
|
||||
multiplies++;
|
||||
} else if (inst->opClass() == IntDivOp) {
|
||||
divides++;
|
||||
}
|
||||
|
||||
if (inst->fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: The result of execution is 0x%x.\n",
|
||||
inst->readTid(), inst->readIntResult(0));
|
||||
} else {
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: [sn:%i]: had a %s "
|
||||
"fault.\n", inst->readTid(), inst->seqNum, inst->fault->name());
|
||||
}
|
||||
|
||||
mult_div_req->setProcessing(false);
|
||||
cpu->wakeCPU();
|
||||
}
|
||||
|
||||
void
|
||||
MultDivUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
ResReqPtr req_ptr = reqs[i];
|
||||
DynInstPtr inst = req_ptr->getInst();
|
||||
|
||||
if (req_ptr->valid &&
|
||||
inst->readTid() == tid &&
|
||||
inst->seqNum > squash_seq_num) {
|
||||
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: Squashing [sn:%i].\n",
|
||||
req_ptr->getInst()->readTid(),
|
||||
req_ptr->getInst()->seqNum);
|
||||
|
||||
req_ptr->setSquashed();
|
||||
|
||||
int req_slot_num = req_ptr->getSlot();
|
||||
|
||||
if (req_ptr->isProcessing())
|
||||
DPRINTF(InOrderMDU, "[tid:%i]: Squashed [sn:%i], but "
|
||||
"waiting for MDU operation to complete.\n",
|
||||
req_ptr->getInst()->readTid(),
|
||||
req_ptr->getInst()->seqNum);
|
||||
else
|
||||
freeSlot(req_slot_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MDUEvent::MDUEvent()
|
||||
: ResourceEvent()
|
||||
{ }
|
||||
|
||||
void
|
||||
MDUEvent::process()
|
||||
{
|
||||
MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
|
||||
|
||||
mdu_res->exeMulDiv(slotIdx);
|
||||
|
||||
ResourceRequest* mult_div_req = resource->reqs[slotIdx];
|
||||
|
||||
if (mult_div_req->isSquashed())
|
||||
mdu_res->freeSlot(slotIdx);
|
||||
}
|
||||
|
||||
|
||||
139
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.hh
Normal file
139
simulators/gem5/src/cpu/inorder/resources/mult_div_unit.hh
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
#include "cpu/op_class.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);
|
||||
|
||||
public:
|
||||
/** Override default Resource getSlot(). Will only getSlot if
|
||||
* valid mult/div sequence is being maintained
|
||||
*/
|
||||
int getSlot(DynInstPtr inst);
|
||||
|
||||
void init();
|
||||
|
||||
/** Get Operand Size For A Division Operation */
|
||||
int getDivOpSize(DynInstPtr inst);
|
||||
|
||||
/** Override default Resource execute */
|
||||
void execute(int slot_num);
|
||||
|
||||
void exeMulDiv(int slot_num);
|
||||
|
||||
/** Register extra resource stats */
|
||||
void regStats();
|
||||
|
||||
void requestAgain(DynInstPtr inst, bool &try_request);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid);
|
||||
|
||||
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 Multiplies */
|
||||
Stats::Scalar multiplies;
|
||||
|
||||
/** Number of Divides */
|
||||
Stats::Scalar divides;
|
||||
|
||||
MDUEvent *mduEvent;
|
||||
};
|
||||
|
||||
class MDUEvent : public ResourceEvent
|
||||
{
|
||||
public:
|
||||
MDUEvent();
|
||||
~MDUEvent() { }
|
||||
|
||||
|
||||
void process();
|
||||
};
|
||||
|
||||
|
||||
#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__
|
||||
48
simulators/gem5/src/cpu/inorder/resources/resource_list.hh
Normal file
48
simulators/gem5/src/cpu/inorder/resources/resource_list.hh
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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_LIST_HH
|
||||
#define CPU_INORDER_RESOURCE_LIST_HH
|
||||
|
||||
#include "cpu/inorder/resources/agen_unit.hh"
|
||||
#include "cpu/inorder/resources/branch_predictor.hh"
|
||||
#include "cpu/inorder/resources/cache_unit.hh"
|
||||
#include "cpu/inorder/resources/decode_unit.hh"
|
||||
#include "cpu/inorder/resources/execution_unit.hh"
|
||||
#include "cpu/inorder/resources/fetch_seq_unit.hh"
|
||||
#include "cpu/inorder/resources/fetch_unit.hh"
|
||||
#include "cpu/inorder/resources/graduation_unit.hh"
|
||||
#include "cpu/inorder/resources/inst_buffer.hh"
|
||||
#include "cpu/inorder/resources/mult_div_unit.hh"
|
||||
#include "cpu/inorder/resources/tlb_unit.hh"
|
||||
#include "cpu/inorder/resources/use_def.hh"
|
||||
|
||||
#endif
|
||||
258
simulators/gem5/src/cpu/inorder/resources/tlb_unit.cc
Normal file
258
simulators/gem5/src/cpu/inorder/resources/tlb_unit.cc
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/tlb_unit.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/pipeline_traits.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)
|
||||
: Resource(res_name, res_id, res_width, res_latency, _cpu)
|
||||
{
|
||||
// Hard-Code Selection For Now
|
||||
if (res_name == "I-TLB")
|
||||
_tlb = params->itb;
|
||||
else if (res_name == "D-TLB")
|
||||
_tlb = params->dtb;
|
||||
else
|
||||
fatal("Unrecognized TLB name passed by user");
|
||||
|
||||
for (int i=0; i < MaxThreads; i++) {
|
||||
tlbBlocked[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
TheISA::TLB*
|
||||
TLBUnit::tlb()
|
||||
{
|
||||
return _tlb;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TLBUnit::init()
|
||||
{
|
||||
resourceEvent = new TLBUnitEvent[width];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new TLBUnitRequest(this);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TLBUnitRequest *tlb_req = dynamic_cast<TLBUnitRequest*>(reqs[slot_num]);
|
||||
tlb_req->setRequest(inst, stage_num, id, slot_num, cmd);
|
||||
return ud_req;
|
||||
}
|
||||
|
||||
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*>(reqs[slot_idx]);
|
||||
assert(tlb_req != 0x0);
|
||||
|
||||
DynInstPtr inst = tlb_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
int stage_num = tlb_req->getStageNum();
|
||||
|
||||
tlb_req->fault = NoFault;
|
||||
|
||||
assert(cpu->thread[tid]->getTC() != 0x0);
|
||||
assert(cpu->pipelineStage[stage_num] != 0x0);
|
||||
|
||||
switch (tlb_req->cmd)
|
||||
{
|
||||
case FetchLookup:
|
||||
{
|
||||
tlb_req->fault =
|
||||
_tlb->translateAtomic(tlb_req->memReq,
|
||||
cpu->thread[tid]->getTC(), TheISA::TLB::Execute);
|
||||
|
||||
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);
|
||||
|
||||
DPRINTF(InOrderTLB, "slot:%i sn:%i schedule event.\n", slot_idx, seq_num);
|
||||
|
||||
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 DataReadLookup:
|
||||
case DataWriteLookup:
|
||||
{
|
||||
DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
|
||||
tid, seq_num, tlb_req->memReq->getVaddr());
|
||||
|
||||
|
||||
TheISA::TLB::Mode tlb_mode = (tlb_req->cmd == DataReadLookup) ?
|
||||
TheISA::TLB::Read : TheISA::TLB::Write;
|
||||
|
||||
tlb_req->fault =
|
||||
_tlb->translateAtomic(tlb_req->memReq,
|
||||
cpu->thread[tid]->getTC(), tlb_mode);
|
||||
|
||||
if (tlb_req->fault != NoFault) {
|
||||
DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
|
||||
"addr:%08p for [sn:%i] %s.\n", tid, tlb_req->fault->name(),
|
||||
tlb_req->memReq->getVaddr(), seq_num, inst->instName());
|
||||
|
||||
if (inst->isDataPrefetch()) {
|
||||
DPRINTF(InOrderTLB, "Ignoring %s fault for data prefetch\n",
|
||||
tlb_req->fault->name());
|
||||
|
||||
tlb_req->fault = NoFault;
|
||||
|
||||
tlb_req->done();
|
||||
} else {
|
||||
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, inst);
|
||||
}
|
||||
} 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->reqs[slotIdx]->inst;
|
||||
int stage_num = resource->reqs[slotIdx]->getStageNum();
|
||||
ThreadID 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(tlb_res->reqs[slotIdx], tid);
|
||||
}
|
||||
|
||||
void
|
||||
TLBUnit::squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
ResReqPtr req_ptr = reqs[i];
|
||||
|
||||
if (req_ptr->valid &&
|
||||
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);
|
||||
|
||||
req_ptr->setSquashed();
|
||||
|
||||
int req_slot_num = req_ptr->getSlot();
|
||||
|
||||
tlbBlocked[tid] = false;
|
||||
|
||||
int stall_stage = reqs[req_slot_num]->getStageNum();
|
||||
|
||||
cpu->pipelineStage[stall_stage]->
|
||||
unsetResStall(reqs[req_slot_num], tid);
|
||||
|
||||
if (resourceEvent[req_slot_num].scheduled())
|
||||
unscheduleEvent(req_slot_num);
|
||||
|
||||
freeSlot(req_slot_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
151
simulators/gem5/src/cpu/inorder/resources/tlb_unit.hh
Normal file
151
simulators/gem5/src/cpu/inorder/resources/tlb_unit.hh
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/inst_buffer.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
|
||||
class TLBUnit : public Resource
|
||||
{
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
enum TLBCommand {
|
||||
FetchLookup,
|
||||
DataReadLookup,
|
||||
DataWriteLookup
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid);
|
||||
|
||||
bool tlbBlocked[ThePipeline::MaxThreads];
|
||||
|
||||
TheISA::TLB* tlb();
|
||||
|
||||
protected:
|
||||
/** List of instructions this resource is currently
|
||||
* processing.
|
||||
*/
|
||||
std::list<DynInstPtr> instList;
|
||||
|
||||
TheISA::TLB *_tlb;
|
||||
};
|
||||
|
||||
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)
|
||||
: ResourceRequest(res), memReq(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
RequestPtr memReq;
|
||||
|
||||
void setRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num,
|
||||
unsigned _cmd)
|
||||
{
|
||||
Addr aligned_addr;
|
||||
int req_size;
|
||||
unsigned flags;
|
||||
|
||||
if (_cmd == TLBUnit::FetchLookup) {
|
||||
aligned_addr = inst->getMemAddr();
|
||||
req_size = sizeof(TheISA::MachInst);
|
||||
flags = 0;
|
||||
inst->fetchMemReq = new Request(inst->readTid(), aligned_addr,
|
||||
req_size, flags,
|
||||
res->cpu->instMasterId(),
|
||||
inst->instAddr(),
|
||||
res->cpu->readCpuId(),
|
||||
inst->readTid());
|
||||
memReq = inst->fetchMemReq;
|
||||
} else {
|
||||
aligned_addr = inst->getMemAddr();;
|
||||
req_size = 0; //inst->getMemAccSize();
|
||||
flags = 0; //inst->getMemFlags();
|
||||
|
||||
if (req_size == 0 && (inst->isDataPrefetch() || inst->isInstPrefetch())) {
|
||||
req_size = 8;
|
||||
}
|
||||
|
||||
inst->dataMemReq = new Request(inst->readTid(), aligned_addr,
|
||||
req_size, flags,
|
||||
res->cpu->dataMasterId(),
|
||||
inst->instAddr(),
|
||||
res->cpu->readCpuId(),
|
||||
inst->readTid());
|
||||
memReq = inst->dataMemReq;
|
||||
}
|
||||
|
||||
ResourceRequest::setRequest(inst, stage_num, res_idx, slot_num, _cmd);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //__CPU_INORDER_TLB_UNIT_HH__
|
||||
509
simulators/gem5/src/cpu/inorder/resources/use_def.cc
Normal file
509
simulators/gem5/src/cpu/inorder/resources/use_def.cc
Normal file
@ -0,0 +1,509 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/inorder/resources/use_def.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "debug/InOrderStall.hh"
|
||||
#include "debug/InOrderUseDef.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)
|
||||
{
|
||||
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
|
||||
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
|
||||
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
|
||||
serializeOnNextInst[tid] = false;
|
||||
serializeAfterSeqNum[tid] = 0;
|
||||
regDepMap[tid] = &cpu->archRegDepMap[tid];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::regStats()
|
||||
{
|
||||
uniqueRegsPerSwitch
|
||||
.name(name() + ".uniqueRegsPerSwitch")
|
||||
.desc("Number of Unique Registers Needed Per Context Switch")
|
||||
.prereq(uniqueRegsPerSwitch);
|
||||
|
||||
intRegFileReads
|
||||
.name(name() + ".intRegFileReads")
|
||||
.desc("Number of Reads from Int. Register File");
|
||||
|
||||
intRegFileWrites
|
||||
.name(name() + ".intRegFileWrites")
|
||||
.desc("Number of Writes to Int. Register File");
|
||||
|
||||
intRegFileAccs
|
||||
.name(name() + ".intRegFileAccesses")
|
||||
.desc("Total Accesses (Read+Write) to the Int. Register File");
|
||||
intRegFileAccs = intRegFileReads + intRegFileWrites;
|
||||
|
||||
floatRegFileReads
|
||||
.name(name() + ".floatRegFileReads")
|
||||
.desc("Number of Reads from FP Register File");
|
||||
|
||||
floatRegFileWrites
|
||||
.name(name() + ".floatRegFileWrites")
|
||||
.desc("Number of Writes to FP Register File");
|
||||
|
||||
floatRegFileAccs
|
||||
.name(name() + ".floatRegFileAccesses")
|
||||
.desc("Total Accesses (Read+Write) to the FP Register File");
|
||||
floatRegFileAccs = floatRegFileReads + floatRegFileWrites;
|
||||
|
||||
//@todo: add miscreg reads/writes
|
||||
// add forwarding by type???
|
||||
|
||||
regForwards
|
||||
.name(name() + ".regForwards")
|
||||
.desc("Number of Registers Read Through Forwarding Logic");
|
||||
|
||||
Resource::regStats();
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::init()
|
||||
{
|
||||
// Set Up Resource Events to Appropriate Resource BandWidth
|
||||
if (latency > 0) {
|
||||
resourceEvent = new ResourceEvent[width];
|
||||
} else {
|
||||
resourceEvent = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
reqs[i] = new UseDefRequest(this);
|
||||
}
|
||||
|
||||
initSlots();
|
||||
}
|
||||
|
||||
ResReqPtr
|
||||
UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
|
||||
int slot_num, unsigned cmd)
|
||||
{
|
||||
UseDefRequest *ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_num]);
|
||||
ud_req->setRequest(inst, stage_num, id, slot_num, cmd,
|
||||
inst->curSkedEntry->idx);
|
||||
return ud_req;
|
||||
}
|
||||
|
||||
|
||||
ResReqPtr
|
||||
UseDefUnit::findRequest(DynInstPtr inst)
|
||||
{
|
||||
for (int i = 0; i < width; i++) {
|
||||
UseDefRequest* ud_req =
|
||||
dynamic_cast<UseDefRequest*>(reqs[i]);
|
||||
assert(ud_req);
|
||||
|
||||
if (ud_req->valid &&
|
||||
ud_req->getInst() == inst &&
|
||||
ud_req->cmd == inst->curSkedEntry->cmd &&
|
||||
ud_req->useDefIdx == inst->curSkedEntry->idx) {
|
||||
return ud_req;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::execute(int slot_idx)
|
||||
{
|
||||
UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_idx]);
|
||||
DynInstPtr inst = ud_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
int ud_idx = ud_req->useDefIdx;
|
||||
|
||||
if (serializeOnNextInst[tid] &&
|
||||
seq_num > serializeAfterSeqNum[tid]) {
|
||||
inst->setSerializeBefore();
|
||||
serializeOnNextInst[tid] = false;
|
||||
}
|
||||
|
||||
if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
|
||||
cpu->instList[tid].front() != inst) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] Serialize before instruction encountered."
|
||||
" Blocking until pipeline is clear.\n", tid, seq_num);
|
||||
ud_req->done(false);
|
||||
return;
|
||||
} else if (inst->isStoreConditional() || inst->isSerializeAfter()) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] Serialize after instruction encountered."
|
||||
" Blocking until pipeline is clear.\n", tid, seq_num);
|
||||
serializeOnNextInst[tid] = true;
|
||||
serializeAfterSeqNum[tid] = seq_num;
|
||||
}
|
||||
|
||||
if (inst->fault != NoFault) {
|
||||
DPRINTF(InOrderUseDef,
|
||||
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
|
||||
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
|
||||
inst->pcState());
|
||||
ud_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
ud_req->done(false);
|
||||
return;
|
||||
} else if (inst->isNonSpeculative()) {
|
||||
*nonSpecInstActive[tid] = true;
|
||||
*nonSpecSeqNum[tid] = seq_num;
|
||||
}
|
||||
|
||||
switch (ud_req->cmd)
|
||||
{
|
||||
case ReadSrcReg:
|
||||
{
|
||||
InOrderCPU::RegType reg_type;
|
||||
RegIndex reg_idx = inst->_srcRegIdx[ud_idx];
|
||||
RegIndex flat_idx = cpu->flattenRegIdx(reg_idx, reg_type, tid);
|
||||
inst->flattenSrcReg(ud_idx, flat_idx);
|
||||
|
||||
if (flat_idx == TheISA::ZeroReg && reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Ignoring Reading of ISA-ZeroReg "
|
||||
"(Int. Reg %i).\n", tid, inst->seqNum, flat_idx);
|
||||
ud_req->done();
|
||||
return;
|
||||
} else {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Attempting to read source "
|
||||
"register idx %i (reg #%i, flat#%i).\n",
|
||||
tid, seq_num, ud_idx, reg_idx, flat_idx);
|
||||
}
|
||||
|
||||
if (regDepMap[tid]->canRead(reg_type, flat_idx, inst)) {
|
||||
switch (reg_type)
|
||||
{
|
||||
case InOrderCPU::IntType:
|
||||
{
|
||||
uniqueIntRegMap[flat_idx] = true;
|
||||
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Int Reg %i"
|
||||
" (%i) from Register File:0x%x.\n",
|
||||
tid, seq_num,
|
||||
reg_idx, flat_idx,
|
||||
cpu->readIntReg(flat_idx,inst->readTid()));
|
||||
inst->setIntSrc(ud_idx,
|
||||
cpu->readIntReg(flat_idx,
|
||||
inst->readTid()));
|
||||
intRegFileReads++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::FloatType:
|
||||
{
|
||||
uniqueFloatRegMap[flat_idx] = true;
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Float Reg %i"
|
||||
" (%i) from Register File:%x (%08f).\n",
|
||||
tid, seq_num,
|
||||
reg_idx - FP_Base_DepTag, flat_idx,
|
||||
cpu->readFloatRegBits(flat_idx,
|
||||
inst->readTid()),
|
||||
cpu->readFloatReg(flat_idx,
|
||||
inst->readTid()));
|
||||
|
||||
inst->setFloatSrc(ud_idx,
|
||||
cpu->readFloatReg(flat_idx,
|
||||
inst->readTid()));
|
||||
inst->setFloatRegBitsSrc(ud_idx,
|
||||
cpu->readFloatRegBits(flat_idx,
|
||||
inst->readTid()));
|
||||
floatRegFileReads++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::MiscType:
|
||||
{
|
||||
uniqueMiscRegMap[flat_idx] = true;
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Misc Reg %i "
|
||||
" (%i) from Register File:0x%x.\n",
|
||||
tid, seq_num,
|
||||
reg_idx - Ctrl_Base_DepTag, flat_idx,
|
||||
cpu->readMiscReg(flat_idx,
|
||||
inst->readTid()));
|
||||
inst->setIntSrc(ud_idx,
|
||||
cpu->readMiscReg(flat_idx,
|
||||
inst->readTid()));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Invalid Register Type: %i", reg_type);
|
||||
}
|
||||
|
||||
ud_req->done();
|
||||
} else {
|
||||
// Look for forwarding opportunities
|
||||
DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_type,
|
||||
flat_idx,
|
||||
inst);
|
||||
|
||||
if (forward_inst) {
|
||||
int dest_reg_idx =
|
||||
forward_inst->getDestIdxNum(flat_idx);
|
||||
|
||||
switch (reg_type)
|
||||
{
|
||||
case InOrderCPU::IntType:
|
||||
{
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
|
||||
" reg %i (%i), value 0x%x from "
|
||||
"[sn:%i] to [sn:%i] source #%x.\n",
|
||||
tid, reg_idx, flat_idx,
|
||||
forward_inst->readIntResult(dest_reg_idx),
|
||||
forward_inst->seqNum,
|
||||
inst->seqNum, ud_idx);
|
||||
inst->setIntSrc(ud_idx,
|
||||
forward_inst->
|
||||
readIntResult(dest_reg_idx));
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::FloatType:
|
||||
{
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
|
||||
" reg %i (%i) value 0x%x from "
|
||||
"[sn:%i] to [sn:%i] source #%i.\n",
|
||||
tid, reg_idx - FP_Base_DepTag, flat_idx,
|
||||
forward_inst->readFloatResult(dest_reg_idx),
|
||||
forward_inst->seqNum, inst->seqNum, ud_idx);
|
||||
inst->setFloatSrc(ud_idx,
|
||||
forward_inst->
|
||||
readFloatResult(dest_reg_idx));
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::MiscType:
|
||||
{
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
|
||||
" reg %i (%i) value 0x%x from "
|
||||
"[sn:%i] to [sn:%i] source #%i.\n",
|
||||
tid, reg_idx - Ctrl_Base_DepTag, flat_idx,
|
||||
forward_inst->readIntResult(dest_reg_idx),
|
||||
forward_inst->seqNum,
|
||||
inst->seqNum, ud_idx);
|
||||
inst->setIntSrc(ud_idx,
|
||||
forward_inst->
|
||||
readIntResult(dest_reg_idx));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Invalid Register Type: %i", reg_type);
|
||||
}
|
||||
|
||||
regForwards++;
|
||||
ud_req->done();
|
||||
} 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);
|
||||
ud_req->done(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WriteDestReg:
|
||||
{
|
||||
InOrderCPU::RegType reg_type;
|
||||
RegIndex reg_idx = inst->_destRegIdx[ud_idx];
|
||||
RegIndex flat_idx = cpu->flattenRegIdx(reg_idx, reg_type, tid);
|
||||
|
||||
if (flat_idx == TheISA::ZeroReg && reg_type == InOrderCPU::IntType) {
|
||||
DPRINTF(IntRegs, "[tid:%i]: Ignoring Writing of ISA-ZeroReg "
|
||||
"(Int. Reg %i)\n", tid, flat_idx);
|
||||
ud_req->done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (regDepMap[tid]->canWrite(reg_type, flat_idx, inst)) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Flattening register idx %i "
|
||||
"(%i) and Attempting to write to Register File.\n",
|
||||
tid, seq_num, reg_idx, flat_idx);
|
||||
|
||||
switch (reg_type)
|
||||
{
|
||||
case InOrderCPU::IntType:
|
||||
{
|
||||
uniqueIntRegMap[flat_idx] = true;
|
||||
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Int. Result "
|
||||
"0x%x to register idx %i (%i).\n",
|
||||
tid, seq_num, inst->readIntResult(ud_idx),
|
||||
reg_idx, flat_idx);
|
||||
|
||||
// Remove Dependencies
|
||||
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
|
||||
|
||||
cpu->setIntReg(flat_idx,
|
||||
inst->readIntResult(ud_idx),
|
||||
inst->readTid());
|
||||
intRegFileWrites++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::FloatType:
|
||||
{
|
||||
uniqueFloatRegMap[flat_idx] = true;
|
||||
|
||||
// Remove Reg. Dependecny Block on this Register
|
||||
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
|
||||
|
||||
if (inst->resultType(ud_idx) ==
|
||||
InOrderDynInst::FloatBits) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing FP-Bits "
|
||||
"Result %08f (bits:0x%x) to register "
|
||||
"idx %i (%i).\n",
|
||||
tid, seq_num,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readFloatBitsResult(ud_idx),
|
||||
reg_idx - FP_Base_DepTag, flat_idx);
|
||||
|
||||
// Check for FloatRegBits Here
|
||||
cpu->setFloatRegBits(flat_idx,
|
||||
inst->readFloatBitsResult(ud_idx),
|
||||
inst->readTid());
|
||||
} else if (inst->resultType(ud_idx) ==
|
||||
InOrderDynInst::Float) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Float "
|
||||
"Result %08f (bits:0x%x) to register "
|
||||
"idx %i (%i).\n",
|
||||
tid, seq_num, inst->readFloatResult(ud_idx),
|
||||
inst->readIntResult(ud_idx),
|
||||
reg_idx - FP_Base_DepTag, flat_idx);
|
||||
|
||||
cpu->setFloatReg(flat_idx,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readTid());
|
||||
} else if (inst->resultType(ud_idx) ==
|
||||
InOrderDynInst::Double) {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Double "
|
||||
"Result %08f (bits:0x%x) to register "
|
||||
"idx %i (%i).\n",
|
||||
tid, seq_num,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readIntResult(ud_idx),
|
||||
reg_idx - FP_Base_DepTag, flat_idx);
|
||||
|
||||
cpu->setFloatReg(flat_idx,
|
||||
inst->readFloatResult(ud_idx),
|
||||
inst->readTid());
|
||||
} else {
|
||||
panic("Result Type Not Set For [sn:%i] %s.\n",
|
||||
inst->seqNum, inst->instName());
|
||||
}
|
||||
|
||||
floatRegFileWrites++;
|
||||
}
|
||||
break;
|
||||
|
||||
case InOrderCPU::MiscType:
|
||||
{
|
||||
uniqueMiscRegMap[flat_idx] = true;
|
||||
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: Writing Misc. 0x%x "
|
||||
"to register idx %i.\n",
|
||||
tid, inst->readIntResult(ud_idx), reg_idx - Ctrl_Base_DepTag);
|
||||
|
||||
// Remove Dependencies
|
||||
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
|
||||
|
||||
cpu->setMiscReg(flat_idx,
|
||||
inst->readIntResult(ud_idx),
|
||||
inst->readTid());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Invalid Register Type: %i", reg_type);
|
||||
}
|
||||
|
||||
ud_req->done();
|
||||
} else {
|
||||
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Dest. register idx: %i is "
|
||||
"not ready to write.\n",
|
||||
tid, seq_num, reg_idx);
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write "
|
||||
"register (idx=%i)\n",
|
||||
tid, reg_idx);
|
||||
ud_req->done(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MarkDestRegs:
|
||||
{
|
||||
regDepMap[tid]->insert(inst);
|
||||
ud_req->done();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized command to %s", resName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
UseDefUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
|
||||
{
|
||||
uniqueRegsPerSwitch = uniqueIntRegMap.size() + uniqueFloatRegMap.size()
|
||||
+ uniqueMiscRegMap.size();
|
||||
uniqueIntRegMap.clear();
|
||||
uniqueFloatRegMap.clear();
|
||||
uniqueMiscRegMap.clear();
|
||||
}
|
||||
134
simulators/gem5/src/cpu/inorder/resources/use_def.hh
Normal file
134
simulators/gem5/src/cpu/inorder/resources/use_def.hh
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/inorder/first_stage.hh"
|
||||
#include "cpu/inorder/inorder_dyn_inst.hh"
|
||||
#include "cpu/inorder/pipeline_traits.hh"
|
||||
#include "cpu/inorder/reg_dep_map.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/func_unit.hh"
|
||||
|
||||
class UseDefUnit : public Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
typedef TheISA::RegIndex RegIndex;
|
||||
|
||||
enum Command {
|
||||
ReadSrcReg,
|
||||
WriteDestReg,
|
||||
MarkDestRegs
|
||||
};
|
||||
|
||||
public:
|
||||
UseDefUnit(std::string res_name, int res_id, int res_width,
|
||||
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
|
||||
|
||||
void init();
|
||||
|
||||
ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num,
|
||||
unsigned cmd);
|
||||
|
||||
ResReqPtr findRequest(DynInstPtr inst);
|
||||
|
||||
void execute(int slot_num);
|
||||
|
||||
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
void regStats();
|
||||
|
||||
protected:
|
||||
RegDepMap *regDepMap[ThePipeline::MaxThreads];
|
||||
|
||||
bool *nonSpecInstActive[ThePipeline::MaxThreads];
|
||||
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
bool serializeOnNextInst[ThePipeline::MaxThreads];
|
||||
InstSeqNum serializeAfterSeqNum[ThePipeline::MaxThreads];
|
||||
|
||||
Stats::Average uniqueRegsPerSwitch;
|
||||
std::map<RegIndex, bool> uniqueIntRegMap;
|
||||
std::map<RegIndex, bool> uniqueFloatRegMap;
|
||||
std::map<RegIndex, bool> uniqueMiscRegMap;
|
||||
|
||||
public:
|
||||
class UseDefRequest : public ResourceRequest {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
UseDefRequest(UseDefUnit *res)
|
||||
: ResourceRequest(res)
|
||||
{ }
|
||||
|
||||
int useDefIdx;
|
||||
|
||||
void setRequest(DynInstPtr _inst, int stage_num, int res_idx,
|
||||
int slot_num, unsigned _cmd, int idx)
|
||||
{
|
||||
useDefIdx = idx;
|
||||
|
||||
ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num,
|
||||
_cmd);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
/** Int. Register File Reads */
|
||||
Stats::Scalar intRegFileReads;
|
||||
|
||||
/** Int. Register File Writes */
|
||||
Stats::Scalar intRegFileWrites;
|
||||
|
||||
/** Int. Register File Total Accesses (Read+Write) */
|
||||
Stats::Formula intRegFileAccs;
|
||||
|
||||
/** Float Register File Reads */
|
||||
Stats::Scalar floatRegFileReads;
|
||||
|
||||
/** Float Register File Writes */
|
||||
Stats::Scalar floatRegFileWrites;
|
||||
|
||||
/** Float Register File Total Accesses (Read+Write) */
|
||||
Stats::Formula floatRegFileAccs;
|
||||
|
||||
/** Source Register Forwarding */
|
||||
Stats::Scalar regForwards;
|
||||
};
|
||||
|
||||
#endif //__CPU_INORDER_USE_DEF_UNIT_HH__
|
||||
251
simulators/gem5/src/cpu/inorder/thread_context.cc
Normal file
251
simulators/gem5/src/cpu/inorder/thread_context.cc
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/thread_context.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/InOrderCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
using namespace TheISA;
|
||||
|
||||
FSTranslatingPortProxy&
|
||||
InOrderThreadContext::getVirtProxy()
|
||||
{
|
||||
return thread->getVirtProxy();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::dumpFuncProfile()
|
||||
{
|
||||
thread->dumpFuncProfile();
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
InOrderThreadContext::readLastActivate()
|
||||
{
|
||||
return thread->lastActivate;
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
InOrderThreadContext::readLastSuspend()
|
||||
{
|
||||
return thread->lastSuspend;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::profileClear()
|
||||
{
|
||||
thread->profileClear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::profileSample()
|
||||
{
|
||||
thread->profileSample();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
|
||||
{
|
||||
// some things should already be set up
|
||||
assert(getSystemPtr() == old_context->getSystemPtr());
|
||||
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::Halted);
|
||||
|
||||
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->threadId(), 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->threadId());
|
||||
}
|
||||
|
||||
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->threadId());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::regStats(const std::string &name)
|
||||
{
|
||||
if (FullSystem) {
|
||||
thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system);
|
||||
thread->kernelStats->regStats(name + ".kern");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::serialize(std::ostream &os)
|
||||
{
|
||||
panic("serialize unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
panic("unserialize unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::copyArchRegs(ThreadContext *src_tc)
|
||||
{
|
||||
TheISA::copyRegs(src_tc, this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InOrderThreadContext::clearArchRegs()
|
||||
{
|
||||
cpu->isa[thread->threadId()].clear();
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
InOrderThreadContext::readIntReg(int reg_idx)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenIntIndex(reg_idx);
|
||||
return cpu->readIntReg(reg_idx, tid);
|
||||
}
|
||||
|
||||
FloatReg
|
||||
InOrderThreadContext::readFloatReg(int reg_idx)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
return cpu->readFloatReg(reg_idx, tid);
|
||||
}
|
||||
|
||||
FloatRegBits
|
||||
InOrderThreadContext::readFloatRegBits(int reg_idx)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
return cpu->readFloatRegBits(reg_idx, tid);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
InOrderThreadContext::readRegOtherThread(int reg_idx, ThreadID tid)
|
||||
{
|
||||
return cpu->readRegOtherThread(reg_idx, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setIntReg(int reg_idx, uint64_t val)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenIntIndex(reg_idx);
|
||||
cpu->setIntReg(reg_idx, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
cpu->setFloatReg(reg_idx, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val)
|
||||
{
|
||||
ThreadID tid = thread->threadId();
|
||||
reg_idx = cpu->isa[tid].flattenFloatIndex(reg_idx);
|
||||
cpu->setFloatRegBits(reg_idx, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val,
|
||||
ThreadID tid)
|
||||
{
|
||||
cpu->setRegOtherThread(misc_reg, val, tid);
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId());
|
||||
}
|
||||
|
||||
void
|
||||
InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
cpu->setMiscReg(misc_reg, val, thread->threadId());
|
||||
}
|
||||
297
simulators/gem5/src/cpu/inorder/thread_context.hh
Normal file
297
simulators/gem5/src/cpu/inorder/thread_context.hh
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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 "config/the_isa.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/thread_state.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "arch/kernel_stats.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
class CheckerCPU;
|
||||
namespace Kernel {
|
||||
class Statistics;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
/** @TODO: PERF: Should we bind this to a pointer in constructor? */
|
||||
TheISA::TLB *getITBPtr() { return cpu->getITBPtr(); }
|
||||
|
||||
/** Returns a pointer to the DTB. */
|
||||
/** @TODO: PERF: Should we bind this to a pointer in constructor? */
|
||||
TheISA::TLB *getDTBPtr() { return cpu->getDTBPtr(); }
|
||||
|
||||
/** Currently InOrder model does not support CheckerCPU, this is
|
||||
* merely here for supporting compilation of gem5 with the Checker
|
||||
* as a runtime option
|
||||
*/
|
||||
CheckerCPU *getCheckerCpuPtr() { return NULL; }
|
||||
|
||||
TheISA::Decoder *
|
||||
getDecoderPtr()
|
||||
{
|
||||
return cpu->getDecoderPtr(thread->contextId());
|
||||
}
|
||||
|
||||
System *getSystemPtr() { return cpu->system; }
|
||||
|
||||
/** Returns a pointer to this CPU. */
|
||||
BaseCPU *getCpuPtr() { return cpu; }
|
||||
|
||||
/** Returns a pointer to this CPU. */
|
||||
std::string getCpuName() { return cpu->name(); }
|
||||
|
||||
/** Reads this CPU's ID. */
|
||||
int cpuId() { return cpu->cpuId(); }
|
||||
|
||||
int contextId() { return thread->contextId(); }
|
||||
|
||||
void setContextId(int id) { thread->setContextId(id); }
|
||||
|
||||
/** Returns this thread's ID number. */
|
||||
int threadId() { return thread->threadId(); }
|
||||
void setThreadId(int id) { return thread->setThreadId(id); }
|
||||
|
||||
uint64_t readMicroPC()
|
||||
{ return 0; }
|
||||
|
||||
void setMicroPC(uint64_t val) { };
|
||||
|
||||
uint64_t readNextMicroPC()
|
||||
{ return 0; }
|
||||
|
||||
void setNextMicroPC(uint64_t val) { };
|
||||
|
||||
/** Returns a pointer to this thread's kernel statistics. */
|
||||
TheISA::Kernel::Statistics *getKernelStats()
|
||||
{ return thread->kernelStats; }
|
||||
|
||||
PortProxy &getPhysProxy() { return thread->getPhysProxy(); }
|
||||
|
||||
FSTranslatingPortProxy &getVirtProxy();
|
||||
|
||||
void initMemProxies(ThreadContext *tc)
|
||||
{ thread->initMemProxies(tc); }
|
||||
|
||||
/** Dumps the function profiling information.
|
||||
* @todo: Implement.
|
||||
*/
|
||||
void dumpFuncProfile();
|
||||
|
||||
/** Reads the last tick that this thread was activated on. */
|
||||
Tick readLastActivate();
|
||||
/** Reads the last tick that this thread was suspended on. */
|
||||
Tick readLastSuspend();
|
||||
|
||||
/** Clears the function profiling information. */
|
||||
void profileClear();
|
||||
|
||||
/** Samples the function profiling information. */
|
||||
void profileSample();
|
||||
|
||||
/** Returns pointer to the quiesce event. */
|
||||
EndQuiesceEvent *getQuiesceEvent()
|
||||
{
|
||||
return this->thread->quiesceEvent;
|
||||
}
|
||||
|
||||
SETranslatingPortProxy &getMemProxy() { return thread->getMemProxy(); }
|
||||
|
||||
/** Returns a pointer to this thread's process. */
|
||||
Process *getProcessPtr() { return thread->getProcessPtr(); }
|
||||
|
||||
/** Returns this thread's status. */
|
||||
Status status() const { return thread->status(); }
|
||||
|
||||
/** Sets this thread's status. */
|
||||
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. */
|
||||
void activate(int delay = 1);
|
||||
|
||||
/** Set the status to Suspended. */
|
||||
void suspend(int delay = 0);
|
||||
|
||||
/** Set the status to Halted. */
|
||||
void halt(int delay = 0);
|
||||
|
||||
/** Takes over execution of a thread from another CPU. */
|
||||
void takeOverFrom(ThreadContext *old_context);
|
||||
|
||||
/** Registers statistics associated with this TC. */
|
||||
void regStats(const std::string &name);
|
||||
|
||||
/** Serializes state. */
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
/** Unserializes state. */
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
/** Returns this thread's ID number. */
|
||||
int getThreadNum() { return thread->threadId(); }
|
||||
|
||||
/** Copies the architectural registers from another TC into this TC. */
|
||||
void copyArchRegs(ThreadContext *src_tc);
|
||||
|
||||
/** Resets all architectural registers to 0. */
|
||||
void clearArchRegs();
|
||||
|
||||
/** Reads an integer register. */
|
||||
uint64_t readIntReg(int reg_idx);
|
||||
|
||||
FloatReg readFloatReg(int reg_idx);
|
||||
|
||||
FloatRegBits readFloatRegBits(int reg_idx);
|
||||
|
||||
uint64_t readRegOtherThread(int misc_reg, ThreadID tid);
|
||||
|
||||
/** Sets an integer register to a value. */
|
||||
void setIntReg(int reg_idx, uint64_t val);
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val);
|
||||
|
||||
void setFloatRegBits(int reg_idx, FloatRegBits val);
|
||||
|
||||
void setRegOtherThread(int misc_reg,
|
||||
const MiscReg &val,
|
||||
ThreadID tid);
|
||||
|
||||
/** Reads this thread's PC. */
|
||||
TheISA::PCState pcState()
|
||||
{ return cpu->pcState(thread->threadId()); }
|
||||
|
||||
/** Sets this thread's PC. */
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{ cpu->pcState(val, thread->threadId()); }
|
||||
|
||||
/** Needs to be implemented for future CheckerCPU support.
|
||||
* See O3CPU for examples on how to integrate Checker.
|
||||
*/
|
||||
void pcStateNoRecord(const TheISA::PCState &val)
|
||||
{}
|
||||
|
||||
Addr instAddr()
|
||||
{ return cpu->instAddr(thread->threadId()); }
|
||||
|
||||
Addr nextInstAddr()
|
||||
{ return cpu->nextInstAddr(thread->threadId()); }
|
||||
|
||||
MicroPC microPC()
|
||||
{ return cpu->microPC(thread->threadId()); }
|
||||
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscRegNoEffect(int misc_reg)
|
||||
{ return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); }
|
||||
|
||||
/** Reads a misc. register, including any side-effects the
|
||||
* read might have as defined by the architecture. */
|
||||
MiscReg readMiscReg(int misc_reg)
|
||||
{ return cpu->readMiscReg(misc_reg, thread->threadId()); }
|
||||
|
||||
/** Sets a misc. register. */
|
||||
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. */
|
||||
void setMiscReg(int misc_reg, const MiscReg &val);
|
||||
|
||||
int flattenIntIndex(int reg)
|
||||
{ return cpu->isa[thread->threadId()].flattenIntIndex(reg); }
|
||||
|
||||
int flattenFloatIndex(int reg)
|
||||
{ return cpu->isa[thread->threadId()].flattenFloatIndex(reg); }
|
||||
|
||||
void activateContext(int delay)
|
||||
{ cpu->activateContext(thread->threadId(), delay); }
|
||||
|
||||
void deallocateContext()
|
||||
{ cpu->deallocateContext(thread->threadId()); }
|
||||
|
||||
/** Returns the number of consecutive store conditional failures. */
|
||||
// @todo: Figure out where these store cond failures should go.
|
||||
unsigned readStCondFailures()
|
||||
{ return thread->storeCondFailures; }
|
||||
|
||||
/** Sets the number of consecutive store conditional failures. */
|
||||
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. */
|
||||
bool misspeculating() { return false; }
|
||||
|
||||
/** Executes a syscall in SE mode. */
|
||||
void syscall(int64_t callnum)
|
||||
{ return cpu->syscall(callnum, thread->threadId()); }
|
||||
|
||||
/** Reads the funcExeInst counter. */
|
||||
Counter readFuncExeInst() { return thread->funcExeInst; }
|
||||
|
||||
void changeRegFileContext(unsigned param,
|
||||
unsigned val)
|
||||
{ panic("Not supported!"); }
|
||||
};
|
||||
|
||||
#endif
|
||||
44
simulators/gem5/src/cpu/inorder/thread_state.cc
Normal file
44
simulators/gem5/src/cpu/inorder/thread_state.cc
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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/cpu.hh"
|
||||
#include "cpu/inorder/thread_state.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
|
||||
using namespace TheISA;
|
||||
|
||||
void
|
||||
InOrderThreadState::dumpFuncProfile()
|
||||
{
|
||||
std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
|
||||
profile->dump(tc, *os);
|
||||
}
|
||||
97
simulators/gem5/src/cpu/inorder/thread_state.hh
Normal file
97
simulators/gem5/src/cpu/inorder/thread_state.hh
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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/isa_traits.hh"
|
||||
#include "base/callback.hh"
|
||||
#include "base/output.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/thread_state.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
class Event;
|
||||
class FunctionalMemory;
|
||||
class FunctionProfile;
|
||||
class InOrderCPU;
|
||||
class Process;
|
||||
class ProfileNode;
|
||||
|
||||
/**
|
||||
* 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, ThreadID _thread_num,
|
||||
Process *_process)
|
||||
: ThreadState(reinterpret_cast<BaseCPU*>(_cpu), _thread_num,
|
||||
_process),
|
||||
cpu(_cpu), inSyscall(0), trapPending(0), lastGradIsBranch(false)
|
||||
{ }
|
||||
|
||||
/** Handles the syscall. */
|
||||
void syscall(int64_t callnum) { process->syscall(callnum, tc); }
|
||||
|
||||
void dumpFuncProfile();
|
||||
|
||||
/** Pointer to the ThreadContext of this thread. */
|
||||
ThreadContext *tc;
|
||||
|
||||
/** Returns a pointer to the TC of this thread. */
|
||||
ThreadContext *getTC() { return tc; }
|
||||
|
||||
/** Is last instruction graduated a branch? */
|
||||
bool lastGradIsBranch;
|
||||
TheISA::PCState lastBranchPC;
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_THREAD_STATE_HH__
|
||||
Reference in New Issue
Block a user