cpu: Remove the InOrderCPU from the tree

This patch takes the final step in removing the InOrderCPU from the
tree. Rest in peace.

The MinorCPU is now used to model an in-order microarchitecture, and
long term the MinorCPU will eventually be renamed InOrderCPU.
This commit is contained in:
Andreas Hansson 2015-04-20 12:46:35 -04:00
parent 076ea249ae
commit cd76e34056
62 changed files with 0 additions and 17803 deletions

View file

@ -1,77 +0,0 @@
# 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
from BranchPredictor import *
class ThreadModel(Enum):
vals = ['Single', 'SMT', 'SwitchOnCacheMiss']
class InOrderCPU(BaseCPU):
type = 'InOrderCPU'
cxx_header = "cpu/inorder/cpu.hh"
activity = Param.Unsigned(0, "Initial count")
@classmethod
def memory_mode(cls):
return 'timing'
@classmethod
def require_caches(cls):
return True
@classmethod
def support_take_over(cls):
return True
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")
stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU")
multLatency = Param.Cycles(1, "Latency for Multiply Operations")
multRepeatRate = Param.Cycles(1, "Repeat Rate for Multiply Operations")
div8Latency = Param.Cycles(1, "Latency for 8-bit Divide Operations")
div8RepeatRate = Param.Cycles(1, "Repeat Rate for 8-bit Divide Operations")
div16Latency = Param.Cycles(1, "Latency for 16-bit Divide Operations")
div16RepeatRate = Param.Cycles(1, "Repeat Rate for 16-bit Divide Operations")
div24Latency = Param.Cycles(1, "Latency for 24-bit Divide Operations")
div24RepeatRate = Param.Cycles(1, "Repeat Rate for 24-bit Divide Operations")
div32Latency = Param.Cycles(1, "Latency for 32-bit Divide Operations")
div32RepeatRate = Param.Cycles(1, "Repeat Rate for 32-bit Divide Operations")
branchPred = Param.BranchPredictor(TournamentBP(numThreads =
Parent.numThreads),
"Branch Predictor")

View file

@ -1,36 +0,0 @@
# 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'
cxx_header = "cpu/inorder/inorder_trace.hh"

View file

@ -1,89 +0,0 @@
# -*- 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/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')

View file

@ -1,33 +0,0 @@
# -*- 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', default=True)

View file

@ -1,85 +0,0 @@
/*
* 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__

File diff suppressed because it is too large Load diff

View file

@ -1,942 +0,0 @@
/*
* Copyright (c) 2012-2013 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* 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/reg_class.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::CCReg CCReg;
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();
void verifyMemoryMode() const;
/** Return a reference to the data port. */
virtual MasterPort &getDataPort() { return dataPort; }
/** Return a reference to the instruction port. */
virtual MasterPort &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 MasterPort
{
private:
/** Pointer to cache unit */
CacheUnit *cacheUnit;
public:
/** Default constructor. */
CachePort(CacheUnit *_cacheUnit, const std::string& name);
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(Cycles delay)
{
assert(!tickEvent.scheduled() || tickEvent.squashed());
reschedule(&tickEvent, clockEdge(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, const Fault &fault,
ThreadID _tid, DynInstPtr inst, CPUEventPri event_pri);
/** Set Type of Event To Be Scheduled */
void setEvent(CPUEventType e_type, const 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(Cycles delay);
/** Unschedule This Event */
void unscheduleEvent();
};
/** Schedule a CPU Event */
void scheduleCpuEvent(CPUEventType cpu_event, const Fault &fault,
ThreadID tid,
DynInstPtr inst, Cycles delay = Cycles(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];
#ifdef ISA_HAS_CC_REGS
TheISA::CCReg ccRegs[ThePipeline::MaxThreads][TheISA::NumCCRegs];
#endif
/** ISA state */
std::vector<TheISA::ISA *> isa;
/** Dependency Tracker for Integer & Floating Point Regs */
RegDepMap archRegDepMap[ThePipeline::MaxThreads];
/** Global communication structure */
TimeBuffer<TimeStruct> timeBuffer;
/** Communication structure that sits in between pipeline stages */
StageQueue *stageQueue[ThePipeline::NumStages-1];
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(const 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(const Fault &fault, ThreadID tid, DynInstPtr inst,
Cycles delay = Cycles(0));
/** Executes a syscall.*/
void syscall(int64_t callnum, ThreadID tid);
/** Schedule a trap on the CPU */
void trapContext(const Fault &fault, ThreadID tid, DynInstPtr inst,
Cycles delay = Cycles(0));
/** Perform trap to Handle Given Fault */
void trap(const Fault &fault, ThreadID tid, DynInstPtr inst);
/** Schedule thread activation on the CPU */
void activateContext(ThreadID tid);
/** 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();
/** Add Thread From Ready List to Active Threads List. */
void activateNextReadyThread();
/** Schedule a thread deactivation on the CPU */
void deactivateContext(ThreadID tid);
/** 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,
Cycles delay = Cycles(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);
CCReg readCCReg(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);
void setCCReg(RegIndex reg_idx, CCReg val, ThreadID tid);
RegIndex flattenRegIdx(RegIndex reg_idx, RegClass &reg_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;
/** 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;
/** Resumes execution after a drain. */
void drainResume();
/** Switches out this CPU. */
virtual void switchOut();
/** Takes over from another CPU. */
virtual void takeOverFrom(BaseCPU *oldCPU);
/** 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__

View file

@ -1,289 +0,0 @@
/*
* 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;
}
void
FirstStage::takeOverFrom()
{
PipelineStage::takeOverFrom();
for(ThreadID tid = 0; tid < this->numThreads; tid++) {
stageStatus[tid] = Running;
}
}

View file

@ -1,96 +0,0 @@
/*
* 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/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();
/** Takes over from another CPU's thread. */
void takeOverFrom();
};
#endif // __CPU_INORDER_FIRST_STAGE_HH__

View file

@ -1,61 +0,0 @@
/*
* 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;
return new InOrderCPU(this);
}

View file

@ -1,626 +0,0 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2013 Advanced Micro Devices, 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 "cpu/reg_class.hh"
#include "debug/InOrderDynInst.hh"
#include "mem/request.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() const
{
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 no_squash_from_TC = this->thread->noSquashFromTC;
this->thread->noSquashFromTC = true;
this->fault = this->staticInst->execute(this, this->traceData);
this->thread->noSquashFromTC = no_squash_from_TC;
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 no_squash_from_TC = this->thread->noSquashFromTC;
this->thread->noSquashFromTC = true;
this->fault = this->staticInst->initiateAcc(this, this->traceData);
this->thread->noSquashFromTC = no_squash_from_TC;
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 std::make_shared<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(const 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(int reg_idx, ThreadID tid)
{
if (tid == -1) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
}
RegIndex rel_idx;
switch (regIdxToClass(reg_idx, &rel_idx)) {
case IntRegClass:
return this->cpu->readIntReg(rel_idx, tid);
case FloatRegClass:
return this->cpu->readFloatRegBits(rel_idx, tid);
case MiscRegClass:
return this->cpu->readMiscReg(rel_idx, tid); // Misc. Register File
default:
panic("register %d out of range\n", reg_idx);
}
}
/** 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(int reg_idx, MiscReg val, ThreadID tid)
{
if (tid == InvalidThreadID) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
}
RegIndex rel_idx;
switch (regIdxToClass(reg_idx, &rel_idx)) {
case IntRegClass:
this->cpu->setIntReg(rel_idx, val, tid);
break;
case FloatRegClass:
this->cpu->setFloatRegBits(rel_idx, val, tid);
break;
case CCRegClass:
this->cpu->setCCReg(rel_idx, val, tid);
break;
case MiscRegClass:
this->cpu->setMiscReg(rel_idx, val, tid); // Misc. Register File
break;
}
}
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();
}
void
InOrderDynInst::armMonitor(Addr address) {
cpu->armMonitor(address);
}
bool
InOrderDynInst::mwait(PacketPtr pkt) {
return cpu->mwait(pkt);
}
void
InOrderDynInst::mwaitAtomic(ThreadContext *tc)
{
return cpu->mwaitAtomic(tc, cpu->getDTBPtr());
}
AddressMonitor *
InOrderDynInst::getAddrMonitor()
{
return cpu->getCpuAddrMonitor();
}

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
/*
* 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);
};

View file

@ -1,98 +0,0 @@
/*
* 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)
: ExeTracerRecord(0, _thread, NULL, _pc)
{
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__

File diff suppressed because it is too large Load diff

View file

@ -1,349 +0,0 @@
/*
* 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. */
virtual 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

View file

@ -1,166 +0,0 @@
/*
* 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;
}
};

View file

@ -1,145 +0,0 @@
/*
* 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"
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

View file

@ -1,242 +0,0 @@
/*
* 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;
}
};

View file

@ -1,153 +0,0 @@
/*
* 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"
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

View file

@ -1,240 +0,0 @@
/*
* 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;
}
};

View file

@ -1,153 +0,0 @@
/*
* 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"
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

View file

@ -1,85 +0,0 @@
/*
* 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

View file

@ -1,304 +0,0 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2013 Advanced Micro Devices, 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(NumRegClasses);
regMap[IntRegClass].resize(NumIntRegs);
regMap[FloatRegClass].resize(NumFloatRegs);
regMap[MiscRegClass].resize(NumMiscRegs);
}
RegDepMap::~RegDepMap()
{
clear();
}
string
RegDepMap::name()
{
return cpu->name() + ".RegDepMap";
}
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++) {
RegClass 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 == IntRegClass) {
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, RegClassStrings[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);
RegClass reg_type = regIdxToClass(inst->destRegIdx(i));
// Merge Dyn Inst & CPU Result Types
if (flat_idx == TheISA::ZeroReg &&
reg_type == IntRegClass) {
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, RegClassStrings[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 < NumRegClasses; 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");
}
}
}
}

View file

@ -1,115 +0,0 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2013 Advanced Micro Devices, 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;
RegDepMap(int size = TheISA::TotalNumRegs);
~RegDepMap();
std::string name();
void setCPU(InOrderCPU *_cpu);
/** Clear the Entire Map */
void clear();
/** Insert all of a instruction's destination registers into map*/
void insert(DynInstPtr inst);
/** 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

View file

@ -1,523 +0,0 @@
/*
* 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,
Cycles 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 > Cycles(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,
Cycles(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 > Cycles(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);
}
void
Resource::scheduleExecution(int slot_num)
{
if (latency > Cycles(0)) {
scheduleEvent(slot_num, latency);
} else {
execute(slot_num);
}
}
void
Resource::scheduleEvent(int slot_idx, Cycles 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->clockEdge(delay));
resourceEvent[slot_idx].scheduleEvent(delay);
}
bool
Resource::scheduleEvent(DynInstPtr inst, Cycles 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(Cycles delay)
{
assert(!scheduled() || squashed());
resource->cpu->reschedule(this,
resource->cpu->clockEdge(delay), true);
}

View file

@ -1,411 +0,0 @@
/*
* 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,
Cycles 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(const 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, Cycles delay);
/** Find instruction in list, Schedule resource event, regardless of its
* current state. */
bool scheduleEvent(DynInstPtr inst, Cycles 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);
/** 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 Cycles 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 Cycles 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(Cycles 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__

View file

@ -1,361 +0,0 @@
/*
* 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();
}

View file

@ -1,475 +0,0 @@
/*
* 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, Cycles(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, Cycles(0), _cpu,
params);
resources.push_back(instUnit);
resources.push_back(new DecodeUnit("decode_unit", Decode,
stage_width, Cycles(0), _cpu,
params));
resources.push_back(new BranchPredictor("branch_predictor", BPred,
stage_width, Cycles(0),
_cpu, params));
resources.push_back(new InstBuffer("fetch_buffer_t0", FetchBuff, 4,
Cycles(0), _cpu, params));
resources.push_back(new UseDefUnit("regfile_manager", RegManager,
stage_width * 3, Cycles(0), _cpu,
params));
resources.push_back(new AGENUnit("agen_unit", AGEN,
stage_width, Cycles(0), _cpu,
params));
resources.push_back(new ExecutionUnit("execution_unit", ExecUnit,
stage_width, Cycles(0), _cpu,
params));
resources.push_back(new MultDivUnit("mult_div_unit", MDU,
stage_width * 2, Cycles(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, Cycles(0), _cpu,
params);
resources.push_back(dataUnit);
gradObjects.push_back(BPred);
resources.push_back(new GraduationUnit("graduation_unit", Grad,
stage_width, Cycles(0), _cpu,
params));
resources.push_back(new InstBuffer("fetch_buffer_t1", FetchBuff2, 4,
Cycles(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(const 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,
Cycles delay, int res_idx, ThreadID tid)
{
assert(delay >= 0);
Tick when = cpu->clockEdge(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(Cycles delay)
{
InOrderCPU *cpu = resPool->cpu;
assert(!scheduled() || squashed());
cpu->reschedule(this, cpu->clockEdge(delay), true);
}
/** Unschedule resource event, regardless of its current state. */
void
ResourcePool::ResPoolEvent::unscheduleEvent()
{
if (scheduled())
squash();
}

View file

@ -1,250 +0,0 @@
/*
* 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/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(Cycles 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(const 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,
Cycles delay = Cycles(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__

View file

@ -1,233 +0,0 @@
/*
* 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++;
}
}
}

View file

@ -1,285 +0,0 @@
/*
* 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__

View file

@ -1,107 +0,0 @@
/*
* 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,
Cycles 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);
}
}

View file

@ -1,64 +0,0 @@
/*
* 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/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,
Cycles 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__

View file

@ -1,181 +0,0 @@
/*
* 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, Cycles res_latency,
InOrderCPU *_cpu,
ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu),
branchPred(params->branchPred)
{
instSize = sizeof(MachInst);
}
void
BranchPredictor::regStats()
{
predictedTaken
.name(name() + ".predictedTaken")
.desc("Number of Branches Predicted As Taken (True).");
predictedNotTaken
.name(name() + ".predictedNotTaken")
.desc("Number of Branches Predicted As Not Taken (False).");
Resource::regStats();
}
void
BranchPredictor::execute(int slot_num)
{
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 instPC = inst->pcState();
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->predictInOrder(
inst->staticInst, inst->seqNum,
inst->asid, instPC, 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);
}

View file

@ -1,87 +0,0 @@
/*
* 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/pred/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,
Cycles 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__

File diff suppressed because it is too large Load diff

View file

@ -1,269 +0,0 @@
/*
* 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,
Cycles 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(const 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 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,
MemCmd _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__

View file

@ -1,97 +0,0 @@
/*
* 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,
Cycles 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);
}
}

View file

@ -1,66 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,249 +0,0 @@
/*
* 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,
Cycles 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);
}
}

View file

@ -1,83 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,335 +0,0 @@
/*
* 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,
Cycles 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", tid, 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(const 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]);
}

View file

@ -1,105 +0,0 @@
/*
* 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,
Cycles 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(const 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

View file

@ -1,591 +0,0 @@
/*
* 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,
Cycles 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;
}
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]->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->getConstPtr<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(const 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();
}

View file

@ -1,139 +0,0 @@
/*
* 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,
Cycles 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(const 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__

View file

@ -1,135 +0,0 @@
/*
* 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,
Cycles 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);
}
}

View file

@ -1,67 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,241 +0,0 @@
/*
* 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,
Cycles 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);
}

View file

@ -1,93 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,66 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,353 +0,0 @@
/*
* 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,
Cycles 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);
}

View file

@ -1,139 +0,0 @@
/*
* 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,
Cycles 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;
Cycles multLatency;
/** Latency & Repeat Rate for 8-bit Divide Insts */
unsigned div8RepeatRate;
Cycles div8Latency;
/** Latency & Repeat Rate for 16-bit Divide Insts */
unsigned div16RepeatRate;
Cycles div16Latency;
/** Latency & Repeat Rate for 24-bit Divide Insts */
unsigned div24RepeatRate;
Cycles div24Latency;
/** Latency & Repeat Rate for 32-bit Divide Insts */
unsigned div32RepeatRate;
Cycles 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__

View file

@ -1,50 +0,0 @@
/*
* 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"
// The TLBUnit is only needed with the 9-stage pipe and is
// triggering a gcc LTO bug
//#include "cpu/inorder/resources/tlb_unit.hh"
#include "cpu/inorder/resources/use_def.hh"
#endif

View file

@ -1,259 +0,0 @@
/*
* 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,
Cycles 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);
}
}
}

View file

@ -1,152 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,510 +0,0 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2013 Advanced Micro Devices, 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,
Cycles 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 > Cycles(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] && 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:
{
RegClass 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 == IntRegClass) {
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 IntRegClass:
{
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 FloatRegClass:
{
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_Reg_Base, 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 MiscRegClass:
{
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 - Misc_Reg_Base, 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 IntRegClass:
{
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 FloatRegClass:
{
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_Reg_Base, 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 MiscRegClass:
{
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
" reg %i (%i) value 0x%x from "
"[sn:%i] to [sn:%i] source #%i.\n",
tid, reg_idx - Misc_Reg_Base, 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:
{
RegClass 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 == IntRegClass) {
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 IntRegClass:
{
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 FloatRegClass:
{
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_Reg_Base, 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_Reg_Base, 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_Reg_Base, 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 MiscRegClass:
{
uniqueMiscRegMap[flat_idx] = true;
DPRINTF(InOrderUseDef, "[tid:%i]: Writing Misc. 0x%x "
"to register idx %i.\n",
tid, inst->readIntResult(ud_idx), reg_idx - Misc_Reg_Base);
// 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();
}

View file

@ -1,135 +0,0 @@
/*
* 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,
Cycles 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__

View file

@ -1,314 +0,0 @@
/*
* Copyright (c) 2012 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* 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 "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)
{
::takeOverFrom(*this, *old_context);
thread->funcExeInst = old_context->readFuncExeInst();
thread->noSquashFromTC = false;
thread->trapPending = false;
}
void
InOrderThreadContext::activate()
{
DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Active)
return;
thread->setStatus(ThreadContext::Active);
cpu->activateContext(thread->threadId());
}
void
InOrderThreadContext::suspend()
{
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()
{
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::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);
}
CCReg
InOrderThreadContext::readCCReg(int reg_idx)
{
ThreadID tid = thread->threadId();
reg_idx = cpu->isa[tid]->flattenCCIndex(reg_idx);
return cpu->readCCReg(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::setCCReg(int reg_idx, CCReg val)
{
ThreadID tid = thread->threadId();
reg_idx = cpu->isa[tid]->flattenCCIndex(reg_idx);
cpu->setCCReg(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());
}
uint64_t
InOrderThreadContext::readIntRegFlat(int idx)
{
const ThreadID tid = thread->threadId();
return cpu->readIntReg(idx, tid);
}
void
InOrderThreadContext::setIntRegFlat(int idx, uint64_t val)
{
const ThreadID tid = thread->threadId();
cpu->setIntReg(idx, val, tid);
}
FloatReg
InOrderThreadContext::readFloatRegFlat(int idx)
{
const ThreadID tid = thread->threadId();
return cpu->readFloatReg(idx, tid);
}
void
InOrderThreadContext::setFloatRegFlat(int idx, FloatReg val)
{
const ThreadID tid = thread->threadId();
cpu->setFloatReg(idx, val, tid);
}
FloatRegBits
InOrderThreadContext::readFloatRegBitsFlat(int idx)
{
const ThreadID tid = thread->threadId();
return cpu->readFloatRegBits(idx, tid);
}
void
InOrderThreadContext::setFloatRegBitsFlat(int idx, FloatRegBits val)
{
const ThreadID tid = thread->threadId();
cpu->setFloatRegBits(idx, val, tid);
}
CCReg
InOrderThreadContext::readCCRegFlat(int idx)
{
const ThreadID tid = thread->threadId();
return cpu->readCCReg(idx, tid);
}
void
InOrderThreadContext::setCCRegFlat(int idx, CCReg val)
{
const ThreadID tid = thread->threadId();
cpu->setCCReg(idx, val, tid);
}

View file

@ -1,317 +0,0 @@
/*
* Copyright (c) 2012 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* 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_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() const { return cpu->cpuId(); }
/** Reads this CPU's Socket ID. */
uint32_t socketId() const { return cpu->socketId(); }
int contextId() const { return thread->contextId(); }
void setContextId(int id) { thread->setContextId(id); }
/** Returns this thread's ID number. */
int threadId() const { 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. */
void activate();
/** Set the status to Suspended. */
void suspend();
/** Set the status to Halted. */
void halt();
/** 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);
/** 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);
CCReg readCCReg(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 setCCReg(int reg_idx, CCReg 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); }
int flattenCCIndex(int reg)
{ return cpu->isa[thread->threadId()]->flattenCCIndex(reg); }
int flattenMiscIndex(int reg)
{ return cpu->isa[thread->threadId()]->flattenMiscIndex(reg); }
void activateContext()
{ cpu->activateContext(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; }
/** 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!"); }
uint64_t readIntRegFlat(int idx);
void setIntRegFlat(int idx, uint64_t val);
FloatReg readFloatRegFlat(int idx);
void setFloatRegFlat(int idx, FloatReg val);
FloatRegBits readFloatRegBitsFlat(int idx);
void setFloatRegBitsFlat(int idx, FloatRegBits val);
CCReg readCCRegFlat(int idx);
void setCCRegFlat(int idx, CCReg val);
};
#endif

View file

@ -1,44 +0,0 @@
/*
* 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);
}

View file

@ -1,103 +0,0 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
*/
#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:
/* This variable controls if writes to a thread context should cause a all
* dynamic/speculative state to be thrown away. Nominally this is the
* desired behavior because the external thread context write has updated
* some state that could be used by an inflight instruction, however there
* are some cases like in a fault/trap handler where this behavior would
* lead to successive restarts and forward progress couldn't be made. This
* variable controls if the squashing will occur.
*/
bool noSquashFromTC;
/** 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), noSquashFromTC(false), trapPending(false),
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__