InOrder: Import new inorder CPU model from MIPS.

This model currently only works in MIPS_SE mode, so it will take some effort
to clean it up and make it generally useful. Hopefully people are willing to
help make that happen!
This commit is contained in:
Korey Sewell 2009-02-10 15:49:29 -08:00
parent 36d9065f5f
commit 973d8b8b13
64 changed files with 15432 additions and 0 deletions

View file

@ -82,3 +82,6 @@ CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
CpuModel('O3CPU', 'o3_cpu_exec.cc',
'#include "cpu/o3/isa_specific.hh"',
{ 'CPU_exec_context': 'O3DynInst' })
CpuModel('InOrderCPU', 'inorder_cpu_exec.cc',
'#include "cpu/inorder/inorder_dyn_inst.hh"',
{ 'CPU_exec_context': 'InOrderDynInst' })

View file

@ -0,0 +1,80 @@
# Copyright (c) 2007 MIPS Technologies, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Korey Sewell
from m5.params import *
from m5.proxy import *
from m5 import build_env
from BaseCPU import BaseCPU
class InOrderCPU(BaseCPU):
type = 'InOrderCPU'
activity = Param.Unsigned(0, "Initial count")
numThreads = Param.Unsigned(1, "number of HW thread contexts")
cachePorts = Param.Unsigned("Cache Ports")
stageWidth = Param.Unsigned(1, "Stage width")
fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from")
dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
_mem_ports = ['icache_port', 'dcache_port']
predType = Param.String("tournament", "Branch predictor type ('local', 'tournament')")
localPredictorSize = Param.Unsigned(2048, "Size of local predictor")
localCtrBits = Param.Unsigned(2, "Bits per counter")
localHistoryTableSize = Param.Unsigned(2048, "Size of local history table")
localHistoryBits = Param.Unsigned(11, "Bits for the local history")
globalPredictorSize = Param.Unsigned(8192, "Size of global predictor")
globalCtrBits = Param.Unsigned(2, "Bits per counter")
globalHistoryBits = Param.Unsigned(13, "Bits of history")
choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor")
choiceCtrBits = Param.Unsigned(2, "Bits of choice counters")
BTBEntries = Param.Unsigned(4096, "Number of BTB entries")
BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits")
RASSize = Param.Unsigned(16, "RAS size")
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
functionTrace = Param.Bool(False, "Enable function trace")
functionTraceStart = Param.Tick(0, "Cycle to start function trace")
stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU")
memBlockSize = Param.Unsigned("Memory Block Size")
multLatency = Param.Unsigned(1, "Latency for Multiply Operations")
multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations")
div8Latency = Param.Unsigned(1, "Latency for 8-bit Divide Operations")
div8RepeatRate = Param.Unsigned(1, "Repeat Rate for 8-bit Divide Operations")
div16Latency = Param.Unsigned(1, "Latency for 16-bit Divide Operations")
div16RepeatRate = Param.Unsigned(1, "Repeat Rate for 16-bit Divide Operations")
div24Latency = Param.Unsigned(1, "Latency for 24-bit Divide Operations")
div24RepeatRate = Param.Unsigned(1, "Repeat Rate for 24-bit Divide Operations")
div32Latency = Param.Unsigned(1, "Latency for 32-bit Divide Operations")
div32RepeatRate = Param.Unsigned(1, "Repeat Rate for 32-bit Divide Operations")

View file

@ -0,0 +1,35 @@
# Copyright (c) 2007 MIPS Technologies, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Korey Sewell
from m5.SimObject import SimObject
from m5.params import *
from InstTracer import InstTracer
class InOrderTrace(InstTracer):
type = 'InOrderTrace'
cxx_class = 'Trace::InOrderTrace'

View file

@ -0,0 +1,82 @@
# -*- mode:python -*-
# Copyright (c) 2007 MIPS Technologies, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Korey Sewell
Import('*')
if 'InOrderCPU' in env['CPU_MODELS']:
SimObject('InOrderCPU.py')
SimObject('InOrderTrace.py')
TraceFlag('ResReqCount')
TraceFlag('FreeList')
TraceFlag('InOrderCachePort')
TraceFlag('InOrderStage')
TraceFlag('InOrderStall')
TraceFlag('InOrderCPU')
TraceFlag('InOrderMDU')
TraceFlag('RegDepMap')
TraceFlag('Rename')
TraceFlag('InOrderDynInst')
TraceFlag('Resource')
TraceFlag('RefCount')
CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
'InOrderMDU', 'RegDepMap', 'Resource', 'Rename'])
Source('pipeline_traits.cc')
Source('inorder_dyn_inst.cc')
Source('inorder_cpu_builder.cc')
Source('inorder_trace.cc')
Source('pipeline_stage.cc')
Source('first_stage.cc')
Source('resource.cc')
Source('resources/agen_unit.cc')
Source('resources/execution_unit.cc')
Source('resources/bpred_unit.cc')
Source('resources/branch_predictor.cc')
Source('resources/cache_unit.cc')
Source('resources/use_def.cc')
Source('resources/decode_unit.cc')
Source('resources/inst_buffer.cc')
Source('resources/graduation_unit.cc')
Source('resources/tlb_unit.cc')
Source('resources/fetch_seq_unit.cc')
Source('resources/mult_div_unit.cc')
Source('resource_pool.cc')
Source('reg_dep_map.cc')
Source('../o3/btb.cc')
Source('../o3/tournament_pred.cc')
Source('../o3/2bit_local_pred.cc')
Source('../o3/free_list.cc')
Source('../o3/rename_map.cc')
Source('../o3/ras.cc')
Source('thread_context.cc')
Source('cpu.cc')

33
src/cpu/inorder/SConsopts Normal file
View file

@ -0,0 +1,33 @@
# -*- mode:python -*-
# Copyright (c) 2007 MIPS Technologies, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Korey Sewell
Import('*')
all_cpu_list.append('InOrderCPU')

104
src/cpu/inorder/comm.hh Normal file
View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_COMM_HH__
#define __CPU_INORDER_COMM_HH__
#include <vector>
#include "arch/faults.hh"
#include "arch/isa_traits.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inst_seq.hh"
#include "sim/host.hh"
/** Struct that defines the information passed from in between stages */
/** This information mainly goes forward through the pipeline. */
struct InterStageStruct {
int size;
ThePipeline::DynInstPtr insts[ThePipeline::StageWidth];
bool squash;
bool branchMispredict;
bool branchTaken;
uint64_t mispredPC;
uint64_t nextPC;
InstSeqNum squashedSeqNum;
bool includeSquashInst;
};
/** Turn This into a Class */
/** Struct that defines all backwards communication. */
struct TimeStruct {
struct stageComm {
bool squash;
bool predIncorrect;
uint64_t branchAddr;
// @todo: Might want to package this kind of branch stuff into a single
// struct as it is used pretty frequently.
bool branchMispredict;
bool branchTaken;
uint64_t mispredPC;
uint64_t nextPC;
unsigned branchCount;
// Represents the instruction that has either been retired or
// squashed. Similar to having a single bus that broadcasts the
// retired or squashed sequence number.
InstSeqNum doneSeqNum;
InstSeqNum bdelayDoneSeqNum;
bool squashDelaySlot;
//Just in case we want to do a commit/squash on a cycle
//(necessary for multiple ROBs?)
bool commitInsts;
InstSeqNum squashSeqNum;
// Communication specifically to the IQ to tell the IQ that it can
// schedule a non-speculative instruction.
InstSeqNum nonSpecSeqNum;
bool uncached;
ThePipeline::DynInstPtr uncachedLoad;
bool interruptPending;
bool clearInterrupt;
};
stageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads];
bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads];
bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads];
};
#endif //__CPU_INORDER_COMM_HH__

1322
src/cpu/inorder/cpu.cc Normal file

File diff suppressed because it is too large Load diff

730
src/cpu/inorder/cpu.hh Normal file
View file

@ -0,0 +1,730 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_CPU_HH__
#define __CPU_INORDER_CPU_HH__
#include <iostream>
#include <list>
#include <queue>
#include <set>
#include <vector>
#include "arch/isa_traits.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "config/full_system.hh"
#include "cpu/activity.hh"
#include "cpu/base.hh"
#include "cpu/simple_thread.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/pipeline_stage.hh"
#include "cpu/inorder/thread_state.hh"
#include "cpu/inorder/reg_dep_map.hh"
#include "cpu/o3/dep_graph.hh"
#include "cpu/o3/rename_map.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
#include "mem/request.hh"
#include "sim/eventq.hh"
#include "sim/process.hh"
class ThreadContext;
class MemInterface;
class MemObject;
class Process;
class ResourcePool;
class InOrderCPU : public BaseCPU
{
protected:
typedef ThePipeline::Params Params;
typedef InOrderThreadState Thread;
//ISA TypeDefs
typedef TheISA::IntReg IntReg;
typedef TheISA::FloatReg FloatReg;
typedef TheISA::FloatRegBits FloatRegBits;
typedef TheISA::MiscReg MiscReg;
typedef TheISA::RegFile RegFile;
typedef SimpleRenameMap RenameMap;
//DynInstPtr TypeDefs
typedef ThePipeline::DynInstPtr DynInstPtr;
typedef std::list<DynInstPtr>::iterator ListIt;
//TimeBuffer TypeDefs
typedef TimeBuffer<InterStageStruct> StageQueue;
friend class Resource;
public:
/** Constructs a CPU with the given parameters. */
InOrderCPU(Params *params);
/** CPU ID */
int cpu_id;
/** Type of core that this is */
std::string coreType;
int readCpuId() { return cpu_id; }
void setCpuId(int val) { cpu_id = val; }
Params *cpu_params;
TheISA::ITB * itb;
TheISA::DTB * dtb;
public:
enum Status {
Running,
Idle,
Halted,
Blocked,
SwitchedOut
};
/** Overall CPU status. */
Status _status;
private:
/** Define TickEvent for the CPU */
class TickEvent : public Event
{
private:
/** Pointer to the CPU. */
InOrderCPU *cpu;
public:
/** Constructs a tick event. */
TickEvent(InOrderCPU *c);
/** Processes a tick event, calling tick() on the CPU. */
void process();
/** Returns the description of the tick event. */
const char *description();
};
/** The tick event used for scheduling CPU ticks. */
TickEvent tickEvent;
/** Schedule tick event, regardless of its current state. */
void scheduleTickEvent(int delay)
{
if (tickEvent.squashed())
mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay)));
else if (!tickEvent.scheduled())
mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay)));
}
/** Unschedule tick event, regardless of its current state. */
void unscheduleTickEvent()
{
if (tickEvent.scheduled())
tickEvent.squash();
}
public:
// List of Events That can be scheduled from
// within the CPU.
// NOTE(1): The Resource Pool also uses this event list
// to schedule events broadcast to all resources interfaces
// NOTE(2): CPU Events usually need to schedule a corresponding resource
// pool event.
enum CPUEventType {
ActivateThread,
DeallocateThread,
SuspendThread,
DisableThreads,
EnableThreads,
DisableVPEs,
EnableVPEs,
Trap,
InstGraduated,
SquashAll,
UpdatePCs,
NumCPUEvents
};
/** Define CPU Event */
class CPUEvent : public Event
{
protected:
InOrderCPU *cpu;
public:
CPUEventType cpuEventType;
unsigned tid;
unsigned vpe;
Fault fault;
public:
/** Constructs a CPU event. */
CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault,
unsigned _tid, unsigned _vpe);
/** Set Type of Event To Be Scheduled */
void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe)
{
fault = _fault;
cpuEventType = e_type;
tid = _tid;
vpe = _vpe;
}
/** Processes a resource event. */
virtual void process();
/** Returns the description of the resource event. */
const char *description();
/** Schedule Event */
void scheduleEvent(int delay);
/** Unschedule This Event */
void unscheduleEvent();
};
/** Schedule a CPU Event */
void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid,
unsigned vpe, unsigned delay = 0);
public:
/** Interface between the CPU and CPU resources. */
ResourcePool *resPool;
/** Instruction used to signify that there is no *real* instruction in buffer slot */
DynInstPtr dummyBufferInst;
/** Used by resources to signify a denied access to a resource. */
ResourceRequest *dummyReq;
/** Identifies the resource id that identifies a fetch
* access unit.
*/
unsigned fetchPortIdx;
/** Identifies the resource id that identifies a data
* access unit.
*/
unsigned dataPortIdx;
/** The Pipeline Stages for the CPU */
PipelineStage *pipelineStage[ThePipeline::NumStages];
TheISA::IntReg PC[ThePipeline::MaxThreads];
TheISA::IntReg nextPC[ThePipeline::MaxThreads];
TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
/** The Register File for the CPU */
/** @TODO: This regFile wont be a sufficient solution for out-of-order, add register
* files as a resource in order to handle ths problem
*/
TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];;
TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];;
TheISA::MiscRegFile miscRegFile;
/** Dependency Tracker for Integer & Floating Point Regs */
RegDepMap archRegDepMap[ThePipeline::MaxThreads];
/** Global communication structure */
TimeBuffer<TimeStruct> timeBuffer;
/** Communication structure that sits in between pipeline stages */
StageQueue *stageQueue[ThePipeline::NumStages-1];
public:
/** Registers statistics. */
void regStats();
/** Ticks CPU, calling tick() on each stage, and checking the overall
* activity to see if the CPU should deschedule itself.
*/
void tick();
/** Initialize the CPU */
void init();
/** Reset State in the CPU */
void reset();
/** Get a Memory Port */
Port* getPort(const std::string &if_name, int idx = 0);
/** trap() - sets up a trap event on the cpuTraps to handle given fault.
* trapCPU() - Traps to handle given fault
*/
void trap(Fault fault, unsigned tid, int delay = 0);
void trapCPU(Fault fault, unsigned tid);
/** Setup CPU to insert a thread's context */
void insertThread(unsigned tid);
/** Remove all of a thread's context from CPU */
void removeThread(unsigned tid);
/** Add Thread to Active Threads List. */
void activateContext(unsigned tid, int delay = 0);
void activateThread(unsigned tid);
/** Remove Thread from Active Threads List */
void suspendContext(unsigned tid, int delay = 0);
void suspendThread(unsigned tid);
/** Remove Thread from Active Threads List &&
* Remove Thread Context from CPU.
*/
void deallocateContext(unsigned tid, int delay = 0);
void deallocateThread(unsigned tid);
void deactivateThread(unsigned tid);
/** Remove Thread from Active Threads List &&
* Remove Thread Context from CPU.
*/
void haltContext(unsigned tid, int delay = 0);
void removePipelineStalls(unsigned tid);
void squashThreadInPipeline(unsigned tid);
/// Notify the CPU to enable a virtual processor element.
virtual void enableVirtProcElement(unsigned vpe);
void enableVPEs(unsigned vpe);
/// Notify the CPU to disable a virtual processor element.
virtual void disableVirtProcElement(unsigned tid, unsigned vpe);
void disableVPEs(unsigned tid, unsigned vpe);
/// Notify the CPU that multithreading is enabled.
virtual void enableMultiThreading(unsigned vpe);
void enableThreads(unsigned vpe);
/// Notify the CPU that multithreading is disabled.
virtual void disableMultiThreading(unsigned tid, unsigned vpe);
void disableThreads(unsigned tid, unsigned vpe);
// Sets a thread-rescheduling condition.
void setThreadRescheduleCondition(uint32_t tid)
{
//@TODO: IMPLEMENT ME
}
/** Activate a Thread When CPU Resources are Available. */
void activateWhenReady(int tid);
/** Add or Remove a Thread Context in the CPU. */
void doContextSwitch();
/** Update The Order In Which We Process Threads. */
void updateThreadPriority();
/** Switches a Pipeline Stage to Active. (Unused currently) */
void switchToActive(int stage_idx)
{ /*pipelineStage[stage_idx]->switchToActive();*/ }
/** Switches out this CPU. (Unused currently) */
//void switchOut(Sampler *sampler);
/** Signals to this CPU that a stage has completed switching out. (Unused currently)*/
void signalSwitched();
/** Takes over from another CPU. (Unused currently)*/
void takeOverFrom(BaseCPU *oldCPU);
/** Get the current instruction sequence number, and increment it. */
InstSeqNum getAndIncrementInstSeq(unsigned tid)
{ return globalSeqNum[tid]++; }
/** Get the current instruction sequence number, and increment it. */
InstSeqNum nextInstSeqNum(unsigned tid)
{ return globalSeqNum[tid]; }
/** Increment Instruction Sequence Number */
void incrInstSeqNum(unsigned tid)
{ globalSeqNum[tid]++; }
/** Set Instruction Sequence Number */
void setInstSeqNum(unsigned tid, InstSeqNum seq_num)
{
globalSeqNum[tid] = seq_num;
}
InstSeqNum getNextEventNum()
{
return cpuEventNum++;
}
/** Get instruction asid. */
int getInstAsid(unsigned tid)
{ return thread[tid]->getInstAsid(); }
/** Get data asid. */
int getDataAsid(unsigned tid)
{ return thread[tid]->getDataAsid(); }
/** Register file accessors */
uint64_t readIntReg(int reg_idx, unsigned tid);
FloatReg readFloatReg(int reg_idx, unsigned tid,
int width = TheISA::SingleWidth);
FloatRegBits readFloatRegBits(int reg_idx, unsigned tid,
int width = TheISA::SingleWidth);
void setIntReg(int reg_idx, uint64_t val, unsigned tid);
void setFloatReg(int reg_idx, FloatReg val, unsigned tid,
int width = TheISA::SingleWidth);
void setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid,
int width = TheISA::SingleWidth);
/** Reads a miscellaneous register. */
MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
/** Reads a misc. register, including any side effects the read
* might have as defined by the architecture.
*/
MiscReg readMiscReg(int misc_reg, unsigned tid);
/** Sets a miscellaneous register. */
void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid);
/** Sets a misc. register, including any side effects the write
* might have as defined by the architecture.
*/
void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid);
/** Reads a int/fp/misc reg. from another thread depending on ISA-defined
* target thread
*/
uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1);
/** Sets a int/fp/misc reg. from another thread depending on an ISA-defined
* target thread
*/
void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid);
/** Reads the commit PC of a specific thread. */
uint64_t readPC(unsigned tid);
/** Sets the commit PC of a specific thread. */
void setPC(Addr new_PC, unsigned tid);
/** Reads the next PC of a specific thread. */
uint64_t readNextPC(unsigned tid);
/** Sets the next PC of a specific thread. */
void setNextPC(uint64_t val, unsigned tid);
/** Reads the next NPC of a specific thread. */
uint64_t readNextNPC(unsigned tid);
/** Sets the next NPC of a specific thread. */
void setNextNPC(uint64_t val, unsigned tid);
/** Add Destination Register To Dependency Maps */
//void addToRegDepMap(DynInstPtr &inst);
/** Function to add instruction onto the head of the list of the
* instructions. Used when new instructions are fetched.
*/
ListIt addInst(DynInstPtr &inst);
/** Function to tell the CPU that an instruction has completed. */
void instDone(DynInstPtr inst, unsigned tid);
/** Add Instructions to the CPU Remove List*/
void addToRemoveList(DynInstPtr &inst);
/** Remove an instruction from CPU */
void removeInst(DynInstPtr &inst);
/** Remove all instructions younger than the given sequence number. */
void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid);
/** Removes the instruction pointed to by the iterator. */
inline void squashInstIt(const ListIt &instIt, const unsigned &tid);
/** Cleans up all instructions on the instruction remove list. */
void cleanUpRemovedInsts();
/** Cleans up all instructions on the request remove list. */
void cleanUpRemovedReqs();
/** Cleans up all instructions on the CPU event remove list. */
void cleanUpRemovedEvents();
/** Debug function to print all instructions on the list. */
void dumpInsts();
/** Translates instruction requestion in syscall emulation mode. */
Fault translateInstReq(RequestPtr &req, Thread *thread)
{
return thread->getProcessPtr()->pTable->translate(req);
}
/** Translates data read request in syscall emulation mode. */
Fault translateDataReadReq(RequestPtr &req, Thread *thread)
{
return thread->getProcessPtr()->pTable->translate(req);
}
/** Translates data write request in syscall emulation mode. */
Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
{
return thread->getProcessPtr()->pTable->translate(req);
}
/** Forwards an instruction read to the appropriate data
* resource (indexes into Resource Pool thru "dataPortIdx")
*/
Fault read(DynInstPtr inst);
/** Forwards an instruction write. to the appropriate data
* resource (indexes into Resource Pool thru "dataPortIdx")
*/
Fault write(DynInstPtr inst);
/** Executes a syscall.*/
void syscall(int64_t callnum, int tid);
/** Gets a syscall argument. */
IntReg getSyscallArg(int i, int tid);
/** Used to shift args for indirect syscall. */
void setSyscallArg(int i, IntReg val, int tid);
/** Sets the return value of a syscall. */
void setSyscallReturn(SyscallReturn return_value, int tid);
public:
/** Per-Thread List of all the instructions in flight. */
std::list<DynInstPtr> instList[ThePipeline::MaxThreads];
/** List of all the instructions that will be removed at the end of this
* cycle.
*/
std::queue<ListIt> removeList;
/** List of all the resource requests that will be removed at the end of this
* cycle.
*/
std::queue<ResourceRequest*> reqRemoveList;
/** List of all the cpu event requests that will be removed at the end of
* the current cycle.
*/
std::queue<Event*> cpuEventRemoveList;
#ifdef DEBUG
/** Debug structure to keep track of the sequence numbers still in
* flight.
*/
std::set<InstSeqNum> snList;
#endif
/** Records if instructions need to be removed this cycle due to
* being retired or squashed.
*/
bool removeInstsThisCycle;
/** True if there is non-speculative Inst Active In Pipeline. Lets any
* execution unit know, NOT to execute while the instruction is active.
*/
bool nonSpecInstActive[ThePipeline::MaxThreads];
/** Instruction Seq. Num of current non-speculative instruction. */
InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads];
/** Instruction Seq. Num of last instruction squashed in pipeline */
InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
/** Last Cycle that the CPU squashed instruction end. */
Tick lastSquashCycle[ThePipeline::MaxThreads];
std::list<unsigned> fetchPriorityList;
/** Rename Map for architectural-to-physical register mappings.
* In a In-order processor, the mapping is fixed
* (e.g. Thread 1: 0-31, Thread 1: 32-63, etc.)
* In a Out-of-Order processor, this is used to maintain
* sequential consistency (?right word here?).
*/
RenameMap renameMap[ThePipeline::MaxThreads];
protected:
/** Active Threads List */
std::list<unsigned> activeThreads;
/** Current Threads List */
std::list<unsigned> currentThreads;
/** Suspended Threads List */
std::list<unsigned> suspendedThreads;
/** Thread Status Functions (Unused Currently) */
bool isThreadInCPU(unsigned tid);
bool isThreadActive(unsigned tid);
bool isThreadSuspended(unsigned tid);
void addToCurrentThreads(unsigned tid);
void removeFromCurrentThreads(unsigned tid);
private:
/** The activity recorder; used to tell if the CPU has any
* activity remaining or if it can go to idle and deschedule
* itself.
*/
ActivityRecorder activityRec;
public:
void readFunctional(Addr addr, uint32_t &buffer);
/** Number of Active Threads in the CPU */
int numActiveThreads() { return activeThreads.size(); }
/** Records that there was time buffer activity this cycle. */
void activityThisCycle() { activityRec.activity(); }
/** Changes a stage's status to active within the activity recorder. */
void activateStage(const int idx)
{ activityRec.activateStage(idx); }
/** Changes a stage's status to inactive within the activity recorder. */
void deactivateStage(const int idx)
{ activityRec.deactivateStage(idx); }
/** Wakes the CPU, rescheduling the CPU if it's not already active. */
void wakeCPU();
/** Gets a free thread id. Use if thread ids change across system. */
int getFreeTid();
// LL/SC debug functionality
unsigned stCondFails;
unsigned readStCondFailures() { return stCondFails; }
unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; }
public:
/** Returns a pointer to a thread context. */
ThreadContext *tcBase(unsigned tid = 0)
{
return thread[tid]->getTC();
}
/** The global sequence number counter. */
InstSeqNum globalSeqNum[ThePipeline::MaxThreads];
/** The global event number counter. */
InstSeqNum cpuEventNum;
/** Counter of how many stages have completed switching out. */
int switchCount;
/** Pointers to all of the threads in the CPU. */
std::vector<Thread *> thread;
/** Pointer to the icache interface. */
MemInterface *icacheInterface;
/** Pointer to the dcache interface. */
MemInterface *dcacheInterface;
/** Whether or not the CPU should defer its registration. */
bool deferRegistration;
/** Per-Stage Instruction Tracing */
bool stageTracing;
/** Is there a context switch pending? */
bool contextSwitch;
/** Threads Scheduled to Enter CPU */
std::list<int> cpuWaitList;
/** The cycle that the CPU was last running, used for statistics. */
Tick lastRunningCycle;
/** Number of Threads the CPU can process */
unsigned numThreads;
/** Number of Virtual Processors the CPU can process */
unsigned numVirtProcs;
/** Update Thread , used for statistic purposes*/
inline void tickThreadStats();
/** Per-Thread Tick */
Stats::Vector<> threadCycles;
/** Tick for SMT */
Stats::Scalar<> smtCycles;
/** Stat for total number of times the CPU is descheduled. */
Stats::Scalar<> timesIdled;
/** Stat for total number of cycles the CPU spends descheduled. */
Stats::Scalar<> idleCycles;
/** Stat for the number of committed instructions per thread. */
Stats::Vector<> committedInsts;
/** Stat for the number of committed instructions per thread. */
Stats::Vector<> smtCommittedInsts;
/** Stat for the total number of committed instructions. */
Stats::Scalar<> totalCommittedInsts;
/** Stat for the CPI per thread. */
Stats::Formula cpi;
/** Stat for the SMT-CPI per thread. */
Stats::Formula smtCpi;
/** Stat for the total CPI. */
Stats::Formula totalCpi;
/** Stat for the IPC per thread. */
Stats::Formula ipc;
/** Stat for the total IPC. */
Stats::Formula smtIpc;
/** Stat for the total IPC. */
Stats::Formula totalIpc;
};
#endif // __CPU_O3_CPU_HH__

View file

@ -0,0 +1,251 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "base/str.hh"
#include "cpu/inorder/first_stage.hh"
#include "cpu/inorder/resources/resource_list.hh"
#include "cpu/inorder/resource_pool.hh"
#include "cpu/inorder/cpu.hh"
#include "params/InOrderTrace.hh"
using namespace std;
using namespace ThePipeline;
FirstStage::FirstStage(Params *params, unsigned stage_num)
: PipelineStage(params, stage_num)
{
for(int tid=0; tid < this->numThreads; tid++) {
stageStatus[tid] = Running;
}
numFetchingThreads = 1;
fetchPolicy = RoundRobin;
}
void
FirstStage::setCPU(InOrderCPU *cpu_ptr)
{
cpu = cpu_ptr;
fetchPriorityList = &cpu->fetchPriorityList;
DPRINTF(InOrderStage, "Set CPU pointer.\n");
}
void
FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid)
{
// Set status to squashing.
//stageStatus[tid] = Squashing;
// Clear the instruction list and skid buffer in case they have any
// insts in them.
DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n");
while (!insts[tid].empty()) {
if (insts[tid].front()->seqNum <= squash_seq_num) {
DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= "
"squashing seqNum %i.\n",
tid,
insts[tid].front()->seqNum,
squash_seq_num);
DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming "
"instructions before delay slot [sn:%i]. %i insts"
"left.\n", tid, squash_seq_num,
insts[tid].size());
break;
}
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
tid, insts[tid].front()->seqNum, insts[tid].front()->PC);
insts[tid].pop();
}
// Now that squash has propagated to the first stage,
// Alert CPU to remove instructions from the CPU instruction list.
// @todo: Move this to the CPU object.
cpu->removeInstsUntil(squash_seq_num, tid);
}
void
FirstStage::processStage(bool &status_change)
{
list<unsigned>::iterator threads = (*activeThreads).begin();
//Check stall and squash signals.
while (threads != (*activeThreads).end()) {
unsigned tid = *threads++;
status_change = checkSignalsAndUpdate(tid) || status_change;
}
for (int threadFetched = 0; threadFetched < numFetchingThreads;
threadFetched++) {
int tid = getFetchingThread(fetchPolicy);
if (tid >= 0) {
DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
processThread(status_change, tid);
} else {
DPRINTF(InOrderStage, "No more threads to fetch from.\n");
}
}
}
//@TODO: Note in documentation, that when you make a pipeline stage change, then
//make sure you change the first stage too
void
FirstStage::processInsts(unsigned tid)
{
bool all_reqs_completed = true;
for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToNextStage(); insts_fetched++) {
DynInstPtr inst;
bool new_inst = false;
if (!insts[tid].empty()) {
inst = insts[tid].front();
} else {
// Get new instruction.
new_inst = true;
inst = new InOrderDynInst(cpu,
cpu->thread[tid],
cpu->nextInstSeqNum(tid),
tid);
#if TRACING_ON
inst->traceData =
tracer->getInstRecord(ThePipeline::NumStages,
cpu->stageTracing,
cpu->thread[tid]->getTC());
#endif // TRACING_ON
DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n",
inst->readTid(),
inst->seqNum,
0/*inst->curCount()*/);
// Add instruction to the CPU's list of instructions.
inst->setInstListIt(cpu->addInst(inst));
DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n",
inst->readTid(),
inst->seqNum,
0/*inst->curCount()*/);
// Create Front-End Resource Schedule For Instruction
ThePipeline::createFrontEndSchedule(inst);
}
// Don't let instruction pass to next stage if it hasnt completed
// all of it's requests for this stage.
all_reqs_completed = processInstSchedule(inst);
if (!all_reqs_completed) {
if (new_inst) {
DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all "
"requests for this stage. Keep in stage inst. "
"list.\n", tid, inst->seqNum);
insts[tid].push(inst);
}
break;
} else if (!insts[tid].empty()){
insts[tid].pop();
}
sendInstToNextStage(inst);
//++stageProcessedInsts;
}
// Record that stage has written to the time buffer for activity
// tracking.
if (toNextStageIndex) {
wroteToTimeBuffer = true;
}
}
int
FirstStage::getFetchingThread(FetchPriority &fetch_priority)
{
if (numThreads > 1) {
switch (fetch_priority) {
case SingleThread:
return 0;
case RoundRobin:
return roundRobin();
default:
return -1;
}
} else {
int tid = *((*activeThreads).begin());
if (stageStatus[tid] == Running ||
stageStatus[tid] == Idle) {
return tid;
} else {
return -1;
}
}
}
int
FirstStage::roundRobin()
{
list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin();
list<unsigned>::iterator end = (*fetchPriorityList).end();
int high_pri;
while (pri_iter != end) {
high_pri = *pri_iter;
assert(high_pri <= numThreads);
if (stageStatus[high_pri] == Running ||
stageStatus[high_pri] == Idle) {
(*fetchPriorityList).erase(pri_iter);
(*fetchPriorityList).push_back(high_pri);
return high_pri;
}
pri_iter++;
}
return -1;
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_FIRST_STAGE_HH__
#define __CPU_INORDER_FIRST_STAGE_HH__
#include <queue>
#include <vector>
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/comm.hh"
#include "cpu/inorder/params.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/pipeline_stage.hh"
class InOrderCPU;
class FirstStage : public PipelineStage {
public:
FirstStage(ThePipeline::Params *params, unsigned stage_num);
/** Set Pointer to CPU */
void setCPU(InOrderCPU *cpu_ptr);
/** Evaluate Stage Info. & Execute Stage */
void processStage(bool &status_change);
/** Process All Instructions Available */
void processInsts(unsigned tid);
/** Squash Instructions Above a Seq. Num */
void squash(InstSeqNum squash_seq_num, unsigned tid);
/** There are no insts. coming from previous stages, so there is
* no need to sort insts here
*/
void sortInsts() {}
/** There are no skidBuffers for the first stage. So
* just use an empty function.
*/
void skidInsert(unsigned tid) { }
/** The number of fetching threads in the CPU */
int numFetchingThreads;
//@TODO: Add fetch priority information to a resource class...
/** Fetching Policy, Add new policies here.*/
enum FetchPriority {
SingleThread,
RoundRobin
};
/** Fetch policy. */
FetchPriority fetchPolicy;
/** List that has the threads organized by priority. */
std::list<unsigned> *fetchPriorityList;
/** Return the next fetching thread */
int getFetchingThread(FetchPriority &fetch_priority);
/** Return next thred given Round Robin Policy for Thread Fetching */
int roundRobin();
};
#endif // __CPU_INORDER_FIRST_STAGE_HH__

View file

@ -0,0 +1,61 @@
/*
* 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/base.hh"
#include "cpu/inst_seq.hh"
#include "cpu/static_inst.hh"
#include "cpu/inorder/cpu.hh"
//#include "cpu/inorder/params.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "params/InOrderCPU.hh"
InOrderCPU *
InOrderCPUParams::create()
{
int actual_num_threads =
(numThreads >= workload.size()) ? numThreads : workload.size();
if (workload.size() == 0) {
fatal("Must specify at least one workload!");
}
numThreads = actual_num_threads;
instShiftAmt = 2;
return new InOrderCPU(this);
}

View file

@ -0,0 +1,780 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <iostream>
#include <set>
#include <string>
#include <sstream>
#include "base/cprintf.hh"
#include "base/trace.hh"
#include "arch/faults.hh"
#include "cpu/exetrace.hh"
#include "mem/request.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC,
Addr pred_PC, InstSeqNum seq_num,
InOrderCPU *cpu)
: staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu)
{
seqNum = seq_num;
PC = inst_PC;
nextPC = PC + sizeof(MachInst);
nextNPC = nextPC + sizeof(MachInst);
predPC = pred_PC;
initVars();
}
InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
InOrderThreadState *state,
InstSeqNum seq_num,
unsigned tid)
: traceData(NULL), cpu(cpu)
{
seqNum = seq_num;
thread = state;
threadNumber = tid;
initVars();
}
InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst)
: staticInst(_staticInst), traceData(NULL)
{
seqNum = 0;
initVars();
}
InOrderDynInst::InOrderDynInst()
: traceData(NULL), cpu(cpu)
{ initVars(); }
int InOrderDynInst::instcount = 0;
void
InOrderDynInst::setMachInst(ExtMachInst machInst)
{
staticInst = StaticInst::decode(machInst, PC);
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
}
void
InOrderDynInst::initVars()
{
req = NULL;
effAddr = 0;
physEffAddr = 0;
readyRegs = 0;
nextStage = 0;
nextInstStageNum = 0;
for(int i = 0; i < MaxInstDestRegs; i++)
instResult[i].val.integer = 0;
status.reset();
memAddrReady = false;
eaCalcDone = false;
memOpDone = false;
predictTaken = false;
procDelaySlotOnMispred = false;
lqIdx = -1;
sqIdx = -1;
// Also make this a parameter, or perhaps get it from xc or cpu.
asid = 0;
virtProcNumber = 0;
// Initialize the fault to be NoFault.
fault = NoFault;
// Make sure to have the renamed register entries set to the same
// as the normal register entries. It will allow the IQ to work
// without any modifications.
if (this->staticInst) {
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
}
// Update Instruction Count for this instruction
++instcount;
if (instcount > 500) {
fatal("Number of Active Instructions in CPU is too high. "
"(Not Dereferencing Ptrs. Correctly?)\n");
}
DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n",
threadNumber, seqNum, instcount);
#ifdef DEBUG
cpu->snList.insert(seqNum);
#endif
}
InOrderDynInst::~InOrderDynInst()
{
if (req) {
delete req;
}
if (traceData) {
delete traceData;
}
fault = NoFault;
--instcount;
deleteStages();
DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n",
threadNumber, seqNum, instcount);
#ifdef DEBUG
cpu->snList.erase(seqNum);
#endif
}
void
InOrderDynInst::setStaticInst(StaticInstPtr &static_inst)
{
this->staticInst = static_inst;
// Make sure to have the renamed register entries set to the same
// as the normal register entries. It will allow the IQ to work
// without any modifications.
if (this->staticInst) {
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
}
}
Fault
InOrderDynInst::execute()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
// (specifically for instructions that have side-effects that use
// the TC). Fix this.
bool in_syscall = this->thread->inSyscall;
this->thread->inSyscall = true;
this->fault = this->staticInst->execute(this, this->traceData);
this->thread->inSyscall = in_syscall;
return this->fault;
}
Fault
InOrderDynInst::initiateAcc()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
// (specifically for instructions that have side-effects that use
// the TC). Fix this.
bool in_syscall = this->thread->inSyscall;
this->thread->inSyscall = true;
this->fault = this->staticInst->initiateAcc(this, this->traceData);
this->thread->inSyscall = in_syscall;
return this->fault;
}
Fault
InOrderDynInst::completeAcc(Packet *pkt)
{
this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
return this->fault;
}
InstStage *InOrderDynInst::addStage()
{
this->currentInstStage = new InstStage(this, nextInstStageNum++);
instStageList.push_back( this->currentInstStage );
return this->currentInstStage;
}
InstStage *InOrderDynInst::addStage(int stage_num)
{
nextInstStageNum = stage_num;
return InOrderDynInst::addStage();
}
void InOrderDynInst::deleteStages() {
std::list<InstStage*>::iterator list_it = instStageList.begin();
std::list<InstStage*>::iterator list_end = instStageList.end();
while(list_it != list_end) {
delete *list_it;
list_it++;
}
}
Fault
InOrderDynInst::calcEA()
{
return staticInst->eaCompInst()->execute(this, this->traceData);
}
Fault
InOrderDynInst::memAccess()
{
//return staticInst->memAccInst()->execute(this, this->traceData);
return initiateAcc( );
}
void
InOrderDynInst::syscall(int64_t callnum)
{
cpu->syscall(callnum, this->threadNumber);
}
void
InOrderDynInst::prefetch(Addr addr, unsigned flags)
{
// This is the "functional" implementation of prefetch. Not much
// happens here since prefetches don't affect the architectural
// state.
/*
// Generate a MemReq so we can translate the effective address.
MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags);
req->asid = asid;
// Prefetches never cause faults.
fault = NoFault;
// note this is a local, not InOrderDynInst::fault
Fault trans_fault = cpu->translateDataReadReq(req);
if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) {
// It's a valid address to cacheable space. Record key MemReq
// parameters so we can generate another one just like it for
// the timing access without calling translate() again (which
// might mess up the TLB).
effAddr = req->vaddr;
physEffAddr = req->paddr;
memReqFlags = req->flags;
} else {
// Bogus address (invalid or uncacheable space). Mark it by
// setting the eff_addr to InvalidAddr.
effAddr = physEffAddr = MemReq::inval_addr;
}
if (traceData) {
traceData->setAddr(addr);
}
*/
}
void
InOrderDynInst::writeHint(Addr addr, int size, unsigned flags)
{
// Not currently supported.
}
/**
* @todo Need to find a way to get the cache block size here.
*/
Fault
InOrderDynInst::copySrcTranslate(Addr src)
{
// Not currently supported.
return NoFault;
}
/**
* @todo Need to find a way to get the cache block size here.
*/
Fault
InOrderDynInst::copy(Addr dest)
{
// Not currently supported.
return NoFault;
}
void
InOrderDynInst::releaseReq(ResourceRequest* req)
{
std::list<ResourceRequest*>::iterator list_it = reqList.begin();
std::list<ResourceRequest*>::iterator list_end = reqList.end();
while(list_it != list_end) {
if((*list_it)->getResIdx() == req->getResIdx() &&
(*list_it)->getSlot() == req->getSlot()) {
DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n",
threadNumber, seqNum, req->res->name());
reqList.erase(list_it);
return;
}
list_it++;
}
panic("Releasing Res. Request That Isnt There!\n");
}
/** Records an integer source register being set to a value. */
void
InOrderDynInst::setIntSrc(int idx, uint64_t val)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n",
threadNumber, seqNum, idx, val);
instSrc[idx].integer = val;
}
/** Records an fp register being set to a value. */
void
InOrderDynInst::setFloatSrc(int idx, FloatReg val, int width)
{
if (width == 32)
instSrc[idx].fp = val;
else if (width == 64)
instSrc[idx].dbl = val;
else
panic("Unsupported width!");
}
/** Records an fp register being set to an integer value. */
void
InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val)
{
instSrc[idx].integer = val;
}
/** Reads a integer register. */
IntReg
InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, unsigned tid)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
threadNumber, seqNum, idx, instSrc[idx].integer);
return instSrc[idx].integer;
}
/** Reads a FP register. */
FloatReg
InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx, int width)
{
return instSrc[idx].fp;
}
/** Reads a FP register as a integer. */
FloatRegBits
InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx, int width)
{
return instSrc[idx].integer;
}
/** Reads a miscellaneous register. */
MiscReg
InOrderDynInst::readMiscReg(int misc_reg)
{
return this->cpu->readMiscReg(misc_reg, threadNumber);
}
/** Reads a misc. register, including any side-effects the read
* might have as defined by the architecture.
*/
MiscReg
InOrderDynInst::readMiscRegNoEffect(int misc_reg)
{
return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber);
}
/** Reads a miscellaneous register. */
MiscReg
InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx)
{
return this->cpu->readMiscRegNoEffect(
si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
this->threadNumber);
}
/** Reads a misc. register, including any side-effects the read
* might have as defined by the architecture.
*/
MiscReg
InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx)
{
return this->cpu->readMiscReg(
si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
this->threadNumber);
}
/** Sets a misc. register. */
void
InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
{
instResult[si->destRegIdx(idx)].val.integer = val;
instResult[si->destRegIdx(idx)].tick = curTick;
this->cpu->setMiscRegNoEffect(
si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
val, this->threadNumber);
}
/** Sets a misc. register, including any side-effects the write
* might have as defined by the architecture.
*/
void
InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
const MiscReg &val)
{
instResult[si->destRegIdx(idx)].val.integer = val;
instResult[si->destRegIdx(idx)].tick = curTick;
this->cpu->setMiscReg(
si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
val, this->threadNumber);
}
MiscReg
InOrderDynInst::readRegOtherThread(unsigned reg_idx, int tid)
{
if (tid == -1) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
}
if (reg_idx < FP_Base_DepTag) { // Integer Register File
return this->cpu->readIntReg(reg_idx, tid);
} else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
reg_idx -= FP_Base_DepTag;
return this->cpu->readFloatRegBits(reg_idx, tid);
} else {
reg_idx -= Ctrl_Base_DepTag;
return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File
}
}
/** Sets a Integer register. */
void
InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
instResult[idx].val.integer = val;
instResult[idx].tick = curTick;
}
/** Sets a FP register. */
void
InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width)
{
if (width == 32)
instResult[idx].val.fp = val;
else if (width == 64)
instResult[idx].val.dbl = val;
else
panic("Unsupported Floating Point Width!");
instResult[idx].tick = curTick;
}
/** Sets a FP register as a integer. */
void
InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
FloatRegBits val, int width)
{
instResult[idx].val.integer = val;
instResult[idx].tick = curTick;
}
/** Sets a misc. register. */
/* Alter this when wanting to *speculate* on Miscellaneous registers */
void
InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber);
}
/** Sets a misc. register, including any side-effects the write
* might have as defined by the architecture.
*/
/* Alter this if/when wanting to *speculate* on Miscellaneous registers */
void
InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
{
this->cpu->setMiscReg(misc_reg, val, threadNumber);
}
void
InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val, int tid)
{
if (tid == -1) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
}
if (reg_idx < FP_Base_DepTag) { // Integer Register File
this->cpu->setIntReg(reg_idx, val, tid);
} else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
reg_idx -= FP_Base_DepTag;
this->cpu->setFloatRegBits(reg_idx, val, tid);
} else {
reg_idx -= Ctrl_Base_DepTag;
this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File
}
}
void
InOrderDynInst::deallocateContext(int thread_num)
{
this->cpu->deallocateContext(thread_num);
}
void
InOrderDynInst::enableVirtProcElement(unsigned vpe)
{
this->cpu->enableVirtProcElement(vpe);
}
void
InOrderDynInst::disableVirtProcElement(unsigned vpe)
{
this->cpu->disableVirtProcElement(threadNumber, vpe);
}
void
InOrderDynInst::enableMultiThreading(unsigned vpe)
{
this->cpu->enableMultiThreading(vpe);
}
void
InOrderDynInst::disableMultiThreading(unsigned vpe)
{
this->cpu->disableMultiThreading(threadNumber, vpe);
}
void
InOrderDynInst::setThreadRescheduleCondition(uint32_t cond)
{
this->cpu->setThreadRescheduleCondition(cond);
}
template<class T>
inline Fault
InOrderDynInst::read(Addr addr, T &data, unsigned flags)
{
return cpu->read(this);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
Fault
InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags);
template
Fault
InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags);
template
Fault
InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags);
template
Fault
InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags);
#endif //DOXYGEN_SHOULD_SKIP_THIS
template<>
Fault
InOrderDynInst::read(Addr addr, double &data, unsigned flags)
{
return read(addr, *(uint64_t*)&data, flags);
}
template<>
Fault
InOrderDynInst::read(Addr addr, float &data, unsigned flags)
{
return read(addr, *(uint32_t*)&data, flags);
}
template<>
Fault
InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags)
{
return read(addr, (uint32_t&)data, flags);
}
template<class T>
inline Fault
InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
//memcpy(memData, gtoh(data), sizeof(T));
storeData = data;
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n",
threadNumber, seqNum, memData);
return cpu->write(this);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
Fault
InOrderDynInst::write(uint64_t data, Addr addr,
unsigned flags, uint64_t *res);
template
Fault
InOrderDynInst::write(uint32_t data, Addr addr,
unsigned flags, uint64_t *res);
template
Fault
InOrderDynInst::write(uint16_t data, Addr addr,
unsigned flags, uint64_t *res);
template
Fault
InOrderDynInst::write(uint8_t data, Addr addr,
unsigned flags, uint64_t *res);
#endif //DOXYGEN_SHOULD_SKIP_THIS
template<>
Fault
InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res)
{
return write(*(uint64_t*)&data, addr, flags, res);
}
template<>
Fault
InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res)
{
return write(*(uint32_t*)&data, addr, flags, res);
}
template<>
Fault
InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
{
return write((uint32_t)data, addr, flags, res);
}
void
InOrderDynInst::dump()
{
cprintf("T%d : %#08d `", threadNumber, PC);
cout << staticInst->disassemble(PC);
cprintf("'\n");
}
void
InOrderDynInst::dump(std::string &outstring)
{
std::ostringstream s;
s << "T" << threadNumber << " : 0x" << PC << " "
<< staticInst->disassemble(PC);
outstring = s.str();
}
#define NOHASH
#ifndef NOHASH
#include "base/hashmap.hh"
unsigned int MyHashFunc(const InOrderDynInst *addr)
{
unsigned a = (unsigned)addr;
unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
return hash;
}
typedef m5::hash_map<const InOrderDynInst *, const InOrderDynInst *, MyHashFunc>
my_hash_t;
my_hash_t thishash;
#endif
#ifdef DEBUG
void
InOrderDynInst::dumpSNList()
{
std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin();
int count = 0;
while (sn_it != cpu->snList.end()) {
cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it));
count++;
sn_it++;
}
}
#endif

View file

@ -0,0 +1,975 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
* Korey Sewell
*/
#ifndef __CPU_INORDER_DYN_INST_HH__
#define __CPU_INORDER_DYN_INST_HH__
#include <bitset>
#include <list>
#include <string>
#include "arch/faults.hh"
#include "base/fast_alloc.hh"
#include "base/trace.hh"
#include "cpu/inorder/inorder_trace.hh"
#include "config/full_system.hh"
#include "cpu/thread_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/inst_seq.hh"
#include "cpu/op_class.hh"
#include "cpu/static_inst.hh"
#include "cpu/inorder/thread_state.hh"
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "mem/packet.hh"
#include "sim/system.hh"
/**
* @file
* Defines a dynamic instruction context for a inorder CPU model.
*/
// Forward declaration.
class StaticInstPtr;
class ResourceRequest;
class InOrderDynInst : public FastAlloc, public RefCounted
{
public:
// Binary machine instruction type.
typedef TheISA::MachInst MachInst;
// Extended machine instruction type
typedef TheISA::ExtMachInst ExtMachInst;
// Logical register index type.
typedef TheISA::RegIndex RegIndex;
// Integer register type.
typedef TheISA::IntReg IntReg;
// Floating point register type.
typedef TheISA::FloatReg FloatReg;
// Floating point register type.
typedef TheISA::MiscReg MiscReg;
typedef short int PhysRegIndex;
/** The refcounted DynInst pointer to be used. In most cases this is
* what should be used, and not DynInst*.
*/
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
// The list of instructions iterator type.
typedef std::list<DynInstPtr>::iterator ListIt;
enum {
MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs
MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs
};
public:
/** BaseDynInst constructor given a binary instruction.
* @param inst The binary instruction.
* @param PC The PC of the instruction.
* @param pred_PC The predicted next PC.
* @param seq_num The sequence number of the instruction.
* @param cpu Pointer to the instruction's CPU.
*/
InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num,
InOrderCPU *cpu);
/** BaseDynInst constructor given a binary instruction.
* @param seq_num The sequence number of the instruction.
* @param cpu Pointer to the instruction's CPU.
* NOTE: Must set Binary Instrution through Member Function
*/
InOrderDynInst(InOrderCPU *cpu, InOrderThreadState *state, InstSeqNum seq_num,
unsigned tid);
/** BaseDynInst constructor given a StaticInst pointer.
* @param _staticInst The StaticInst for this BaseDynInst.
*/
InOrderDynInst(StaticInstPtr &_staticInst);
/** Skeleton Constructor. */
InOrderDynInst();
/** InOrderDynInst destructor. */
~InOrderDynInst();
public:
/** The sequence number of the instruction. */
InstSeqNum seqNum;
/** The sequence number of the instruction. */
InstSeqNum bdelaySeqNum;
enum Status {
RegDepMapEntry, /// Instruction has been entered onto the RegDepMap
IqEntry, /// Instruction is in the IQ
RobEntry, /// Instruction is in the ROB
LsqEntry, /// Instruction is in the LSQ
Completed, /// Instruction has completed
ResultReady, /// Instruction has its result
CanIssue, /// Instruction can issue and execute
Issued, /// Instruction has issued
Executed, /// Instruction has executed
CanCommit, /// Instruction can commit
AtCommit, /// Instruction has reached commit
Committed, /// Instruction has committed
Squashed, /// Instruction is squashed
SquashedInIQ, /// Instruction is squashed in the IQ
SquashedInLSQ, /// Instruction is squashed in the LSQ
SquashedInROB, /// Instruction is squashed in the ROB
RecoverInst, /// Is a recover instruction
BlockingInst, /// Is a blocking instruction
ThreadsyncWait, /// Is a thread synchronization instruction
SerializeBefore, /// Needs to serialize on
/// instructions ahead of it
SerializeAfter, /// Needs to serialize instructions behind it
SerializeHandled, /// Serialization has been handled
NumStatus
};
/** The status of this BaseDynInst. Several bits can be set. */
std::bitset<NumStatus> status;
/** The thread this instruction is from. */
short threadNumber;
/** data address space ID, for loads & stores. */
short asid;
/** The virtual processor number */
short virtProcNumber;
/** The StaticInst used by this BaseDynInst. */
StaticInstPtr staticInst;
/** InstRecord that tracks this instructions. */
Trace::InOrderTraceRecord *traceData;
/** Pointer to the Impl's CPU object. */
InOrderCPU *cpu;
/** Pointer to the thread state. */
InOrderThreadState *thread;
/** The kind of fault this instruction has generated. */
Fault fault;
/** The memory request. */
Request *req;
/** Pointer to the data for the memory access. */
uint8_t *memData;
/** Data used for a store for operation. */
uint64_t loadData;
/** Data used for a store for operation. */
uint64_t storeData;
/** The resource schedule for this inst */
ThePipeline::ResSchedule resSched;
/** List of active resource requests for this instruction */
std::list<ResourceRequest*> reqList;
/** The effective virtual address (lds & stores only). */
Addr effAddr;
/** The effective physical address. */
Addr physEffAddr;
/** Effective virtual address for a copy source. */
Addr copySrcEffAddr;
/** Effective physical address for a copy source. */
Addr copySrcPhysEffAddr;
/** The memory request flags (from translation). */
unsigned memReqFlags;
/** How many source registers are ready. */
unsigned readyRegs;
/** An instruction src/dest has to be one of these types */
union InstValue {
uint64_t integer;
float fp;
double dbl;
};
/** Result of an instruction execution */
struct InstResult {
InstValue val;
Tick tick;
};
/** The source of the instruction; assumes for now that there's only one
* destination register.
*/
InstValue instSrc[MaxInstSrcRegs];
/** The result of the instruction; assumes for now that there's only one
* destination register.
*/
InstResult instResult[MaxInstDestRegs];
/** PC of this instruction. */
Addr PC;
/** Next non-speculative PC. It is not filled in at fetch, but rather
* once the target of the branch is truly known (either decode or
* execute).
*/
Addr nextPC;
/** Next next non-speculative PC. It is not filled in at fetch, but rather
* once the target of the branch is truly known (either decode or
* execute).
*/
Addr nextNPC;
/** Predicted next PC. */
Addr predPC;
/** Address to fetch from */
Addr fetchAddr;
/** Address to get/write data from/to */
Addr memAddr;
/** Whether or not the source register is ready.
* @todo: Not sure this should be here vs the derived class.
*/
bool _readySrcRegIdx[MaxInstSrcRegs];
/** Physical register index of the destination registers of this
* instruction.
*/
PhysRegIndex _destRegIdx[MaxInstDestRegs];
/** Physical register index of the source registers of this
* instruction.
*/
PhysRegIndex _srcRegIdx[MaxInstSrcRegs];
/** Physical register index of the previous producers of the
* architected destinations.
*/
PhysRegIndex _prevDestRegIdx[MaxInstDestRegs];
int nextStage;
/* vars to keep track of InstStage's - used for resource sched defn */
int nextInstStageNum;
ThePipeline::InstStage *currentInstStage;
std::list<ThePipeline::InstStage*> instStageList;
private:
/** Function to initialize variables in the constructors. */
void initVars();
public:
Tick memTime;
////////////////////////////////////////////////////////////
//
// BASE INSTRUCTION INFORMATION.
//
////////////////////////////////////////////////////////////
void setMachInst(ExtMachInst inst);
/** Sets the StaticInst. */
void setStaticInst(StaticInstPtr &static_inst);
/** Sets the sequence number. */
void setSeqNum(InstSeqNum seq_num) { seqNum = seq_num; }
/** Sets the ASID. */
void setASID(short addr_space_id) { asid = addr_space_id; }
/** Reads the thread id. */
short readTid() { return threadNumber; }
/** Sets the thread id. */
void setTid(unsigned tid) { threadNumber = tid; }
void setVpn(int id) { virtProcNumber = id; }
int readVpn() { return virtProcNumber; }
/** Sets the pointer to the thread state. */
void setThreadState(InOrderThreadState *state) { thread = state; }
/** Returns the thread context. */
ThreadContext *tcBase() { return thread->getTC(); }
/** Returns the fault type. */
Fault getFault() { return fault; }
////////////////////////////////////////////////////////////
//
// INSTRUCTION TYPES - Forward checks to StaticInst object.
//
////////////////////////////////////////////////////////////
bool isNop() const { return staticInst->isNop(); }
bool isMemRef() const { return staticInst->isMemRef(); }
bool isLoad() const { return staticInst->isLoad(); }
bool isStore() const { return staticInst->isStore(); }
bool isStoreConditional() const
{ return staticInst->isStoreConditional(); }
bool isInstPrefetch() const { return staticInst->isInstPrefetch(); }
bool isDataPrefetch() const { return staticInst->isDataPrefetch(); }
bool isCopy() const { return staticInst->isCopy(); }
bool isInteger() const { return staticInst->isInteger(); }
bool isFloating() const { return staticInst->isFloating(); }
bool isControl() const { return staticInst->isControl(); }
bool isCall() const { return staticInst->isCall(); }
bool isReturn() const { return staticInst->isReturn(); }
bool isDirectCtrl() const { return staticInst->isDirectCtrl(); }
bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); }
bool isCondCtrl() const { return staticInst->isCondCtrl(); }
bool isUncondCtrl() const { return staticInst->isUncondCtrl(); }
bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); }
bool isThreadSync() const { return staticInst->isThreadSync(); }
bool isSerializing() const { return staticInst->isSerializing(); }
bool isSerializeBefore() const
{ return staticInst->isSerializeBefore() || status[SerializeBefore]; }
bool isSerializeAfter() const
{ return staticInst->isSerializeAfter() || status[SerializeAfter]; }
bool isMemBarrier() const { return staticInst->isMemBarrier(); }
bool isWriteBarrier() const { return staticInst->isWriteBarrier(); }
bool isNonSpeculative() const { return staticInst->isNonSpeculative(); }
bool isQuiesce() const { return staticInst->isQuiesce(); }
bool isIprAccess() const { return staticInst->isIprAccess(); }
bool isUnverifiable() const { return staticInst->isUnverifiable(); }
/////////////////////////////////////////////
//
// RESOURCE SCHEDULING
//
/////////////////////////////////////////////
void setNextStage(int stage_num) { nextStage = stage_num; }
int getNextStage() { return nextStage; }
ThePipeline::InstStage *addStage();
ThePipeline::InstStage *addStage(int stage);
ThePipeline::InstStage *currentStage() { return currentInstStage; }
void deleteStages();
/** Add A Entry To Reource Schedule */
void addToSched(ThePipeline::ScheduleEntry* sched_entry)
{ resSched.push(sched_entry); }
/** Print Resource Schedule */
void printSched()
{
using namespace ThePipeline;
ResSchedule tempSched;
std::cerr << "\tInst. Res. Schedule: ";
while (!resSched.empty()) {
std::cerr << '\t' << resSched.top()->stageNum << "-"
<< resSched.top()->resNum << ", ";
tempSched.push(resSched.top());
resSched.pop();
}
std::cerr << std::endl;
resSched = tempSched;
}
/** Return Next Resource Stage To Be Used */
int nextResStage()
{
if (resSched.empty())
return -1;
else
return resSched.top()->stageNum;
}
/** Return Next Resource To Be Used */
int nextResource()
{
if (resSched.empty())
return -1;
else
return resSched.top()->resNum;
}
/** Remove & Deallocate a schedule entry */
void popSchedEntry()
{
if (!resSched.empty()) {
ThePipeline::ScheduleEntry* sked = resSched.top();
resSched.pop();
delete sked;
}
}
/** Release a Resource Request (Currently Unused) */
void releaseReq(ResourceRequest* req);
////////////////////////////////////////////
//
// INSTRUCTION EXECUTION
//
////////////////////////////////////////////
/** Returns the opclass of this instruction. */
OpClass opClass() const { return staticInst->opClass(); }
/** Executes the instruction.*/
Fault execute();
unsigned curResSlot;
unsigned getCurResSlot() { return curResSlot; }
void setCurResSlot(unsigned slot_num) { curResSlot = slot_num; }
/** Calls a syscall. */
void syscall(int64_t callnum);
void prefetch(Addr addr, unsigned flags);
void writeHint(Addr addr, int size, unsigned flags);
Fault copySrcTranslate(Addr src);
Fault copy(Addr dest);
////////////////////////////////////////////////////////////
//
// MULTITHREADING INTERFACE TO CPU MODELS
//
////////////////////////////////////////////////////////////
virtual void deallocateContext(int thread_num);
virtual void enableVirtProcElement(unsigned vpe);
virtual void disableVirtProcElement(unsigned vpe);
virtual void enableMultiThreading(unsigned vpe);
virtual void disableMultiThreading(unsigned vpe);
virtual void setThreadRescheduleCondition(uint32_t cond);
////////////////////////////////////////////////////////////
//
// PROGRAM COUNTERS - PC/NPC/NPC
//
////////////////////////////////////////////////////////////
/** Read the PC of this instruction. */
const Addr readPC() const { return PC; }
/** Sets the PC of this instruction. */
void setPC(Addr pc) { PC = pc; }
/** Returns the next PC. This could be the speculative next PC if it is
* called prior to the actual branch target being calculated.
*/
Addr readNextPC() { return nextPC; }
/** Set the next PC of this instruction (its actual target). */
void setNextPC(uint64_t val) { nextPC = val; }
/** Returns the next NPC. This could be the speculative next NPC if it is
* called prior to the actual branch target being calculated.
*/
Addr readNextNPC() { return nextNPC; }
/** Set the next PC of this instruction (its actual target). */
void setNextNPC(uint64_t val) { nextNPC = val; }
////////////////////////////////////////////////////////////
//
// BRANCH PREDICTION
//
////////////////////////////////////////////////////////////
/** Set the predicted target of this current instruction. */
void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; }
/** Returns the predicted target of the branch. */
Addr readPredTarg() { return predPC; }
/** Returns whether the instruction was predicted taken or not. */
bool predTaken() { return predictTaken; }
/** Returns whether the instruction mispredicted. */
bool mispredicted()
{
// Special case since a not-taken, cond. delay slot, effectively
// nullifies the delay slot instruction
if (isCondDelaySlot() && !predictTaken) {
return predPC != nextPC;
} else {
return predPC != nextNPC;
}
}
/** Returns whether the instruction mispredicted. */
bool mistargeted() { return predPC != nextNPC; }
/** Returns the branch target address. */
Addr branchTarget() const { return staticInst->branchTarget(PC); }
/** Checks whether or not this instruction has had its branch target
* calculated yet. For now it is not utilized and is hacked to be
* always false.
* @todo: Actually use this instruction.
*/
bool doneTargCalc() { return false; }
void setBranchPred(bool prediction) { predictTaken = prediction; }
int squashingStage;
bool predictTaken;
bool procDelaySlotOnMispred;
////////////////////////////////////////////
//
// MEMORY ACCESS
//
////////////////////////////////////////////
/**
* Does a read to a given address.
* @param addr The address to read.
* @param data The read's data is written into this parameter.
* @param flags The request's flags.
* @return Returns any fault due to the read.
*/
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
/**
* Does a write to a given address.
* @param data The data to be written.
* @param addr The address to write to.
* @param flags The request's flags.
* @param res The result of the write (for load locked/store conditionals).
* @return Returns any fault due to the write.
*/
template <class T>
Fault write(T data, Addr addr, unsigned flags,
uint64_t *res);
/** Initiates a memory access - Calculate Eff. Addr & Initiate Memory Access
* Only valid for memory operations.
*/
Fault initiateAcc();
/** Completes a memory access - Only valid for memory operations. */
Fault completeAcc(Packet *pkt);
/** Calculates Eff. Addr. part of a memory instruction. */
Fault calcEA();
/** Read Effective Address from instruction & do memory access */
Fault memAccess();
RequestPtr memReq;
bool memAddrReady;
bool validMemAddr()
{ return memAddrReady; }
void setMemAddr(Addr addr)
{ memAddr = addr; memAddrReady = true;}
void unsetMemAddr()
{ memAddrReady = false;}
Addr getMemAddr()
{ return memAddr; }
int getMemAccSize() { return staticInst->memAccSize(this); }
int getMemFlags() { return staticInst->memAccFlags(); }
/** Sets the effective address. */
void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; }
/** Returns the effective address. */
const Addr &getEA() const { return instEffAddr; }
/** Returns whether or not the eff. addr. calculation has been completed. */
bool doneEACalc() { return eaCalcDone; }
/** Returns whether or not the eff. addr. source registers are ready.
* Assume that src registers 1..n-1 are the ones that the
* EA calc depends on. (i.e. src reg 0 is the source of the data to be
* stored)
*/
bool eaSrcsReady()
{
for (int i = 1; i < numSrcRegs(); ++i) {
if (!_readySrcRegIdx[i])
return false;
}
return true;
}
//////////////////////////////////////////////////
//
// SOURCE-DESTINATION REGISTER INDEXING
//
//////////////////////////////////////////////////
/** Returns the number of source registers. */
int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
/** Returns the number of destination registers. */
int8_t numDestRegs() const { return staticInst->numDestRegs(); }
// the following are used to track physical register usage
// for machines with separate int & FP reg files
int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); }
int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); }
/** Returns the logical register index of the i'th destination register. */
RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); }
/** Returns the logical register index of the i'th source register. */
RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); }
//////////////////////////////////////////////////
//
// RENAME/PHYSICAL REGISTER FILE SUPPORT
//
//////////////////////////////////////////////////
/** Returns the physical register index of the i'th destination
* register.
*/
PhysRegIndex renamedDestRegIdx(int idx) const
{
return _destRegIdx[idx];
}
/** Returns the physical register index of the i'th source register. */
PhysRegIndex renamedSrcRegIdx(int idx) const
{
return _srcRegIdx[idx];
}
/** Returns the physical register index of the previous physical register
* that remapped to the same logical register index.
*/
PhysRegIndex prevDestRegIdx(int idx) const
{
return _prevDestRegIdx[idx];
}
/** Returns if a source register is ready. */
bool isReadySrcRegIdx(int idx) const
{
return this->_readySrcRegIdx[idx];
}
/** Records that one of the source registers is ready. */
void markSrcRegReady()
{
if (++readyRegs == numSrcRegs()) {
status.set(CanIssue);
}
}
/** Marks a specific register as ready. */
void markSrcRegReady(RegIndex src_idx)
{
_readySrcRegIdx[src_idx] = true;
markSrcRegReady();
}
/** Renames a destination register to a physical register. Also records
* the previous physical register that the logical register mapped to.
*/
void renameDestReg(int idx,
PhysRegIndex renamed_dest,
PhysRegIndex previous_rename)
{
_destRegIdx[idx] = renamed_dest;
_prevDestRegIdx[idx] = previous_rename;
}
/** Renames a source logical register to the physical register which
* has/will produce that logical register's result.
* @todo: add in whether or not the source register is ready.
*/
void renameSrcReg(int idx, PhysRegIndex renamed_src)
{
_srcRegIdx[idx] = renamed_src;
}
PhysRegIndex readDestRegIdx(int idx)
{
return _destRegIdx[idx];
}
void setDestRegIdx(int idx, PhysRegIndex dest_idx)
{
_destRegIdx[idx] = dest_idx;
}
int getDestIdxNum(PhysRegIndex dest_idx)
{
for (int i=0; i < staticInst->numDestRegs(); i++) {
if (_destRegIdx[i] == dest_idx)
return i;
}
return -1;
}
PhysRegIndex readSrcRegIdx(int idx)
{
return _srcRegIdx[idx];
}
void setSrcRegIdx(int idx, PhysRegIndex src_idx)
{
_srcRegIdx[idx] = src_idx;
}
int getSrcIdxNum(PhysRegIndex src_idx)
{
for (int i=0; i < staticInst->numSrcRegs(); i++) {
if (_srcRegIdx[i] == src_idx)
return i;
}
return -1;
}
////////////////////////////////////////////////////
//
// SOURCE-DESTINATION REGISTER VALUES
//
////////////////////////////////////////////////////
/** Functions that sets an integer or floating point
* source register to a value. */
void setIntSrc(int idx, uint64_t val);
void setFloatSrc(int idx, FloatReg val, int width = 32);
void setFloatRegBitsSrc(int idx, uint64_t val);
uint64_t* getIntSrcPtr(int idx) { return &instSrc[idx].integer; }
uint64_t readIntSrc(int idx) { return instSrc[idx].integer; }
/** These Instructions read a integer/float/misc. source register
* value in the instruction. The instruction's execute function will
* call these and it is the interface that is used by the ISA descr.
* language (which is why the name isnt readIntSrc(...)) Note: That
* the source reg. value is set using the setSrcReg() function.
*/
IntReg readIntRegOperand(const StaticInst *si, int idx, unsigned tid=0);
FloatReg readFloatRegOperand(const StaticInst *si, int idx,
int width = TheISA::SingleWidth);
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
int width = TheISA::SingleWidth);
MiscReg readMiscReg(int misc_reg);
MiscReg readMiscRegNoEffect(int misc_reg);
MiscReg readMiscRegOperand(const StaticInst *si, int idx);
MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx);
/** Returns the result value instruction. */
uint64_t readIntResult(int idx) { return instResult[idx].val.integer; }
float readFloatResult(int idx) { return instResult[idx].val.fp; }
double readDoubleResult(int idx) { return instResult[idx].val.dbl; }
Tick readResultTime(int idx) { return instResult[idx].tick; }
uint64_t* getIntResultPtr(int idx) { return &instResult[idx].val.integer; }
/** This is the interface that an instruction will use to write
* it's destination register.
*/
void setIntRegOperand(const StaticInst *si, int idx, IntReg val);
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
int width = TheISA::SingleWidth);
void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val,
int width = TheISA::SingleWidth);
void setMiscReg(int misc_reg, const MiscReg &val);
void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val);
void setMiscRegOperandNoEffect(const StaticInst *si, int idx, const MiscReg &val);
virtual uint64_t readRegOtherThread(unsigned idx, int tid = -1);
virtual void setRegOtherThread(unsigned idx, const uint64_t &val, int tid = -1);
//////////////////////////////////////////////////////////////
//
// INSTRUCTION STATUS FLAGS (READ/SET)
//
//////////////////////////////////////////////////////////////
/** Sets this instruction as entered on the CPU Reg Dep Map */
void setRegDepEntry() { status.set(RegDepMapEntry); }
/** Returns whether or not the entry is on the CPU Reg Dep Map */
bool isRegDepEntry() const { return status[RegDepMapEntry]; }
/** Sets this instruction as completed. */
void setCompleted() { status.set(Completed); }
/** Returns whether or not this instruction is completed. */
bool isCompleted() const { return status[Completed]; }
/** Marks the result as ready. */
void setResultReady() { status.set(ResultReady); }
/** Returns whether or not the result is ready. */
bool isResultReady() const { return status[ResultReady]; }
/** Sets this instruction as ready to issue. */
void setCanIssue() { status.set(CanIssue); }
/** Returns whether or not this instruction is ready to issue. */
bool readyToIssue() const { return status[CanIssue]; }
/** Sets this instruction as issued from the IQ. */
void setIssued() { status.set(Issued); }
/** Returns whether or not this instruction has issued. */
bool isIssued() const { return status[Issued]; }
/** Sets this instruction as executed. */
void setExecuted() { status.set(Executed); }
/** Returns whether or not this instruction has executed. */
bool isExecuted() const { return status[Executed]; }
/** Sets this instruction as ready to commit. */
void setCanCommit() { status.set(CanCommit); }
/** Clears this instruction as being ready to commit. */
void clearCanCommit() { status.reset(CanCommit); }
/** Returns whether or not this instruction is ready to commit. */
bool readyToCommit() const { return status[CanCommit]; }
void setAtCommit() { status.set(AtCommit); }
bool isAtCommit() { return status[AtCommit]; }
/** Sets this instruction as committed. */
void setCommitted() { status.set(Committed); }
/** Returns whether or not this instruction is committed. */
bool isCommitted() const { return status[Committed]; }
/** Sets this instruction as squashed. */
void setSquashed() { status.set(Squashed); }
/** Returns whether or not this instruction is squashed. */
bool isSquashed() const { return status[Squashed]; }
/** Temporarily sets this instruction as a serialize before instruction. */
void setSerializeBefore() { status.set(SerializeBefore); }
/** Clears the serializeBefore part of this instruction. */
void clearSerializeBefore() { status.reset(SerializeBefore); }
/** Checks if this serializeBefore is only temporarily set. */
bool isTempSerializeBefore() { return status[SerializeBefore]; }
/** Temporarily sets this instruction as a serialize after instruction. */
void setSerializeAfter() { status.set(SerializeAfter); }
/** Clears the serializeAfter part of this instruction.*/
void clearSerializeAfter() { status.reset(SerializeAfter); }
/** Checks if this serializeAfter is only temporarily set. */
bool isTempSerializeAfter() { return status[SerializeAfter]; }
/** Sets the serialization part of this instruction as handled. */
void setSerializeHandled() { status.set(SerializeHandled); }
/** Checks if the serialization part of this instruction has been
* handled. This does not apply to the temporary serializing
* state; it only applies to this instruction's own permanent
* serializing state.
*/
bool isSerializeHandled() { return status[SerializeHandled]; }
private:
/** Instruction effective address.
* @todo: Consider if this is necessary or not.
*/
Addr instEffAddr;
/** Whether or not the effective address calculation is completed.
* @todo: Consider if this is necessary or not.
*/
bool eaCalcDone;
public:
/** Whether or not the memory operation is done. */
bool memOpDone;
public:
/** Load queue index. */
int16_t lqIdx;
/** Store queue index. */
int16_t sqIdx;
/** Iterator pointing to this BaseDynInst in the list of all insts. */
ListIt instListIt;
/** Returns iterator to this instruction in the list of all insts. */
ListIt &getInstListIt() { return instListIt; }
/** Sets iterator for this instruction in the list of all insts. */
void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; }
/** Count of total number of dynamic instructions. */
static int instcount;
#ifdef DEBUG
void dumpSNList();
#endif
/** Dumps out contents of this BaseDynInst. */
void dump();
/** Dumps out contents of this BaseDynInst into given string. */
void dump(std::string &outstring);
//inline int curCount() { return curCount(); }
};
#endif // __CPU_BASE_DYN_INST_HH__

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*/
#include <iomanip>
#include "cpu/exetrace.hh"
#include "cpu/inorder/inorder_trace.hh"
#include "cpu/static_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/thread_context.hh"
#include "params/InOrderTrace.hh"
using namespace std;
using namespace TheISA;
namespace Trace {
inline void
Trace::InOrderTraceRecord::dumpTicks(std::ostream &outs)
{
if (!stageTrace) {
ccprintf(outs, "%7d: ", when);
} else {
ccprintf(outs, "");
for (int i=0; i < stageCycle.size(); i++) {
if (i < stageCycle.size() - 1)
outs << dec << stageCycle[i] << "-";
else
outs << dec << stageCycle[i] << ":";
}
}
}
InOrderTraceRecord *
InOrderTrace::getInstRecord(unsigned num_stages, bool stage_tracing,
ThreadContext *tc)
{
if (!IsOn(ExecEnable))
return NULL;
if (!Trace::enabled)
return NULL;
return new InOrderTraceRecord(num_stages, stage_tracing, tc);
}
InOrderTraceRecord *
InOrderTrace::getInstRecord(Tick when, ThreadContext *tc,
const StaticInstPtr staticInst, Addr pc,
const StaticInstPtr macroStaticInst, MicroPC upc)
{
return new InOrderTraceRecord(ThePipeline::NumStages, true, tc);
}
/* namespace Trace */ }
////////////////////////////////////////////////////////////////////////
//
// ExeTracer Simulation Object
//
Trace::InOrderTrace *
InOrderTraceParams::create()
{
return new Trace::InOrderTrace(this);
};

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*/
#ifndef __INORDERTRACE_HH__
#define __INORDERTRACE_HH__
#include "base/trace.hh"
#include "cpu/static_inst.hh"
#include "sim/host.hh"
#include "sim/insttracer.hh"
#include "params/InOrderTrace.hh"
#include "cpu/exetrace.hh"
class ThreadContext;
namespace Trace {
class InOrderTraceRecord : public ExeTracerRecord
{
public:
InOrderTraceRecord(unsigned num_stages, bool _stage_tracing,
ThreadContext *_thread, bool spec = false)
: ExeTracerRecord(0, _thread, NULL, 0, spec)
{
stageTrace = _stage_tracing;
stageCycle.resize(num_stages);
}
// Trace stage-by-stage execution of instructions.
bool stageTrace;
std::vector<Tick> stageCycle;
void dumpTicks(std::ostream &outs);
void
setStageCycle(int num_stage, Tick cur_cycle)
{
if (stageTrace) {
stageCycle[num_stage] = cur_cycle;
} else {
when = cur_cycle;
}
}
void
setStaticInst(const StaticInstPtr &_staticInst)
{
staticInst = _staticInst;
}
void setPC(Addr _pc) { PC = _pc; }
};
class InOrderTrace : public InstTracer
{
public:
InOrderTrace(const InOrderTraceParams *p) : InstTracer(p)
{}
InOrderTraceRecord *
getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc);
virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
const StaticInstPtr staticInst, Addr pc,
const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0);
};
/* namespace Trace */ }
#endif // __EXETRACE_HH__

124
src/cpu/inorder/params.hh Normal file
View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*/
#ifndef __CPU_INORDER_PARAMS_HH__
#define __CPU_INORDER_PARAMS_HH__
#include "cpu/base.hh"
//Forward declarations
class FunctionalMemory;
class Process;
class MemObject;
class MemInterface;
/**
* This file defines the parameters that will be used for the InOrderCPU.
* This must be defined externally so that the Impl can have a params class
* defined that it can pass to all of the individual stages.
*/
class InOrderParams : public BaseCPU::Params
{
public:
// Workloads
#if !FULL_SYSTEM
std::vector<Process *> workload;
Process *process;
#endif // FULL_SYSTEM
//
// Memory System/Caches
//
unsigned cachePorts;
std::string fetchMemPort;
std::string dataMemPort;
//
// Branch predictor (BP & BTB)
//
std::string predType;
unsigned localPredictorSize;
unsigned localCtrBits;
unsigned localHistoryTableSize;
unsigned localHistoryBits;
unsigned globalPredictorSize;
unsigned globalCtrBits;
unsigned globalHistoryBits;
unsigned choicePredictorSize;
unsigned choiceCtrBits;
unsigned BTBEntries;
unsigned BTBTagSize;
unsigned RASSize;
// Pipeline Parameters
unsigned stageWidth;
// InOrderCPU Simulation Parameters
unsigned instShiftAmt;
unsigned activity;
unsigned deferRegistration;
//
// Memory Parameters
//
unsigned memBlockSize;
//
// Multiply Divide Unit
//
// @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr,
// then MDU must be defined as its own SimObject so that an arbitrary # can
// be defined with different parameters
/** Latency & Repeat Rate for Multiply Insts */
unsigned multLatency;
unsigned multRepeatRate;
/** Latency & Repeat Rate for 8-bit Divide Insts */
unsigned div8Latency;
unsigned div8RepeatRate;
/** Latency & Repeat Rate for 16-bit Divide Insts */
unsigned div16Latency;
unsigned div16RepeatRate;
/** Latency & Repeat Rate for 24-bit Divide Insts */
unsigned div24Latency;
unsigned div24RepeatRate;
/** Latency & Repeat Rate for 32-bit Divide Insts */
unsigned div32Latency;
unsigned div32RepeatRate;
};
#endif // __CPU_O3_CPU_INORDER_PARAMS_HH__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,358 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_PIPELINE_STAGE_HH__
#define __CPU_INORDER_PIPELINE_STAGE_HH__
#include <queue>
#include <vector>
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/comm.hh"
#include "params/InOrderCPU.hh"
#include "cpu/inorder/pipeline_traits.hh"
class InOrderCPU;
class PipelineStage
{
protected:
typedef ThePipeline::Params Params;
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
/** Overall stage status. Used to determine if the CPU can
* deschedule itself due to a lack of activity.
*/
enum StageStatus {
Active,
Inactive
};
/** Individual thread status. */
enum ThreadStatus {
Running,
Idle,
StartSquash,
Squashing,
Blocked,
Unblocking,
MemWaitResponse,
MemWaitRetry,
MemAccessComplete
};
protected:
/** The Number of This Pipeline Stage */
unsigned stageNum;
/** The width of stage, in instructions. */
unsigned stageWidth;
/** Number of Threads*/
unsigned numThreads;
/** Stage status. */
StageStatus _status;
/** Per-thread status. */
ThreadStatus stageStatus[ThePipeline::MaxThreads];
public:
PipelineStage(Params *params, unsigned stage_num);
/** MUST use init() function if this constructor is used. */
PipelineStage() { }
virtual ~PipelineStage() { }
/** PipelineStage initialization. */
void init(Params *params, unsigned stage_num);
/** Returns the name of stage. */
std::string name() const;
/** Registers statistics. */
void regStats();
/** Sets CPU pointer. */
virtual void setCPU(InOrderCPU *cpu_ptr);
virtual void scheduleStageStart(int delay, int tid) { }
/** Sets the main backwards communication time buffer pointer. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
/** Sets pointer to time buffer coming from fetch. */
void setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr);
/** Sets pointer to time buffer used to communicate to the next stage. */
void setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr);
/** Sets pointer to list of active threads. */
void setActiveThreads(std::list<unsigned> *at_ptr);
bool nextStageQueueValid(int stage_num);
bool isBlocked(unsigned tid);
/** Changes the status of this stage to active, and indicates this
* to the CPU.
*/
//inline void switchToActive();
/** Changes the status of this stage to inactive, and indicates
* this to the CPU.
*/
//inline void switchToInactive();
/** Switches out the stage stage. */
void switchOut();
/** Takes over from another CPU's thread. */
void takeOverFrom();
/** Ticks stage, processing all input signals and executing as many
* instructions as possible.
*/
virtual void tick();
/** Is out of order processing valid? */
bool outOfOrderValid();
/** Set a resource stall in the pipeline-stage */
void setResStall(ResReqPtr res_req, unsigned tid);
/** Unset a resource stall in the pipeline-stage */
void unsetResStall(ResReqPtr res_req, unsigned tid);
/** Remove all stall signals for a particular thread; */
virtual void removeStalls(unsigned tid);
/** Is there room in the stage buffer? */
int stageBufferAvail();
protected:
/** Evaluate Stage Conditions and then process stage */
virtual void processStage(bool &status_change);
/** Determines what to do based on stage's current status.
* @param status_change stage() sets this variable if there was a status
* change (ie switching from from blocking to unblocking).
* @param tid Thread id to stage instructions from.
*/
virtual void processThread(bool &status_change, unsigned tid);
/** Processes instructions from fetch and passes them on to rename.
* Decoding of instructions actually happens when they are created in
* fetch, so this function mostly checks if PC-relative branches are
* correct.
*/
virtual void processInsts(unsigned tid);
/** Process all resources on an instruction's resource schedule */
virtual bool processInstSchedule(DynInstPtr inst);
/** Is there room in the next stage buffer for this instruction? */
virtual bool canSendInstToNextStage();
/** Send an instruction to the next stage buffer */
virtual bool sendInstToNextStage(DynInstPtr inst);
/** Inserts a thread's instructions into the skid buffer, to be staged
* once stage unblocks.
*/
virtual void skidInsert(unsigned tid);
/** Returns if all of the skid buffers are empty. */
bool skidsEmpty();
/** Updates overall stage status based on all of the threads' statuses. */
virtual void updateStatus();
/** Separates instructions from fetch into individual lists of instructions
* sorted by thread.
*/
void sortInsts();
/** Reads all stall signals from the backwards communication timebuffer. */
virtual void readStallSignals(unsigned tid);
/** Checks all input signals and updates stage's status appropriately. */
virtual bool checkSignalsAndUpdate(unsigned tid);
/** Checks all stall signals, and returns if any are true. */
virtual bool checkStall(unsigned tid) const;
/** Returns if there any instructions from the previous stage
* on this cycle.
*/
inline bool prevStageInstsValid();
/** Switches stage to blocking, and signals back that stage has
* become blocked.
* @return Returns true if there is a status change.
*/
virtual bool block(unsigned tid);
void blockDueToBuffer(unsigned tid);
/** Switches stage to unblocking if the skid buffer is empty, and
* signals back that stage has unblocked.
* @return Returns true if there is a status change.
*/
virtual bool unblock(unsigned tid);
public:
/** Squashes if there is a PC-relative branch that was predicted
* incorrectly. Sends squash information back to fetch.
*/
virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid);
/** Squash instructions from stage buffer */
virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid);
/** Squashes due to commit signalling a squash. Changes status to
* squashing and clears block/unblock signals as needed.
*/
virtual void squash(InstSeqNum squash_num, unsigned tid);
void dumpInsts();
protected:
/** CPU interface. */
InOrderCPU *cpu;
Trace::InOrderTrace *tracer;
/** List of active thread ids */
std::list<unsigned> *activeThreads;
/** Queue of all instructions coming from previous stage on this cycle. */
std::queue<DynInstPtr> insts[ThePipeline::MaxThreads];
/** Queue of instructions that are finished processing and ready to go next stage.
* This is used to prevent from processing an instrution more than once on any
* stage. NOTE: It is up to the PROGRAMMER must manage this as a queue
*/
std::list<DynInstPtr> instsToNextStage;
/** Skid buffer between previous stage and this one. */
std::queue<DynInstPtr> skidBuffer[ThePipeline::MaxThreads];
/** Instruction used to signify that there is no *real* instruction in buffer slot */
DynInstPtr dummyBufferInst;
/** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */
Addr bdelayDoneSeqNum[ThePipeline::MaxThreads];
/** Instruction used for squashing branch (used for MIPS) */
DynInstPtr squashInst[ThePipeline::MaxThreads];
/** Tells when their is a pending delay slot inst. to send
* to rename. If there is, then wait squash after the next
* instruction (used for MIPS).
*/
bool squashAfterDelaySlot[ThePipeline::MaxThreads];
/** Maximum size of the inter-stage buffer connecting the previous stage to
* this stage (which we call a skid buffer) */
unsigned stageBufferMax;
/** Variable that tracks if stage has written to the time buffer this
* cycle. Used to tell CPU if there is activity this cycle.
*/
bool wroteToTimeBuffer;
/** Index of instructions being sent to the next stage. */
unsigned toNextStageIndex;
/** The last stage that this particular stage should look for stalls */
int lastStallingStage[ThePipeline::MaxThreads];
/** Time buffer interface. */
TimeBuffer<TimeStruct> *timeBuffer;
public:
/** Wire to get rename's output from backwards time buffer. */
TimeBuffer<TimeStruct>::wire fromNextStages;
/** Wire to get iew's information from backwards time buffer. */
TimeBuffer<TimeStruct>::wire toPrevStages;
/** Instruction queue linking previous stage */
TimeBuffer<InterStageStruct> *prevStageQueue;
/** Wire to get the previous stage's. */
TimeBuffer<InterStageStruct>::wire prevStage;
/** Instruction queue linking next stage */
TimeBuffer<InterStageStruct> *nextStageQueue;
/** Wire to write to the next stage */
TimeBuffer<InterStageStruct>::wire nextStage;
/** Is Previous Stage Valid? */
bool prevStageValid;
/** Is Next Stage Valid? */
bool nextStageValid;
/** Source of possible stalls. */
struct Stalls {
bool stage[ThePipeline::NumStages];
std::vector<ResReqPtr> resources;
};
/** Tracks which stages are telling decode to stall. */
Stalls stalls[ThePipeline::MaxThreads];
//@TODO: Use Stats for the pipeline stages
/** Stat for total number of idle cycles. */
//Stats::Scalar<> stageIdleCycles;
/** Stat for total number of blocked cycles. */
//Stats::Scalar<> stageBlockedCycles;
/** Stat for total number of normal running cycles. */
//Stats::Scalar<> stageRunCycles;
/** Stat for total number of unblocking cycles. */
//Stats::Scalar<> stageUnblockCycles;
/** Stat for total number of squashing cycles. */
//Stats::Scalar<> stageSquashCycles;
/** Stat for total number of staged instructions. */
//Stats::Scalar<> stageProcessedInsts;
/** Stat for total number of squashed instructions. */
//Stats::Scalar<> stageSquashedInsts;
};
#endif

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/resources/resource_list.hh"
using namespace std;
namespace ThePipeline {
//@TODO: create my own Instruction Schedule Class
//that operates as a Priority QUEUE
int getNextPriority(DynInstPtr &inst, int stage_num)
{
int cur_pri = 20;
/*
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_it = inst->resSched.begin();
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_end = inst->resSched.end();
while (sked_it != sked_end) {
if (sked_it.top()->stageNum == stage_num) {
cur_pri = sked_it.top()->priority;
}
sked_it++;
}
*/
return cur_pri;
}
void createFrontEndSchedule(DynInstPtr &inst)
{
int stNum = 0;
int stPri = 0;
// Get Pointer to Instuction's Schedule
ResSchedule *inst_sched = &inst->resSched;
//
// IF - Stage 0
// ---------------------------------------
inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::AssignNextPC));
inst_sched->push(new ScheduleEntry(stNum, stPri++, ITLB, TLBUnit::FetchLookup));
inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::InitiateFetch));
//
// DE - Stage 1
// ---------------------------------------
stNum++; stPri = 0;
inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::CompleteFetch));
inst_sched->push(new ScheduleEntry(stNum, stPri++, Decode, DecodeUnit::DecodeInst));
inst_sched->push(new ScheduleEntry(stNum, stPri++, BPred, BranchPredictor::PredictBranch));
inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::UpdateTargetPC));
}
bool createBackEndSchedule(DynInstPtr &inst)
{
if (!inst->staticInst) {
return false;
}
int stNum = BackEndStartStage;
int stPri = 0;
// Get Pointer to Instuction's Schedule
ResSchedule *inst_sched = &inst->resSched;
//
// EX - Stage 2
// ---------------------------------------
for (int idx=0; idx < inst->numSrcRegs(); idx++) {
if (!idx || !inst->isStore())
inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, idx));
}
if ( inst->isNonSpeculative() ) {
// skip execution of non speculative insts until later
} else if (inst->isMemRef()) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, AGEN, AGENUnit::GenerateAddr));
if ( inst->isLoad() ) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup));
inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateReadData));
}
} else {
inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst));
}
//
// MEM - Stage 3
// ---------------------------------------
stPri = 0; stNum++;
if ( inst->isStore() ) { // for store, need src reg at this point
inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, 1));
}
if ( inst->isLoad() ) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteReadData));
} else if ( inst->isStore() ) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup));
inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateWriteData));
}
//
// WB - Stage 4
// ---------------------------------------
stPri = 0; stNum++;
if (inst->isNonSpeculative()) {
if (inst->isMemRef())
fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
} else {
inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst));
}
}
if ( inst->isStore() )
inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteWriteData));
// Write Back to Register File
for (int idx=0; idx < inst->numDestRegs(); idx++) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::WriteDestReg, idx));
}
// Graduate Instructions
inst_sched->push(new ScheduleEntry(stNum, stPri++, Grad, GraduationUnit::GraduateInst));
return true;
}
};

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__
#define __CPU_INORDER_PIPELINE_IMPL_HH__
#include <list>
#include <queue>
#include <vector>
#include "arch/isa_traits.hh"
#include "cpu/inorder/params.hh"
class InOrderDynInst;
/* This Namespace contains constants, typedefs, functions and
* objects specific to the Pipeline Implementation.
*/
namespace ThePipeline {
// Pipeline Constants
const unsigned NumStages = 5;
const unsigned MaxThreads = 3;
const unsigned StageWidth = 1;
const unsigned BackEndStartStage = 2;
// Enumerated List of Resources The Pipeline Uses
enum ResourceList {
FetchSeq = 0,
ITLB,
ICache,
Decode,
BPred,
FetchBuff,
RegManager,
AGEN,
ExecUnit,
DTLB,
DCache,
Grad,
FetchBuff2
};
// Expand this as necessary for your inter stage buffer sizes
static const unsigned interStageBuffSize[] = {
StageWidth, /* Stage 0 - 1 */
StageWidth, /* Stage 1 - 2 */
StageWidth, /* Stage 2 - 3 */
StageWidth, /* Stage 3 - 4 */
StageWidth, /* Stage 4 - 5 */
StageWidth, /* Stage 5 - 6 */
StageWidth, /* Stage 6 - 7 */
StageWidth, /* Stage 7 - 8 */
StageWidth /* Stage 8 - 9 */
};
typedef InOrderCPUParams Params;
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
//////////////////////////
// RESOURCE SCHEDULING
//////////////////////////
struct ScheduleEntry {
ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
int _idx = 0) :
stageNum(stage_num), resNum(res_num), cmd(_cmd),
idx(_idx), priority(_priority)
{ }
virtual ~ScheduleEntry(){}
// Stage number to perform this service.
int stageNum;
// Resource ID to access
int resNum;
// See specific resource for meaning
unsigned cmd;
// See specific resource for meaning
unsigned idx;
// Some Resources May Need Priority?
int priority;
};
struct entryCompare {
bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
{
// Prioritize first by stage number that the resource is needed
if (lhs->stageNum > rhs->stageNum) {
return true;
} else if (lhs->stageNum == rhs->stageNum) {
/*if (lhs->resNum > rhs->resNum) {
return true;
} else {
return false;
}*/
if (lhs->priority > rhs->priority) {
return true;
} else {
return false;
}
} else {
return false;
}
}
};
typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare> ResSchedule;
void createFrontEndSchedule(DynInstPtr &inst);
bool createBackEndSchedule(DynInstPtr &inst);
int getNextPriority(DynInstPtr &inst, int stage_num);
};
#endif

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/resources/resource_list.hh"
using namespace std;
namespace ThePipeline {
//@TODO: create my own Instruction Schedule Class
//that operates as a Priority QUEUE
int getNextPriority(DynInstPtr &inst, int stage_num)
{
int cur_pri = 20;
/*
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_it = inst->resSched.begin();
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_end = inst->resSched.end();
while (sked_it != sked_end) {
if (sked_it.top()->stageNum == stage_num) {
cur_pri = sked_it.top()->priority;
}
sked_it++;
}
*/
return cur_pri;
}
void createFrontEndSchedule(DynInstPtr &inst)
{
int stNum = 0;
int stPri = 0;
// Get Pointer to Instuction's Schedule
ResSchedule *inst_sched = &inst->resSched;
//
// Stage 0
// ---------------------------------------
inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch));
stPri++;
// Reset Priority / Update Next Stage Number
stNum++;
stPri = 0;
//
// Stage 1
// ---------------------------------------
inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC));
stPri++;
if (inst->readTid() == 0)
inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff, InstBuffer::ScheduleOrBypass));
else //if (inst->readTid() == 1)
inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff2, InstBuffer::ScheduleOrBypass));
stPri++;
// Reset Priority / Update Next Stage Number
stNum++;
stPri = 0;
//
// Stage 2
// ---------------------------------------
// Reset Priority / Update Next Stage Number
stNum++;
stPri = 0;
}
bool createBackEndSchedule(DynInstPtr &inst)
{
if (!inst->staticInst) {
return false;
}
std::string name = inst->staticInst->getName();
int stNum = BackEndStartStage;
int stPri = 0;
// Get Pointer to Instuction's Schedule
ResSchedule *inst_sched = &inst->resSched;
//
// Stage 3
// ---------------------------------------
// Set When Source Registers Should be read - Stage 4
for (int idx=0; idx < inst->numSrcRegs(); idx++) {
inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx));
}
stPri++;
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 4
// ---------------------------------------
if (inst->isMemRef()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr));
}
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 5
// ---------------------------------------
// Execution Unit
if (!inst->isNonSpeculative() && !inst->isMemRef()) {
if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
} else {
inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
}
}
stPri++;
// DCache Initiate Access
if (inst->isMemRef()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup));
stPri++;
if (inst->isLoad()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData));
} else if (inst->isStore()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData));
}
}
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 6
// ---------------------------------------
// DCache Complete Access
if (inst->isMemRef()) {
if (inst->isLoad()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData));
} else if (inst->isStore()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData));
}
}
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 7
// ---------------------------------------
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 8
// ---------------------------------------
// NonSpeculative Execution
if (inst->isNonSpeculative() ) {
if (inst->isMemRef())
fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
stPri++;
}
// Write Back to Register File
for (int idx=0; idx < inst->numDestRegs(); idx++) {
inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx));
stPri++;
}
// Graduate Instructions
inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst));
stPri++;
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
return true;
}
};

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__
#define __CPU_INORDER_PIPELINE_IMPL_HH__
#include <list>
#include <queue>
#include <vector>
#include <map>
#include "arch/isa_traits.hh"
#include "cpu/inorder/params.hh"
class InOrderDynInst;
/* This Namespace contains constants, typedefs, functions and
* objects specific to the Pipeline Implementation.
*/
namespace ThePipeline {
// Pipeline Constants
const unsigned NumStages = 9;
const unsigned MaxThreads = 3;
const unsigned StageWidth = 2;
const unsigned BackEndStartStage = 3;
// Use this to over-ride default stage widths
static std::map<unsigned, unsigned> stageBufferSizes;
//static unsigned interStageBuffSize[NumStages];
static const unsigned interStageBuffSize[NumStages] = {
StageWidth, /* Stage 0 - 1 */
StageWidth, /* Stage 1 - 2 */
4, /* Stage 2 - 3 */
StageWidth, /* Stage 3 - 4 */
StageWidth, /* Stage 4 - 5 */
StageWidth, /* Stage 5 - 6 */
StageWidth, /* Stage 6 - 7 */
StageWidth, /* Stage 7 - 8 */
StageWidth /* Stage 8 - 9 */
};
// Enumerated List of Resources The Pipeline Uses
enum ResourceList {
FetchSeq = 0,
ITLB,
ICache,
Decode,
BPred,
FetchBuff,
RegManager,
AGEN,
ExecUnit,
DTLB,
DCache,
Grad,
FetchBuff2
};
typedef InOrderCPUParams Params;
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
//void initPipelineTraits();
//////////////////////////
// RESOURCE SCHEDULING
//////////////////////////
struct ScheduleEntry {
ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
int _idx = 0) :
stageNum(stage_num), resNum(res_num), cmd(_cmd),
idx(_idx), priority(_priority)
{ }
virtual ~ScheduleEntry(){}
// Stage number to perform this service.
int stageNum;
// Resource ID to access
int resNum;
// See specific resource for meaning
unsigned cmd;
// See specific resource for meaning
unsigned idx;
// Some Resources May Need Priority?
int priority;
};
struct entryCompare {
bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
{
// Prioritize first by stage number that the resource is needed
if (lhs->stageNum > rhs->stageNum) {
return true;
} else if (lhs->stageNum == rhs->stageNum) {
/*if (lhs->resNum > rhs->resNum) {
return true;
} else {
return false;
}*/
if (lhs->priority > rhs->priority) {
return true;
} else {
return false;
}
} else {
return false;
}
}
};
typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare> ResSchedule;
void createFrontEndSchedule(DynInstPtr &inst);
bool createBackEndSchedule(DynInstPtr &inst);
int getNextPriority(DynInstPtr &inst, int stage_num);
};
#endif

View file

@ -0,0 +1,240 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/resources/resource_list.hh"
using namespace std;
namespace ThePipeline {
//@TODO: create my own Instruction Schedule Class
//that operates as a Priority QUEUE
int getNextPriority(DynInstPtr &inst, int stage_num)
{
int cur_pri = 20;
/*
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_it = inst->resSched.begin();
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_end = inst->resSched.end();
while (sked_it != sked_end) {
if (sked_it.top()->stageNum == stage_num) {
cur_pri = sked_it.top()->priority;
}
sked_it++;
}
*/
return cur_pri;
}
void createFrontEndSchedule(DynInstPtr &inst)
{
int stNum = 0;
int stPri = 0;
// Get Pointer to Instuction's Schedule
ResSchedule *inst_sched = &inst->resSched;
//
// Stage 0
// ---------------------------------------
inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch));
stPri++;
// Reset Priority / Update Next Stage Number
stNum++;
stPri = 0;
//
// Stage 1
// ---------------------------------------
inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch));
stPri++;
inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC));
stPri++;
int fetch_buff_num = FetchBuff + inst->readTid();
inst_sched->push(new ScheduleEntry(stNum, stPri, fetch_buff_num, InstBuffer::ScheduleOrBypass));
// Reset Priority / Update Next Stage Number
stNum++;
stPri = 0;
//
// Stage 2
// ---------------------------------------
// Reset Priority / Update Next Stage Number
stNum++;
stPri = 0;
}
bool createBackEndSchedule(DynInstPtr &inst)
{
if (!inst->staticInst) {
return false;
}
std::string name = inst->staticInst->getName();
int stNum = BackEndStartStage;
int stPri = 0;
// Get Pointer to Instuction's Schedule
ResSchedule *inst_sched = &inst->resSched;
//
// Stage 3
// ---------------------------------------
// Set When Source Registers Should be read - Stage 4
for (int idx=0; idx < inst->numSrcRegs(); idx++) {
inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx));
}
stPri++;
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 4
// ---------------------------------------
if (inst->isMemRef()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr));
}
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 5
// ---------------------------------------
// Execution Unit
if (!inst->isNonSpeculative() && !inst->isMemRef()) {
//if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
//inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
//} else {
inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
//}
}
stPri++;
// DCache Initiate Access
if (inst->isMemRef()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup));
stPri++;
if (inst->isLoad()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData));
} else if (inst->isStore()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData));
}
}
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 6
// ---------------------------------------
// DCache Complete Access
if (inst->isMemRef()) {
if (inst->isLoad()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData));
} else if (inst->isStore()) {
inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData));
}
}
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 7
// ---------------------------------------
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
//
// Stage 8
// ---------------------------------------
// NonSpeculative Execution
if (inst->isNonSpeculative() ) {
if (inst->isMemRef())
fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
stPri++;
}
// Write Back to Register File
for (int idx=0; idx < inst->numDestRegs(); idx++) {
inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx));
stPri++;
}
// Graduate Instructions
inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst));
stPri++;
// Reset Priority / Update Next Stage Number
stPri = 0;
stNum++;
return true;
}
};

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__
#define __CPU_INORDER_PIPELINE_IMPL_HH__
#include <list>
#include <queue>
#include <vector>
#include <map>
#include "arch/isa_traits.hh"
#include "cpu/inorder/params.hh"
class InOrderDynInst;
/* This Namespace contains constants, typedefs, functions and
* objects specific to the Pipeline Implementation.
*/
namespace ThePipeline {
// Pipeline Constants
const unsigned NumStages = 9;
const unsigned MaxThreads = 2;
const unsigned StageWidth = 1;
const unsigned BackEndStartStage = 3;
// Use this to over-ride default stage widths
static std::map<unsigned, unsigned> stageBufferSizes;
//static unsigned interStageBuffSize[NumStages];
static const unsigned interStageBuffSize[NumStages] = {
StageWidth, /* Stage 0 - 1 */
StageWidth, /* Stage 1 - 2 */
MaxThreads * 4, /* Stage 2 - 3 */
StageWidth, /* Stage 3 - 4 */
MaxThreads * 4, /* Stage 4 - 5 */
StageWidth, /* Stage 5 - 6 */
StageWidth, /* Stage 6 - 7 */
StageWidth, /* Stage 7 - 8 */
MaxThreads /* Stage 8 - 9 */
};
// Enumerated List of Resources The Pipeline Uses
enum ResourceList {
FetchSeq = 0,
ITLB,
ICache,
Decode,
BPred,
RegManager,
AGEN,
ExecUnit,
DTLB,
DCache,
Grad,
FetchBuff,
FetchBuff2
};
typedef InOrderCPUParams Params;
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
//void initPipelineTraits();
//////////////////////////
// RESOURCE SCHEDULING
//////////////////////////
struct ScheduleEntry {
ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
int _idx = 0) :
stageNum(stage_num), resNum(res_num), cmd(_cmd),
idx(_idx), priority(_priority)
{ }
virtual ~ScheduleEntry(){}
// Stage number to perform this service.
int stageNum;
// Resource ID to access
int resNum;
// See specific resource for meaning
unsigned cmd;
// See specific resource for meaning
unsigned idx;
// Some Resources May Need Priority?
int priority;
};
struct entryCompare {
bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
{
// Prioritize first by stage number that the resource is needed
if (lhs->stageNum > rhs->stageNum) {
return true;
} else if (lhs->stageNum == rhs->stageNum) {
/*if (lhs->resNum > rhs->resNum) {
return true;
} else {
return false;
}*/
if (lhs->priority > rhs->priority) {
return true;
} else {
return false;
}
} else {
return false;
}
}
};
typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare> ResSchedule;
void createFrontEndSchedule(DynInstPtr &inst);
bool createBackEndSchedule(DynInstPtr &inst);
int getNextPriority(DynInstPtr &inst, int stage_num);
};
#endif

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/resources/resource_list.hh"
using namespace std;
namespace ThePipeline {
//@TODO: create my own Instruction Schedule Class
//that operates as a Priority QUEUE
int getNextPriority(DynInstPtr &inst, int stage_num)
{
int cur_pri = 20;
/*
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_it = inst->resSched.begin();
std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
entryCompare>::iterator sked_end = inst->resSched.end();
while (sked_it != sked_end) {
if (sked_it.top()->stageNum == stage_num) {
cur_pri = sked_it.top()->priority;
}
sked_it++;
}
*/
return cur_pri;
}
void createFrontEndSchedule(DynInstPtr &inst)
{
InstStage *I = inst->addStage();
InstStage *E = inst->addStage();
I->needs(FetchSeq, FetchSeqUnit::AssignNextPC);
I->needs(ITLB, TLBUnit::FetchLookup);
I->needs(ICache, CacheUnit::InitiateFetch);
E->needs(ICache, CacheUnit::CompleteFetch);
E->needs(Decode, DecodeUnit::DecodeInst);
E->needs(BPred, BranchPredictor::PredictBranch);
E->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC);
}
bool createBackEndSchedule(DynInstPtr &inst)
{
if (!inst->staticInst) {
return false;
}
InstStage *E = inst->currentStage();
InstStage *M = inst->addStage();
InstStage *A = inst->addStage();
InstStage *W = inst->addStage();
for (int idx=0; idx < inst->numSrcRegs(); idx++) {
if (!idx || !inst->isStore()) {
E->needs(RegManager, UseDefUnit::ReadSrcReg, idx);
}
}
if ( inst->isNonSpeculative() ) {
// skip execution of non speculative insts until later
} else if ( inst->isMemRef() ) {
E->needs(AGEN, AGENUnit::GenerateAddr);
if ( inst->isLoad() ) {
E->needs(DTLB, TLBUnit::DataLookup);
E->needs(DCache, CacheUnit::InitiateReadData);
}
} else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
E->needs(MDU, MultDivUnit::StartMultDiv);
// ZERO-LATENCY Multiply:
// E->needs(MDU, MultDivUnit::MultDiv);
} else {
E->needs(ExecUnit, ExecutionUnit::ExecuteInst);
}
if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
M->needs(MDU, MultDivUnit::EndMultDiv);
}
if ( inst->isLoad() ) {
M->needs(DCache, CacheUnit::CompleteReadData);
} else if ( inst->isStore() ) {
M->needs(RegManager, UseDefUnit::ReadSrcReg, 1);
M->needs(DTLB, TLBUnit::DataLookup);
M->needs(DCache, CacheUnit::InitiateWriteData);
}
if ( inst->isStore() ) {
A->needs(DCache, CacheUnit::CompleteWriteData);
}
if ( inst->isNonSpeculative() ) {
if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction");
W->needs(ExecUnit, ExecutionUnit::ExecuteInst);
}
for (int idx=0; idx < inst->numDestRegs(); idx++) {
W->needs(RegManager, UseDefUnit::WriteDestReg, idx);
}
W->needs(Grad, GraduationUnit::GraduateInst);
return true;
}
InstStage::InstStage(DynInstPtr inst, int stage_num)
{
stageNum = stage_num;
nextTaskPriority = 0;
instSched = &inst->resSched;
}
};

View file

@ -0,0 +1,177 @@
/*
* 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 "cpu/inorder/params.hh"
#include "params/InOrderCPU.hh"
class InOrderDynInst;
/* This Namespace contains constants, typedefs, functions and
* objects specific to the Pipeline Implementation.
*/
namespace ThePipeline {
// Pipeline Constants
const unsigned NumStages = 5;
const unsigned MaxThreads = 8;
const unsigned StageWidth = 1;
const unsigned BackEndStartStage = 2;
// Enumerated List of Resources The Pipeline Uses
enum ResourceList {
FetchSeq = 0,
ITLB,
ICache,
Decode,
BPred,
FetchBuff,
RegManager,
AGEN,
ExecUnit,
MDU,
DTLB,
DCache,
Grad,
FetchBuff2
};
// Expand this as necessary for your inter stage buffer sizes
static const unsigned interStageBuffSize[] = {
StageWidth, /* Stage 0 - 1 */
StageWidth, /* Stage 1 - 2 */
StageWidth, /* Stage 2 - 3 */
StageWidth, /* Stage 3 - 4 */
StageWidth, /* Stage 4 - 5 */
StageWidth, /* Stage 5 - 6 */
StageWidth, /* Stage 6 - 7 */
StageWidth, /* Stage 7 - 8 */
StageWidth /* Stage 8 - 9 */
};
typedef InOrderCPUParams Params;
typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
//////////////////////////
// RESOURCE SCHEDULING
//////////////////////////
struct ScheduleEntry {
ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
int _idx = 0) :
stageNum(stage_num), resNum(res_num), cmd(_cmd),
idx(_idx), priority(_priority)
{ }
virtual ~ScheduleEntry(){}
// Stage number to perform this service.
int stageNum;
// Resource ID to access
int resNum;
// See specific resource for meaning
unsigned cmd;
// See specific resource for meaning
unsigned idx;
// Some Resources May Need Priority?
int priority;
};
struct entryCompare {
bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
{
// Prioritize first by stage number that the resource is needed
if (lhs->stageNum > rhs->stageNum) {
return true;
} else if (lhs->stageNum == rhs->stageNum) {
/*if (lhs->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);
class InstStage {
private:
int nextTaskPriority;
int stageNum;
ResSchedule *instSched;
public:
InstStage(DynInstPtr inst, int stage_num);
void needs(int unit, int request) {
instSched->push( new ScheduleEntry(
stageNum, nextTaskPriority++, unit, request
));
}
void needs(int unit, int request, int param) {
instSched->push( new ScheduleEntry(
stageNum, nextTaskPriority++, unit, request, param
));
}
};
};
#endif

View file

@ -0,0 +1,236 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "arch/isa_traits.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/reg_dep_map.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
RegDepMap::RegDepMap(int size)
{
regMap.resize(size);
}
string
RegDepMap::name()
{
return cpu->name() + ".RegDepMap";
}
void
RegDepMap::setCPU(InOrderCPU *_cpu)
{
cpu = _cpu;
}
void
RegDepMap::clear()
{
regMap.clear();
}
void
RegDepMap::insert(DynInstPtr inst)
{
int dest_regs = inst->numDestRegs();
DPRINTF(RegDepMap, "Setting Output Dependencies for [sn:%i] "
", %s (dest. regs = %i).\n",
inst->seqNum,
inst->staticInst->getName(),
dest_regs);
for (int i = 0; i < dest_regs; i++) {
int idx = inst->destRegIdx(i);
//if (inst->numFPDestRegs())
// idx += TheISA::FP_Base_DepTag;
insert(idx, inst);
}
}
void
RegDepMap::insert(unsigned idx, DynInstPtr inst)
{
DPRINTF(RegDepMap, "Inserting [sn:%i] onto dep. list for reg. idx %i.\n",
inst->seqNum, idx);
regMap[idx].push_back(inst);
inst->setRegDepEntry();
}
void
RegDepMap::remove(DynInstPtr inst)
{
if (inst->isRegDepEntry()) {
DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map.\n",
inst->seqNum);
int dest_regs = inst->numDestRegs();
for (int i = 0; i < dest_regs; i++) {
int idx = inst->destRegIdx(i);
remove(idx, inst);
}
}
}
void
RegDepMap::remove(unsigned idx, DynInstPtr inst)
{
std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
std::list<DynInstPtr>::iterator list_end = regMap[idx].end();
while (list_it != list_end) {
if((*list_it) == inst) {
regMap[idx].erase(list_it);
break;
}
list_it++;
}
}
void
RegDepMap::removeFront(unsigned idx, DynInstPtr inst)
{
std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on phys. reg."
"%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum);
assert(list_it != regMap[idx].end());
assert(inst == (*list_it));
regMap[idx].erase(list_it);
}
bool
RegDepMap::canRead(unsigned idx, DynInstPtr inst)
{
if (regMap[idx].size() == 0)
return true;
std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
if (inst->seqNum <= (*list_it)->seqNum) {
return true;
} else {
DPRINTF(RegDepMap, "[sn:%i] Can't read from RegFile, [sn:%i] has not written"
" it's value back yet.\n", inst->seqNum, (*list_it)->seqNum);
return false;
}
}
ThePipeline::DynInstPtr
RegDepMap::canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst)
{
std::list<DynInstPtr>::iterator list_it = regMap[reg_idx].begin();
std::list<DynInstPtr>::iterator list_end = regMap[reg_idx].end();
DynInstPtr forward_inst = NULL;
// Look for first, oldest instruction
while (list_it != list_end &&
(*list_it)->seqNum < inst->seqNum) {
forward_inst = (*list_it);
list_it++;
}
if (forward_inst) {
if (forward_inst->isExecuted() &&
forward_inst->readResultTime(src_idx) < curTick) {
return forward_inst;
} else {
DPRINTF(RegDepMap, "[sn:%i] Can't get value through forwarding, "
" [sn:%i] has not been executed yet.\n",
inst->seqNum, forward_inst->seqNum);
return NULL;
}
} else {
DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n",
inst->seqNum);
return NULL;
}
}
bool
RegDepMap::canWrite(unsigned idx, DynInstPtr inst)
{
if (regMap[idx].size() == 0)
return true;
std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
if (inst->seqNum <= (*list_it)->seqNum) {
return true;
} else {
DPRINTF(RegDepMap, "[sn:%i] Can't write from RegFile: [sn:%i] has not written"
" it's value back yet.\n", inst->seqNum, (*list_it)->seqNum);
}
return false;
}
int
RegDepMap::depSize(unsigned idx)
{
return regMap[idx].size();
}
ThePipeline::DynInstPtr
RegDepMap::findBypassInst(unsigned idx)
{
std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
if (depSize(idx) == 1)
return NULL;
list_it++;
while (list_it != regMap[idx].end()) {
if((*list_it)->isExecuted()) {
return *list_it;
break;
}
}
return NULL;
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef CPU_INORDER_REG_DEP_MAP_HH
#define CPU_INORDER_REG_DEP_MAP_HH
#include <list>
#include <vector>
#include "arch/isa_traits.hh"
#include "cpu/inorder/pipeline_traits.hh"
class InOrderCPU;
class RegDepMap
{
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
RegDepMap(int size = TheISA::TotalNumRegs);
~RegDepMap() { }
std::string name();
void setCPU(InOrderCPU *_cpu);
/** Clear the Entire Map */
void clear();
/** Insert all of a instruction's destination registers into map*/
void insert(DynInstPtr inst);
/** Insert an instruction into a specific destination register index onto map */
void insert(unsigned idx, DynInstPtr inst);
/** Remove all of a instruction's destination registers into map*/
void remove(DynInstPtr inst);
/** Remove a specific instruction and destination register index from map */
void remove(unsigned idx, DynInstPtr inst);
/** Remove Front instruction from a destination register */
void removeFront(unsigned idx, DynInstPtr inst);
/** Is the current instruction able to read from this destination register? */
bool canRead(unsigned idx, DynInstPtr inst);
/** Is the current instruction able to get a forwarded value from another instruction
* for this destination register? */
DynInstPtr canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst);
/** find an instruction to forward/bypass a value from */
DynInstPtr findBypassInst(unsigned idx);
/** Is the current instruction able to write to this destination register? */
bool canWrite(unsigned idx, DynInstPtr inst);
/** Size of Dependency of Map */
int depSize(unsigned idx);
protected:
// Eventually make this a map of lists for
// efficiency sake!
std::vector<std::list<DynInstPtr> > regMap;
InOrderCPU *cpu;
};
#endif

434
src/cpu/inorder/resource.cc Normal file
View file

@ -0,0 +1,434 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
Resource::Resource(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu)
: resName(res_name), id(res_id),
width(res_width), latency(res_latency), cpu(_cpu)
{
// Use to deny a instruction a resource.
deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0);
}
void
Resource::init()
{
// Set Up Resource Events to Appropriate Resource BandWidth
resourceEvent = new ResourceEvent[width];
initSlots();
}
void
Resource::initSlots()
{
// Add available slot numbers for resource
for (int slot_idx = 0; slot_idx < width; slot_idx++) {
availSlots.push_back(slot_idx);
resourceEvent[slot_idx].init(this, slot_idx);
}
}
std::string
Resource::name()
{
return cpu->name() + "." + resName;
}
void
Resource::regStats()
{
instReqsProcessed
.name(name() + ".instReqsProcessed")
.desc("Number of Instructions Requests that completed in this resource.");
}
int
Resource::slotsAvail()
{
return availSlots.size();
}
int
Resource::slotsInUse()
{
return width - availSlots.size();
}
void
Resource::freeSlot(int slot_idx)
{
DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n",
reqMap[slot_idx]->inst->readTid(),
reqMap[slot_idx]->inst->seqNum,
slot_idx);
// Put slot number on this resource's free list
availSlots.push_back(slot_idx);
// Erase Request Pointer From Request Map
std::map<int, ResReqPtr>::iterator req_it = reqMap.find(slot_idx);
assert(req_it != reqMap.end());
reqMap.erase(req_it);
}
// TODO: More efficiently search for instruction's slot within
// resource.
int
Resource::findSlot(DynInstPtr inst)
{
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
map<int, ResReqPtr>::iterator map_end = reqMap.end();
int slot_num = -1;
while (map_it != map_end) {
if ((*map_it).second->getInst()->seqNum ==
inst->seqNum) {
slot_num = (*map_it).second->getSlot();
}
map_it++;
}
return slot_num;
}
int
Resource::getSlot(DynInstPtr inst)
{
int slot_num;
if (slotsAvail() != 0) {
slot_num = availSlots[0];
vector<int>::iterator vect_it = availSlots.begin();
assert(slot_num == *vect_it);
availSlots.erase(vect_it);
} else {
DPRINTF(Resource, "[tid:%i]: No slots in resource "
"available to service [sn:%i].\n", inst->readTid(),
inst->seqNum);
slot_num = -1;
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
map<int, ResReqPtr>::iterator map_end = reqMap.end();
while (map_it != map_end) {
if ((*map_it).second) {
DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n",
(*map_it).second->getInst()->readTid(),
(*map_it).second->getInst()->seqNum);
}
map_it++;
}
}
return slot_num;
}
ResReqPtr
Resource::request(DynInstPtr inst)
{
// See if the resource is already serving this instruction.
// If so, use that request;
bool try_request = false;
int slot_num;
int stage_num;
ResReqPtr inst_req = findRequest(inst);
if (inst_req) {
// If some preprocessing has to be done on instruction
// that has already requested once, then handle it here.
// update the 'try_request' variable if we should
// re-execute the request.
requestAgain(inst, try_request);
slot_num = inst_req->getSlot();
stage_num = inst_req->getStageNum();
} else {
// Get new slot # for instruction
slot_num = getSlot(inst);
if (slot_num != -1) {
// Get Stage # from Schedule Entry
stage_num = inst->resSched.top()->stageNum;
unsigned cmd = inst->resSched.top()->cmd;
// Generate Resource Request
inst_req = getRequest(inst, stage_num, id, slot_num, cmd);
if (inst->staticInst) {
DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n",
inst->readTid(), inst->seqNum);
} else {
DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n",
inst->readTid());
}
reqMap[slot_num] = inst_req;
try_request = true;
}
}
if (try_request) {
// Schedule execution of resource
scheduleExecution(slot_num);
} else {
inst_req = deniedReq;
rejectRequest(inst);
}
return inst_req;
}
void
Resource::requestAgain(DynInstPtr inst, bool &do_request)
{
do_request = true;
if (inst->staticInst) {
DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n",
inst->readTid(), inst->seqNum);
} else {
DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n",
inst->readTid());
}
}
ResReqPtr
Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
return new ResourceRequest(this, inst, stage_num, id, slot_num,
cmd);
}
ResReqPtr
Resource::findRequest(DynInstPtr inst)
{
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
map<int, ResReqPtr>::iterator map_end = reqMap.end();
while (map_it != map_end) {
if ((*map_it).second &&
(*map_it).second->getInst() == inst) {
return (*map_it).second;
}
map_it++;
}
return NULL;
}
void
Resource::rejectRequest(DynInstPtr inst)
{
DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n",
inst->readTid(), inst->seqNum);
}
void
Resource::execute(int slot_idx)
{
DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n",
reqMap[slot_idx]->getTid(), name());
reqMap[slot_idx]->setCompleted(true);
reqMap[slot_idx]->fault = NoFault;
reqMap[slot_idx]->done();
}
void
Resource::deactivateThread(unsigned tid)
{
// In the most basic case, deactivation means squashing everything
// from a particular thread
DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid);
squash(dummy_inst, 0, 0, tid);
}
void
Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
{
std::vector<int> slot_remove_list;
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
map<int, ResReqPtr>::iterator map_end = reqMap.end();
while (map_it != map_end) {
ResReqPtr req_ptr = (*map_it).second;
if (req_ptr &&
req_ptr->getInst()->readTid() == tid &&
req_ptr->getInst()->seqNum > squash_seq_num) {
DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
req_ptr->getInst()->readTid(),
req_ptr->getInst()->seqNum);
int req_slot_num = req_ptr->getSlot();
unscheduleEvent(req_slot_num);
// Mark request for later removal
cpu->reqRemoveList.push(req_ptr);
// Mark slot for removal from resource
slot_remove_list.push_back(req_ptr->getSlot());
}
map_it++;
}
// Now Delete Slot Entry from Req. Map
for (int i = 0; i < slot_remove_list.size(); i++) {
freeSlot(slot_remove_list[i]);
}
}
Tick
Resource::ticks(int num_cycles)
{
return cpu->ticks(num_cycles);
}
void
Resource::scheduleExecution(int slot_num)
{
int res_latency = getLatency(slot_num);
if (res_latency >= 1) {
scheduleEvent(slot_num, res_latency);
} else {
execute(slot_num);
}
}
void
Resource::scheduleEvent(int slot_idx, int delay)
{
DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n",
reqMap[slot_idx]->inst->readTid(),
reqMap[slot_idx]->inst->seqNum,
cpu->ticks(delay) + curTick);
resourceEvent[slot_idx].scheduleEvent(delay);
}
bool
Resource::scheduleEvent(DynInstPtr inst, int delay)
{
int slot_idx = findSlot(inst);
if(slot_idx != -1)
resourceEvent[slot_idx].scheduleEvent(delay);
return slot_idx;
}
void
Resource::unscheduleEvent(int slot_idx)
{
resourceEvent[slot_idx].unscheduleEvent();
}
bool
Resource::unscheduleEvent(DynInstPtr inst)
{
int slot_idx = findSlot(inst);
if(slot_idx != -1)
resourceEvent[slot_idx].unscheduleEvent();
return slot_idx;
}
int ResourceRequest::resReqID = 0;
int ResourceRequest::resReqCount = 0;
void
ResourceRequest::done(bool completed)
{
DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n",
res->name(), inst->seqNum, inst->readTid());
setCompleted(completed);
// Add to remove list
res->cpu->reqRemoveList.push(res->reqMap[slotNum]);
// Free Slot So Another Instruction Can Use This Resource
res->freeSlot(slotNum);
res->instReqsProcessed++;
}
ResourceEvent::ResourceEvent()
: Event((Event::Priority)Resource_Event_Pri)
{ }
ResourceEvent::ResourceEvent(Resource *res, int slot_idx)
: Event((Event::Priority)Resource_Event_Pri), resource(res),
slotIdx(slot_idx)
{ }
void
ResourceEvent::init(Resource *res, int slot_idx)
{
resource = res;
slotIdx = slot_idx;
}
void
ResourceEvent::process()
{
resource->execute(slotIdx);
}
const char *
ResourceEvent::description()
{
string desc = resource->name() + " event";
return desc.c_str();
}

404
src/cpu/inorder/resource.hh Normal file
View file

@ -0,0 +1,404 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_RESOURCE_HH__
#define __CPU_INORDER_RESOURCE_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inst_seq.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
class Event;
class InOrderCPU;
class ResourceEvent;
class ResourceRequest;
typedef ResourceRequest ResReq;
typedef ResourceRequest* ResReqPtr;
class Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
friend class ResourceEvent;
friend class ResourceRequest;
public:
Resource(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu);
virtual ~Resource() {}
/** Return name of this resource */
virtual std::string name();
/** Define this function if resource, has a port to connect to an outside
* simulation object.
*/
virtual Port* getPort(const std::string &if_name, int idx) { return NULL; }
/** Return ID for this resource */
int getId() { return id; }
/** Any extra initiliazation stuff can be set up using this function that
* should get called before the simulation starts (tick 0)
*/
virtual void init();
virtual void initSlots();
/** Tasks to perform when simulation starts */
//virtual void startup() { }
/** Register Stats for this resource */
virtual void regStats();
/** Resources that care about thread activation override this. */
virtual void activateThread(unsigned tid) { }
/** Deactivate Thread. Default action is to squash all instructions
* from deactivated thread.
*/
virtual void deactivateThread(unsigned tid);
/** Resources that care when an instruction has been graduated
* can override this
*/
virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { }
/** Request usage of this resource. Returns a ResourceRequest object
* with all the necessary resource information
*/
virtual ResourceRequest* request(DynInstPtr inst);
/** Get the next available slot in this resource. Instruction is passed
* so that resources can check the instruction before allocating a slot
* if necessary.
*/
virtual int getSlot(DynInstPtr inst);
/** Find the slot that this instruction is using in a resource */
virtual int findSlot(DynInstPtr inst);
/** Free a resource slot */
virtual void freeSlot(int slot_idx);
/** Request usage of a resource for this instruction. If this instruction already
* has made this request to this resource, and that request is uncompleted
* this function will just return that request
*/
virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
int res_idx, int slot_num,
unsigned cmd);
/** Schedule Execution of This Resource For A Given Slot*/
virtual void scheduleExecution(int slot_idx);
/** Execute the function of this resource. The Default is action
* is to do nothing. More specific models will derive from this
* class and define their own execute function.
*/
virtual void execute(int slot_idx);
/** Fetch on behalf of an instruction. Will check to see
* if instruction is actually in resource before
* trying to fetch. Needs to be defined for derived units.
*/
virtual Fault doFetchAccess(DynInstPtr inst)
{ panic("doFetchAccess undefined for %s", name()); return NoFault; }
/** Read/Write on behalf of an instruction. Will check to see
* if instruction is actually in resource before
* trying to do access.Needs to be defined for derived units.
*/
virtual Fault doDataAccess(DynInstPtr inst)
{ panic("doDataAccess undefined for %s", name()); return NoFault; }
/** Squash All Requests After This Seq Num */
virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
/** The number of instructions available that this resource can
* can still process
*/
int slotsAvail();
/** The number of instructions using this resource */
int slotsInUse();
/** Schedule resource event, regardless of its current state. */
void scheduleEvent(int slot_idx, int delay);
/** Find instruction in list, Schedule resource event, regardless of its current state. */
bool scheduleEvent(DynInstPtr inst, int delay);
/** Unschedule resource event, regardless of its current state. */
void unscheduleEvent(int slot_idx);
/** Unschedule resource event, regardless of its current state. */
bool unscheduleEvent(DynInstPtr inst);
/** Return the number of cycles in 'Tick' format */
Tick ticks(int numCycles);
/** Find the request that corresponds to this instruction */
virtual ResReqPtr findRequest(DynInstPtr inst);
/** */
virtual void rejectRequest(DynInstPtr inst);
/** Request a Resource again. Some resources have to special process this
* in subsequent accesses.
*/
virtual void requestAgain(DynInstPtr inst, bool &try_request);
/** Return Latency of Resource */
/* Can be overridden for complex cases */
virtual int getLatency(int slot_num) { return latency; }
protected:
/** The name of this resource */
std::string resName;
/** ID of the resource. The Resource Pool uses this # to identify this
* resource.
*/
int id;
/** The number of instructions the resource can simultaneously
* process.
*/
int width;
/** Constant latency for this resource.
* Note: Dynamic latency resources set this to 0 and
* manage the latency themselves
*/
const int latency;
public:
/** Mapping of slot-numbers to the resource-request pointers */
std::map<int, ResReqPtr> reqMap;
/** A list of all the available execution slots for this resource.
* This correlates with the actual resource event idx.
*/
std::vector<int> availSlots;
/** The CPU(s) that this resource interacts with */
InOrderCPU *cpu;
protected:
/** The resource event used for scheduling resource slots on the
* event queue
*/
ResourceEvent *resourceEvent;
/** Default denied resource request pointer*/
ResReqPtr deniedReq;
public:
/////////////////////////////////////////////////////////////////
//
// DEFAULT RESOURCE STATISTICS
//
/////////////////////////////////////////////////////////////////
/** Number of Instruction Requests the Resource Processes */
Stats::Scalar<> instReqsProcessed;
};
class ResourceEvent : public Event
{
public:
/** Pointer to the CPU. */
Resource *resource;
/// Resource events that come before other associated CPU events
/// (for InOrderCPU model).
/// check src/sim/eventq.hh for more event priorities.
enum InOrderPriority {
Resource_Event_Pri = 45,
};
/** The Resource Slot that this event is servicing */
int slotIdx;
/** Constructs a resource event. */
ResourceEvent();
ResourceEvent(Resource *res, int slot_idx);
virtual ~ResourceEvent() { }
/** Initialize data for this resource event. */
virtual void init(Resource *res, int slot_idx);
/** Processes a resource event. */
virtual void process();
/** Returns the description of the resource event. */
const char *description();
/** Set slot idx for event */
void setSlot(int slot) { slotIdx = slot; }
/** Schedule resource event, regardless of its current state. */
void scheduleEvent(int delay)
{
if (squashed())
mainEventQueue.reschedule(this, curTick + resource->ticks(delay));
else if (!scheduled())
mainEventQueue.schedule(this, curTick + resource->ticks(delay));
}
/** Unschedule resource event, regardless of its current state. */
void unscheduleEvent()
{
if (scheduled())
squash();
}
};
class ResourceRequest
{
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
static int resReqID;
static int resReqCount;
public:
ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num,
int res_idx, int slot_num, unsigned _cmd)
: res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num),
resIdx(res_idx), slotNum(slot_num), completed(false),
squashed(false), processing(false), waiting(false)
{
reqID = resReqID++;
resReqCount++;
DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount);
if (resReqCount > 100) {
fatal("Too many undeleted resource requests. Memory leak?\n");
}
}
virtual ~ResourceRequest()
{
resReqCount--;
DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount);
}
int reqID;
/** Acknowledge that this is a request is done and remove
* from resource.
*/
void done(bool completed = true);
/////////////////////////////////////////////
//
// GET RESOURCE REQUEST IDENTIFICATION / INFO
//
/////////////////////////////////////////////
/** Get Resource Index */
int getResIdx() { return resIdx; }
/** Get Slot Number */
int getSlot() { return slotNum; }
/** Get Stage Number */
int getStageNum() { return stageNum; }
/** Set/Get Thread Ids */
void setTid(unsigned _tid) { tid = _tid; }
int getTid() { return tid; }
/** Instruction this request is for */
DynInstPtr getInst() { return inst; }
/** Data from this request. Overridden by Resource-Specific Request
* Objects
*/
virtual PacketDataPtr getData() { return NULL; }
/** Pointer to Resource that is being used */
Resource *res;
/** Instruction being used */
DynInstPtr inst;
/** Fault Associated With This Resource Request */
Fault fault;
/** Command For This Resource */
unsigned cmd;
////////////////////////////////////////
//
// GET RESOURCE REQUEST STATUS FROM VARIABLES
//
////////////////////////////////////////
/** Get/Set Completed variables */
bool isCompleted() { return completed; }
void setCompleted(bool cond = true) { completed = cond; }
/** Get/Set Squashed variables */
bool isSquashed() { return squashed; }
void setSquashed() { squashed = true; }
/** Get/Set IsProcessing variables */
bool isProcessing() { return processing; }
void setProcessing() { processing = true; }
/** Get/Set IsWaiting variables */
bool isWaiting() { return waiting; }
void setWaiting() { waiting = true; }
protected:
/** Resource Identification */
int tid;
int stageNum;
int resIdx;
int slotNum;
/** Resource Status */
bool completed;
bool squashed;
bool processing;
bool waiting;
};
#endif //__CPU_INORDER_RESOURCE_HH__

View file

@ -0,0 +1,357 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resource_pool.hh"
#include "cpu/inorder/resources/resource_list.hh"
#include <vector>
#include <list>
using namespace std;
using namespace ThePipeline;
ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
: cpu(_cpu)
{
//@todo: use this function to instantiate the resources in resource pool. This will help in the
//auto-generation of this pipeline model.
//ThePipeline::addResources(resources, memObjects);
// Declare Resource Objects
// name - id - bandwidth - latency - CPU - Parameters
// --------------------------------------------------
resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params));
resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params));
memObjects.push_back(ICache);
resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params));
resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params));
for (int i = 0; i < params->numberOfThreads; i++) {
char fbuff_name[20];
sprintf(fbuff_name, "Fetch-Buffer-T%i", i);
resources.push_back(new InstBuffer(fbuff_name, FetchBuff + i, 4, 0, _cpu, params));
}
resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params));
resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params));
resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params));
resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params));
memObjects.push_back(DCache);
resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params));
}
void
ResourcePool::init()
{
for (int i=0; i < resources.size(); i++) {
resources[i]->init();
}
}
string
ResourcePool::name()
{
return cpu->name() + ".ResourcePool";
}
void
ResourcePool::regStats()
{
DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->regStats();
}
}
Port *
ResourcePool::getPort(const std::string &if_name, int idx)
{
for (int i = 0; i < memObjects.size(); i++) {
int obj_idx = memObjects[i];
Port *port = resources[obj_idx]->getPort(if_name, idx);
if (port != NULL) {
return port;
}
}
return NULL;
}
unsigned
ResourcePool::getPortIdx(const std::string &port_name)
{
for (int i = 0; i < memObjects.size(); i++) {
unsigned obj_idx = memObjects[i];
Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
if (port != NULL) {
return obj_idx;
}
}
return 0;
}
ResReqPtr
ResourcePool::request(int res_idx, DynInstPtr inst)
{
//Make Sure This is a valid resource ID
assert(res_idx >= 0 && res_idx < resources.size());
return resources[res_idx]->request(inst);
}
void
ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid)
{
resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid);
}
int
ResourcePool::slotsAvail(int res_idx)
{
return resources[res_idx]->slotsAvail();
}
int
ResourcePool::slotsInUse(int res_idx)
{
return resources[res_idx]->slotsInUse();
}
void
ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
int delay, int res_idx, int tid)
{
assert(delay >= 0);
ResPoolEvent *res_pool_event = new ResPoolEvent(this);
switch (e_type)
{
case InOrderCPU::ActivateThread:
{
DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->bdelaySeqNum,
inst->readTid());
res_pool_event->schedule(curTick + cpu->cycles(delay));
}
break;
case InOrderCPU::SuspendThread:
case InOrderCPU::DeallocateThread:
{
DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->bdelaySeqNum,
tid);
res_pool_event->schedule(curTick + cpu->cycles(delay));
}
break;
case ResourcePool::InstGraduated:
{
DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->seqNum,
inst->readTid());
res_pool_event->schedule(curTick + cpu->cycles(delay));
}
break;
case ResourcePool::SquashAll:
{
DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->bdelaySeqNum,
inst->readTid());
res_pool_event->schedule(curTick + cpu->cycles(delay));
}
break;
default:
DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type);
; // If Resource Pool doesnt recognize event, we ignore it.
}
}
void
ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
{
resources[res_idx]->unscheduleEvent(inst);
}
void
ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n",
stage_num, tid, done_seq_num);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->squash(inst, stage_num, done_seq_num, tid);
}
}
void
ResourcePool::activateAll(unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n",
tid);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->activateThread(tid);
}
}
void
ResourcePool::deactivateAll(unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n",
tid);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->deactivateThread(tid);
}
}
void
ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n",
tid, seq_num);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->instGraduated(seq_num, tid);
}
}
ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
: Event(&mainEventQueue, CPU_Tick_Pri),
resPool(_resPool)
{ eventType = (InOrderCPU::CPUEventType) Default; }
void
ResourcePool::ResPoolEvent::process()
{
switch (eventType)
{
case InOrderCPU::ActivateThread:
resPool->activateAll(tid);
break;
case InOrderCPU::SuspendThread:
case InOrderCPU::DeallocateThread:
resPool->deactivateAll(tid);
break;
case ResourcePool::InstGraduated:
resPool->instGraduated(seqNum, tid);
break;
case ResourcePool::SquashAll:
resPool->squashAll(inst, stageNum, seqNum, tid);
break;
default:
fatal("Unrecognized Event Type");
}
resPool->cpu->cpuEventRemoveList.push(this);
}
const char *
ResourcePool::ResPoolEvent::description()
{
return "Resource Pool event";
}
/** Schedule resource event, regardless of its current state. */
void
ResourcePool::ResPoolEvent::scheduleEvent(int delay)
{
if (squashed())
reschedule(curTick + resPool->cpu->cycles(delay));
else if (!scheduled())
schedule(curTick + resPool->cpu->cycles(delay));
}
/** Unschedule resource event, regardless of its current state. */
void
ResourcePool::ResPoolEvent::unscheduleEvent()
{
if (scheduled())
squash();
}

View file

@ -0,0 +1,364 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resource_pool.hh"
#include "cpu/inorder/resources/resource_list.hh"
#include <vector>
#include <list>
using namespace std;
using namespace ThePipeline;
ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
: cpu(_cpu)
{
//@todo: use this function to instantiate the resources in resource pool. This will help in the
//auto-generation of this pipeline model.
//ThePipeline::addResources(resources, memObjects);
// Declare Resource Objects
// name - id - bandwidth - latency - CPU - Parameters
// --------------------------------------------------
resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params));
resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params));
memObjects.push_back(ICache);
resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params));
resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params));
resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params));
resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params));
resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params));
resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params));
resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params));
memObjects.push_back(DCache);
resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params));
resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params));
}
void
ResourcePool::init()
{
for (int i=0; i < resources.size(); i++) {
DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name());
resources[i]->init();
}
}
string
ResourcePool::name()
{
return cpu->name() + ".ResourcePool";
}
void
ResourcePool::regStats()
{
DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->regStats();
}
}
Port *
ResourcePool::getPort(const std::string &if_name, int idx)
{
DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name);
for (int i = 0; i < memObjects.size(); i++) {
int obj_idx = memObjects[i];
Port *port = resources[obj_idx]->getPort(if_name, idx);
if (port != NULL) {
DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name,
resources[obj_idx]->name(), obj_idx);
return port;
}
}
return NULL;
}
unsigned
ResourcePool::getPortIdx(const std::string &port_name)
{
DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name);
for (int i = 0; i < memObjects.size(); i++) {
unsigned obj_idx = memObjects[i];
Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
if (port != NULL) {
DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name);
return obj_idx;
}
}
return 0;
}
ResReqPtr
ResourcePool::request(int res_idx, DynInstPtr inst)
{
//Make Sure This is a valid resource ID
assert(res_idx >= 0 && res_idx < resources.size());
return resources[res_idx]->request(inst);
}
void
ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid)
{
resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid);
}
int
ResourcePool::slotsAvail(int res_idx)
{
return resources[res_idx]->slotsAvail();
}
int
ResourcePool::slotsInUse(int res_idx)
{
return resources[res_idx]->slotsInUse();
}
void
ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
int delay, int res_idx, int tid)
{
assert(delay >= 0);
ResPoolEvent *res_pool_event = new ResPoolEvent(this);
switch (e_type)
{
case InOrderCPU::ActivateThread:
{
DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->bdelaySeqNum,
inst->readTid());
mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
}
break;
case InOrderCPU::SuspendThread:
case InOrderCPU::DeallocateThread:
{
DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->bdelaySeqNum,
tid);
mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
}
break;
case ResourcePool::InstGraduated:
{
DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->seqNum,
inst->readTid());
mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
}
break;
case ResourcePool::SquashAll:
{
DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n",
curTick + delay);
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
inst->bdelaySeqNum,
inst->readTid());
mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
}
break;
default:
DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type);
; // If Resource Pool doesnt recognize event, we ignore it.
}
}
void
ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
{
resources[res_idx]->unscheduleEvent(inst);
}
void
ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n",
stage_num, tid, done_seq_num);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->squash(inst, stage_num, done_seq_num, tid);
}
}
void
ResourcePool::activateAll(unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n",
tid);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->activateThread(tid);
}
}
void
ResourcePool::deactivateAll(unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n",
tid);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->deactivateThread(tid);
}
}
void
ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid)
{
DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n",
tid, seq_num);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++) {
resources[idx]->instGraduated(seq_num, tid);
}
}
ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
: Event(CPU_Tick_Pri),
resPool(_resPool)
{ eventType = (InOrderCPU::CPUEventType) Default; }
void
ResourcePool::ResPoolEvent::process()
{
switch (eventType)
{
case InOrderCPU::ActivateThread:
resPool->activateAll(tid);
break;
case InOrderCPU::SuspendThread:
case InOrderCPU::DeallocateThread:
resPool->deactivateAll(tid);
break;
case ResourcePool::InstGraduated:
resPool->instGraduated(seqNum, tid);
break;
case ResourcePool::SquashAll:
resPool->squashAll(inst, stageNum, seqNum, tid);
break;
default:
fatal("Unrecognized Event Type");
}
resPool->cpu->cpuEventRemoveList.push(this);
}
const char *
ResourcePool::ResPoolEvent::description()
{
return "Resource Pool event";
}
/** Schedule resource event, regardless of its current state. */
void
ResourcePool::ResPoolEvent::scheduleEvent(int delay)
{
if (squashed())
mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay));
else if (!scheduled())
mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay));
}
/** Unschedule resource event, regardless of its current state. */
void
ResourcePool::ResPoolEvent::unscheduleEvent()
{
if (scheduled())
squash();
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_RESOURCE_POOL_HH__
#define __CPU_INORDER_RESOURCE_POOL_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inst_seq.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/params.hh"
#include "params/InOrderCPU.hh"
#include "cpu/inorder/cpu.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
class Event;
class InOrderCPU;
class Resource;
class ResourceEvent;
class ResourcePool {
public:
typedef InOrderDynInst::DynInstPtr DynInstPtr;
public:
// List of Resource Pool Events that extends
// the list started by the CPU
// NOTE(1): Resource Pool also uses event list
// CPUEventType defined in inorder/cpu.hh
enum ResPoolEventType {
InstGraduated = InOrderCPU::NumCPUEvents,
SquashAll,
Default
};
class ResPoolEvent : public Event
{
protected:
/** Resource Pool */
ResourcePool *resPool;
public:
InOrderCPU::CPUEventType eventType;
DynInstPtr inst;
InstSeqNum seqNum;
int stageNum;
unsigned tid;
public:
/** Constructs a resource event. */
ResPoolEvent(ResourcePool *_resPool);
/** Set Type of Event To Be Scheduled */
void setEvent(InOrderCPU::CPUEventType e_type,
DynInstPtr _inst,
int stage_num,
InstSeqNum seq_num,
unsigned _tid)
{
eventType = e_type;
inst = _inst;
seqNum = seq_num;
stageNum = stage_num;
tid = _tid;
}
/** Processes a resource event. */
virtual void process();
/** Returns the description of the resource event. */
const char *description();
/** Schedule Event */
void scheduleEvent(int delay);
/** Unschedule This Event */
void unscheduleEvent();
};
public:
ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~ResourcePool() {}
std::string name();
std::string name(int res_idx) { return resources[res_idx]->name(); }
void init();
/** Register Statistics in All Resources */
void regStats();
/** Returns a specific port. */
Port* getPort(const std::string &if_name, int idx);
/** Returns a specific port. */
unsigned getPortIdx(const std::string &if_name);
Resource* getResource(int res_idx) { return resources[res_idx]; }
/** Request usage of this resource. Returns -1 if not granted and
* a positive request tag if granted.
*/
ResReqPtr request(int res_idx, DynInstPtr inst);
/** Squash The Resource */
void squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid);
/** Squash All Resources in Pool after Done Seq. Num */
void squashAll(DynInstPtr inst, int stage_num,
InstSeqNum done_seq_num, unsigned tid);
/** Activate Thread in all resources */
void activateAll(unsigned tid);
/** De-Activate Thread in all resources */
void deactivateAll(unsigned tid);
/** Broadcast graduation to all resources */
void instGraduated(InstSeqNum seq_num,unsigned tid);
/** The number of instructions available that a resource can
* can still process.
*/
int slotsAvail(int res_idx);
/** The number of instructions using a resource */
int slotsInUse(int res_idx);
/** Schedule resource event, regardless of its current state. */
void scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst = NULL,
int delay = 0, int res_idx = 0, int tid = 0);
/** UnSchedule resource event, regardless of its current state. */
void unscheduleEvent(int res_idx, DynInstPtr inst);
/** Tasks to perform when simulation starts */
virtual void startup() { }
/** The CPU(s) that this resource interacts with */
InOrderCPU *cpu;
DynInstPtr dummyInst[ThePipeline::MaxThreads];
private:
std::vector<Resource *> resources;
std::vector<int> memObjects;
};
#endif //__CPU_INORDER_RESOURCE_HH__

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resources/agen_unit.hh"
AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{ }
void
AGENUnit::execute(int slot_num)
{
ResourceRequest* agen_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
Fault fault = reqMap[slot_num]->fault;
int tid;
int seq_num = inst->seqNum;
tid = inst->readTid();
agen_req->fault = NoFault;
switch (agen_req->cmd)
{
case GenerateAddr:
{
// Load/Store Instruction
if (inst->isMemRef()) {
DPRINTF(Resource, "[tid:%i] Generating Address for [sn:%i] (%s).\n",
tid, inst->seqNum, inst->staticInst->getName());
// We are not handdling Prefetches quite yet
if (inst->isDataPrefetch() || inst->isInstPrefetch()) {
panic("Prefetches arent handled yet.\n");
} else {
if (inst->isLoad()) {
fault = inst->calcEA();
inst->setMemAddr(inst->getEA());
//inst->setExecuted();
DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: "
"%#x.\n", tid, inst->seqNum, inst->getEA());
} else if (inst->isStore()) {
fault = inst->calcEA();
inst->setMemAddr(inst->getEA());
DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: "
"%#x.\n", tid, inst->seqNum, inst->getEA());
} else {
panic("Unexpected memory type!\n");
}
if (fault == NoFault) {
agen_req->done();
} else {
fatal("%s encountered @ [sn:%i]",fault->name(), seq_num);
}
}
} else {
DPRINTF(Resource, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num);
agen_req->done();
}
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_AGEN_UNIT_HH__
#define __CPU_INORDER_AGEN_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
#include "cpu/inorder/params.hh"
class AGENUnit : public Resource {
public:
typedef InOrderDynInst::DynInstPtr DynInstPtr;
public:
AGENUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~AGENUnit() {}
enum Command {
GenerateAddr
};
virtual void execute(int slot_num);
protected:
/** @todo: Add Resource Stats Here */
};
#endif //__CPU_INORDER_DECODE_UNIT_HH__

View file

@ -0,0 +1,426 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
*/
#include <list>
#include <vector>
#include "base/trace.hh"
#include "base/traceflags.hh"
#include "cpu/inorder/resources/bpred_unit.hh"
using namespace std;
using namespace ThePipeline;
BPredUnit::BPredUnit(ThePipeline::Params *params)
: BTB(params->BTBEntries,
params->BTBTagSize,
params->instShiftAmt)
{
// Setup the selected predictor.
if (params->predType == "local") {
localBP = new LocalBP(params->localPredictorSize,
params->localCtrBits,
params->instShiftAmt);
predictor = Local;
} else if (params->predType == "tournament") {
tournamentBP = new TournamentBP(params->localPredictorSize,
params->localCtrBits,
params->localHistoryTableSize,
params->localHistoryBits,
params->globalPredictorSize,
params->globalHistoryBits,
params->globalCtrBits,
params->choicePredictorSize,
params->choiceCtrBits,
params->instShiftAmt);
predictor = Tournament;
} else {
fatal("Invalid BP selected!");
}
for (int i=0; i < ThePipeline::MaxThreads; i++)
RAS[i].init(params->RASSize);
}
void
BPredUnit::regStats()
{
lookups
.name(name() + ".BPredUnit.lookups")
.desc("Number of BP lookups")
;
condPredicted
.name(name() + ".BPredUnit.condPredicted")
.desc("Number of conditional branches predicted")
;
condIncorrect
.name(name() + ".BPredUnit.condIncorrect")
.desc("Number of conditional branches incorrect")
;
BTBLookups
.name(name() + ".BPredUnit.BTBLookups")
.desc("Number of BTB lookups")
;
BTBHits
.name(name() + ".BPredUnit.BTBHits")
.desc("Number of BTB hits")
;
BTBCorrect
.name(name() + ".BPredUnit.BTBCorrect")
.desc("Number of correct BTB predictions (this stat may not "
"work properly.")
;
usedRAS
.name(name() + ".BPredUnit.usedRAS")
.desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
.name(name() + ".BPredUnit.RASInCorrect")
.desc("Number of incorrect RAS predictions.")
;
}
void
BPredUnit::switchOut()
{
// Clear any state upon switch out.
for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
squash(0, i);
}
}
void
BPredUnit::takeOverFrom()
{
// Can reset all predictor state, but it's not necessarily better
// than leaving it be.
/*
for (int i = 0; i < ThePipeline::MaxThreads; ++i)
RAS[i].reset();
BP.reset();
BTB.reset();
*/
}
bool
BPredUnit::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
using TheISA::MachInst;
bool pred_taken = false;
Addr target;
++lookups;
void *bp_history = NULL;
if (inst->isUncondCtrl()) {
DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid);
pred_taken = true;
// Tell the BP there was an unconditional branch.
BPUncond(bp_history);
if (inst->isReturn() && RAS[tid].empty()) {
DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting "
"false.\n", tid);
pred_taken = false;
}
} else {
++condPredicted;
pred_taken = BPLookup(PC, bp_history);
DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i "
"for PC %#x\n",
tid, pred_taken, inst->readPC());
}
PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
if (inst->isReturn()) {
++usedRAS;
// If it's a function return call, then look up the address
// in the RAS.
target = RAS[tid].top();
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = target;
assert(predict_record.RASIndex < 16);
RAS[tid].pop();
DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, "
"RAS predicted target: %#x, RAS index: %i.\n",
tid, inst->readPC(), target, predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
RAS[tid].push(PC + sizeof(MachInst));
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
predict_record.wasCall = true;
DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call"
", adding %#x to the RAS.\n",
tid, inst->readPC(), PC + sizeof(MachInst));
}
if (inst->isCall() &&
inst->isUncondCtrl() &&
inst->isDirectCtrl()) {
target = inst->branchTarget();
DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted"
" target to %#x.\n",
tid, inst->readPC(), target);
} else if (BTB.valid(PC, tid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
target = BTB.lookup(PC, tid);
DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted"
" target is %#x.\n",
tid, inst->readPC(), target);
} else {
DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a "
"valid entry.\n",tid);
pred_taken = false;
}
}
}
if (pred_taken) {
// Set the PC and the instruction's predicted target.
PC = target;
inst->setPredTarg(target);
} else {
PC = PC + sizeof(MachInst);
inst->setPredTarg(PC);
}
predHist[tid].push_front(predict_record);
DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size());
inst->setBranchPred(pred_taken);
return pred_taken;
}
void
BPredUnit::update(const InstSeqNum &done_sn, unsigned tid)
{
DPRINTF(Resource, "BranchPred: [tid:%i]: Commiting branches until sequence"
"number %lli.\n", tid, done_sn);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
BPUpdate(predHist[tid].back().PC,
predHist[tid].back().predTaken,
predHist[tid].back().bpHistory);
predHist[tid].pop_back();
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn, unsigned tid)
{
History &pred_hist = predHist[tid];
while (!pred_hist.empty() &&
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().usedRAS) {
DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
" target: %#x.\n",
tid,
pred_hist.front().RASIndex,
pred_hist.front().RASTarget);
RAS[tid].restore(pred_hist.front().RASIndex,
pred_hist.front().RASTarget);
} else if (pred_hist.front().wasCall) {
DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry "
"added to the RAS.\n",tid);
RAS[tid].pop();
}
// This call should delete the bpHistory.
BPSquash(pred_hist.front().bpHistory);
pred_hist.pop_front();
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn,
const Addr &corr_target,
const bool actually_taken,
unsigned tid)
{
// Now that we know that a branch was mispredicted, we need to undo
// all the branches that have been seen up until this branch and
// fix up everything.
History &pred_hist = predHist[tid];
++condIncorrect;
DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
"setting target to %#x.\n",
tid, squashed_sn, corr_target);
squash(squashed_sn, tid);
// If there's a squash due to a syscall, there may not be an entry
// corresponding to the squash. In that case, don't bother trying to
// fix up the entry.
if (!pred_hist.empty()) {
assert(pred_hist.front().seqNum == squashed_sn);
if (pred_hist.front().usedRAS) {
++RASIncorrect;
}
BPUpdate(pred_hist.front().PC, actually_taken,
pred_hist.front().bpHistory);
BTB.update(pred_hist.front().PC, corr_target, tid);
pred_hist.pop_front();
}
}
void
BPredUnit::BPUncond(void * &bp_history)
{
// Only the tournament predictor cares about unconditional branches.
if (predictor == Tournament) {
tournamentBP->uncondBr(bp_history);
}
}
void
BPredUnit::BPSquash(void *bp_history)
{
if (predictor == Local) {
localBP->squash(bp_history);
} else if (predictor == Tournament) {
tournamentBP->squash(bp_history);
} else {
panic("Predictor type is unexpected value!");
}
}
bool
BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history)
{
if (predictor == Local) {
return localBP->lookup(inst_PC, bp_history);
} else if (predictor == Tournament) {
return tournamentBP->lookup(inst_PC, bp_history);
} else {
panic("Predictor type is unexpected value!");
}
}
void
BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
{
if (predictor == Local) {
localBP->update(inst_PC, taken, bp_history);
} else if (predictor == Tournament) {
tournamentBP->update(inst_PC, taken, bp_history);
} else {
panic("Predictor type is unexpected value!");
}
}
void
BPredUnit::dump()
{
/*typename History::iterator pred_hist_it;
for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
if (!predHist[i].empty()) {
pred_hist_it = predHist[i].begin();
cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
while (pred_hist_it != predHist[i].end()) {
cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
"bpHistory:%#x\n",
(*pred_hist_it).seqNum, (*pred_hist_it).PC,
(*pred_hist_it).tid, (*pred_hist_it).predTaken,
(*pred_hist_it).bpHistory);
pred_hist_it++;
}
cprintf("\n");
}
}*/
}

View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
* Korey Sewell
*/
#ifndef __CPU_INORDER_BPRED_UNIT_HH__
#define __CPU_INORDER_BPRED_UNIT_HH__
// For Addr type.
#include "arch/isa_traits.hh"
#include "base/statistics.hh"
#include "cpu/inst_seq.hh"
//#include "cpu/inorder/params.hh"
#include "cpu/o3/2bit_local_pred.hh"
#include "cpu/o3/btb.hh"
#include "cpu/o3/ras.hh"
#include "cpu/o3/tournament_pred.hh"
#include "params/InOrderCPU.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include <list>
/**
* Basically a wrapper class to hold both the branch predictor
* and the BTB.
*/
class BPredUnit
{
private:
enum PredType {
Local,
Tournament
};
PredType predictor;
public:
/**
* @param params The params object, that has the size of the BP and BTB.
*/
BPredUnit(ThePipeline::Params *params);
/**
* Registers statistics.
*/
void regStats();
void switchOut();
void takeOverFrom();
/**
* Predicts whether or not the instruction is a taken branch, and the
* target of the branch if it is taken.
* @param inst The branch instruction.
* @param PC The predicted PC is passed back through this parameter.
* @param tid The thread id.
* @return Returns if the branch is taken or not.
*/
bool predict(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid);
// @todo: Rename this function.
void BPUncond(void * &bp_history);
/**
* Tells the branch predictor to commit any updates until the given
* sequence number.
* @param done_sn The sequence number to commit any older updates up until.
* @param tid The thread id.
*/
void update(const InstSeqNum &done_sn, unsigned tid);
/**
* Squashes all outstanding updates until a given sequence number.
* @param squashed_sn The sequence number to squash any younger updates up
* until.
* @param tid The thread id.
*/
void squash(const InstSeqNum &squashed_sn, unsigned tid);
/**
* Squashes all outstanding updates until a given sequence number, and
* corrects that sn's update with the proper address and taken/not taken.
* @param squashed_sn The sequence number to squash any younger updates up
* until.
* @param corr_target The correct branch target.
* @param actually_taken The correct branch direction.
* @param tid The thread id.
*/
void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
bool actually_taken, unsigned tid);
/**
* @param bp_history Pointer to the history object. The predictor
* will need to update any state and delete the object.
*/
void BPSquash(void *bp_history);
/**
* Looks up a given PC in the BP to see if it is taken or not taken.
* @param inst_PC The PC to look up.
* @param bp_history Pointer that will be set to an object that
* has the branch predictor state associated with the lookup.
* @return Whether the branch is taken or not taken.
*/
bool BPLookup(Addr &inst_PC, void * &bp_history);
/**
* Looks up a given PC in the BTB to see if a matching entry exists.
* @param inst_PC The PC to look up.
* @return Whether the BTB contains the given PC.
*/
bool BTBValid(Addr &inst_PC)
{ return BTB.valid(inst_PC, 0); }
/**
* Looks up a given PC in the BTB to get the predicted target.
* @param inst_PC The PC to look up.
* @return The address of the target of the branch.
*/
Addr BTBLookup(Addr &inst_PC)
{ return BTB.lookup(inst_PC, 0); }
/**
* Updates the BP with taken/not taken information.
* @param inst_PC The branch's PC that will be updated.
* @param taken Whether the branch was taken or not taken.
* @param bp_history Pointer to the branch predictor state that is
* associated with the branch lookup that is being updated.
* @todo Make this update flexible enough to handle a global predictor.
*/
void BPUpdate(Addr &inst_PC, bool taken, void *bp_history);
/**
* Updates the BTB with the target of a branch.
* @param inst_PC The branch's PC that will be updated.
* @param target_PC The branch's target that will be added to the BTB.
*/
void BTBUpdate(Addr &inst_PC, Addr &target_PC)
{ BTB.update(inst_PC, target_PC,0); }
void dump();
private:
struct PredictorHistory {
/**
* Makes a predictor history struct that contains any
* information needed to update the predictor, BTB, and RAS.
*/
PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
const bool pred_taken, void *bp_history,
const unsigned _tid)
: seqNum(seq_num), PC(inst_PC), RASTarget(0),
RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0),
wasCall(0), bpHistory(bp_history)
{ }
/** The sequence number for the predictor history entry. */
InstSeqNum seqNum;
/** The PC associated with the sequence number. */
Addr PC;
/** The RAS target (only valid if a return). */
Addr RASTarget;
/** The RAS index of the instruction (only valid if a call). */
unsigned RASIndex;
/** The thread id. */
unsigned tid;
/** Whether or not it was predicted taken. */
bool predTaken;
/** Whether or not the RAS was used. */
bool usedRAS;
/** Whether or not the instruction was a call. */
bool wasCall;
/** Pointer to the history object passed back from the branch
* predictor. It is used to update or restore state of the
* branch predictor.
*/
void *bpHistory;
};
typedef std::list<PredictorHistory> History;
/**
* The per-thread predictor history. This is used to update the predictor
* as instructions are committed, or restore it to the proper state after
* a squash.
*/
History predHist[ThePipeline::MaxThreads];
/** The local branch predictor. */
LocalBP *localBP;
/** The tournament branch predictor. */
TournamentBP *tournamentBP;
/** The BTB. */
DefaultBTB BTB;
/** The per-thread return address stack. */
ReturnAddrStack RAS[ThePipeline::MaxThreads];
/** Stat for number of BP lookups. */
Stats::Scalar<> lookups;
/** Stat for number of conditional branches predicted. */
Stats::Scalar<> condPredicted;
/** Stat for number of conditional branches predicted incorrectly. */
Stats::Scalar<> condIncorrect;
/** Stat for number of BTB lookups. */
Stats::Scalar<> BTBLookups;
/** Stat for number of BTB hits. */
Stats::Scalar<> BTBHits;
/** Stat for number of times the BTB is correct. */
Stats::Scalar<> BTBCorrect;
/** Stat for number of times the RAS is used to get a target. */
Stats::Scalar<> usedRAS;
/** Stat for number of times the RAS is incorrect. */
Stats::Scalar<> RASIncorrect;
};
#endif // __CPU_INORDER_BPRED_UNIT_HH__

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resources/branch_predictor.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu),
branchPred(params)
{
instSize = sizeof(MachInst);
}
void
BranchPredictor::regStats()
{
predictedTaken
.name(name() + ".predictedTaken")
.desc("Number of Branches Predicted As Taken (True).");
predictedNotTaken
.name(name() + ".predictedNotTaken")
.desc("Number of Branches Predicted As Not Taken (False).");
Resource::regStats();
}
void
BranchPredictor::execute(int slot_num)
{
// After this is working, change this to a reinterpret cast
// for performance considerations
ResourceRequest* bpred_req = reqMap[slot_num];
DynInstPtr inst = bpred_req->inst;
int tid = inst->readTid();
int seq_num = inst->seqNum;
//int stage_num = bpred_req->getStageNum();
bpred_req->fault = NoFault;
switch (bpred_req->cmd)
{
case PredictBranch:
{
Addr pred_PC = inst->readNextPC();
if (inst->isControl()) {
// If predicted, the pred_PC will be updated to new target value
// If not, the pred_PC be updated to pc+8
bool predict_taken = branchPred.predict(inst, pred_PC, tid);
if (predict_taken) {
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n",
tid, seq_num);
inst->setPredTarg(pred_PC);
predictedTaken++;
} else {
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted false.\n",
tid, seq_num);
if (inst->isCondDelaySlot())
{
inst->setPredTarg(inst->readPC() + (2 * instSize));
} else {
inst->setPredTarg(pred_PC);
}
predictedNotTaken++;
}
inst->setBranchPred(predict_taken);
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n",
tid, seq_num, pred_PC);
} else {
DPRINTF(Resource, "[tid:%i]: Ignoring [sn:%i] because this isn't "
"a control instruction.\n", tid, seq_num);
}
bpred_req->done();
}
break;
case UpdatePredictor:
{
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n",
tid, seq_num);
branchPred.update(seq_num, tid);
bpred_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
void
BranchPredictor::squash(DynInstPtr inst, int squash_stage,
InstSeqNum squash_seq_num, unsigned tid)
{
DPRINTF(Resource, "Squashing...\n");
branchPred.squash(squash_seq_num, tid);
}
void
BranchPredictor::instGraduated(InstSeqNum seq_num,unsigned tid)
{
branchPred.update(seq_num, tid);
}

View file

@ -0,0 +1,87 @@
/*
* 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 <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/resources/bpred_unit.hh"
#include "cpu/inorder/cpu.hh"
//#include "cpu/inorder/params.hh"
class BranchPredictor : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
enum Command {
PredictBranch,
UpdatePredictor
};
public:
BranchPredictor(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual void regStats();
virtual void execute(int slot_num);
virtual void squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, unsigned tid);
virtual void instGraduated(InstSeqNum seq_num,unsigned 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__

View file

@ -0,0 +1,609 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "arch/isa_traits.hh"
#include "arch/mips/locked_mem.hh"
#include "arch/utility.hh"
#include "cpu/inorder/resources/cache_unit.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
#include "mem/request.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
Tick
CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
{
panic("DefaultFetch doesn't expect recvAtomic callback!");
return curTick;
}
void
CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
{
panic("DefaultFetch doesn't expect recvFunctional callback!");
}
void
CacheUnit::CachePort::recvStatusChange(Status status)
{
if (status == RangeChange)
return;
panic("DefaultFetch doesn't expect recvStatusChange callback!");
}
bool
CacheUnit::CachePort::recvTiming(Packet *pkt)
{
cachePortUnit->processCacheCompletion(pkt);
return true;
}
void
CacheUnit::CachePort::recvRetry()
{
cachePortUnit->recvRetry();
}
CacheUnit::CacheUnit(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu),
retryPkt(NULL), retrySlot(-1)
{
//cacheData.resize(res_width);
//slotStatus = new CachePortStatus[width];
//fetchPC = new Addr[width];
cachePort = new CachePort(this);
cacheBlocked = false;
}
Port *
CacheUnit::getPort(const std::string &if_name, int idx)
{
if (if_name == resName)
return cachePort;
else
return NULL;
}
int
CacheUnit::getSlot(DynInstPtr inst)
{
if (!inst->validMemAddr()) {
panic("Mem. Addr. must be set before requesting cache access.\n");
}
Addr req_addr = inst->getMemAddr();
if (resName == "icache_port" ||
find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) {
int new_slot = Resource::getSlot(inst);
if (new_slot != -1) {
inst->memTime = curTick;
addrList.push_back(req_addr);
addrMap[req_addr] = inst->seqNum;
DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Address %08p added to dependency list.\n",
inst->readTid(), inst->seqNum, req_addr);
return new_slot;
} else {
return -1;
}
} else {
DPRINTF(InOrderCachePort,"Denying request because there is an outstanding"
" request to/for addr. %08p. by [sn:%i] @ tick %i\n",
req_addr, addrMap[req_addr], inst->memTime);
return -1;
}
}
void
CacheUnit::freeSlot(int slot_num)
{
std::vector<Addr>::iterator vect_it = find(addrList.begin(), addrList.end(),
reqMap[slot_num]->inst->getMemAddr());
assert(vect_it != addrList.end());
DPRINTF(InOrderCachePort, "[tid:%i]: Address %08p removed from dependency list.\n",
reqMap[slot_num]->inst->readTid(), (*vect_it));
addrList.erase(vect_it);
Resource::freeSlot(slot_num);
}
ResReqPtr
CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
ScheduleEntry* sched_entry = inst->resSched.top();
if (!inst->validMemAddr()) {
panic("Mem. Addr. must be set before requesting cache access.\n");
}
int req_size = 0;
MemCmd::Command pkt_cmd;
if (sched_entry->cmd == InitiateReadData) {
pkt_cmd = MemCmd::ReadReq;
req_size = inst->getMemAccSize();
DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p.\n",
inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
} else if (sched_entry->cmd == InitiateWriteData) {
pkt_cmd = MemCmd::WriteReq;
req_size = inst->getMemAccSize();
DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p.\n",
inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
} else if (sched_entry->cmd == InitiateFetch){
pkt_cmd = MemCmd::ReadReq;
req_size = sizeof(MachInst); //@TODO: mips16e
DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p.\n",
inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
} else {
panic("%i: Unexpected request type (%i) to %s", curTick, sched_entry->cmd, name());
}
return new CacheRequest(this, inst, stage_num, id, slot_num,
sched_entry->cmd, req_size, pkt_cmd,
0/*flags*/, this->cpu->readCpuId());
}
void
CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
{
//service_request = false;
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
assert(cache_req);
// Check to see if this instruction is requesting the same command
// or a different one
if (cache_req->cmd != inst->resSched.top()->cmd) {
// If different, then update command in the request
cache_req->cmd = inst->resSched.top()->cmd;
DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Updating the command for this "
"instruction.\n", inst->readTid(), inst->seqNum);
service_request = true;
} else {
// If same command, just check to see if memory access was completed
// but dont try to re-execute
DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: requesting this resource again.\n",
inst->readTid(), inst->seqNum);
service_request = true;
}
}
void
CacheUnit::execute(int slot_num)
{
if (cacheBlocked) {
DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access.\n");
return;
}
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
assert(cache_req);
DynInstPtr inst = cache_req->inst;
int tid;
tid = inst->readTid();
int seq_num;
seq_num = inst->seqNum;
//int stage_num = cache_req->getStageNum();
cache_req->fault = NoFault;
switch (cache_req->cmd)
{
case InitiateFetch:
{
DPRINTF(InOrderCachePort,
"[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
tid, name(), cache_req->inst->getMemAddr());
DPRINTF(InOrderCachePort,
"[tid:%u]: Fetching new cache block from addr: %08p\n",
tid, cache_req->memReq->getVaddr());
inst->setCurResSlot(slot_num);
doDataAccess(inst);
}
break;
case CompleteFetch:
{
if (cache_req->isMemAccComplete()) {
DPRINTF(InOrderCachePort,
"[tid:%i]: Completing Fetch Access for [sn:%i]\n",
tid, inst->seqNum);
MachInst mach_inst = cache_req->dataPkt->get<MachInst>();
//@TODO: May Need This Function for Endianness-Compatibility
//mach_inst = gtoh(*reinterpret_cast<MachInst *>(&cacheData[tid][offset]));
DPRINTF(InOrderCachePort,
"[tid:%i]: Fetched instruction is %08p\n",
tid, mach_inst);
//ExtMachInst ext_inst
// = TheISA::makeExtMI(mach_inst, cpu->tcBase(tid));
inst->setMachInst(mach_inst);
inst->setASID(tid);
inst->setThreadState(cpu->thread[tid]);
DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n",
tid, seq_num, inst->staticInst->disassemble(inst->PC));
// Set Up More TraceData info
if (inst->traceData) {
inst->traceData->setStaticInst(inst->staticInst);
inst->traceData->setPC(inst->readPC());
}
cache_req->done();
} else {
DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access.\n",
tid, inst->seqNum);
DPRINTF(InOrderStall, "STALL: [tid:%i]: Fetch miss from %08p.\n",
tid, cache_req->inst->readPC());
cache_req->setCompleted(false);
}
}
break;
case InitiateReadData:
case InitiateWriteData:
{
DPRINTF(InOrderCachePort, "[tid:%u]: Initiating data access to %s "
"for addr. %08p\n",
tid, name(), cache_req->inst->getMemAddr());
inst->setCurResSlot(slot_num);
//inst->memAccess();
inst->initiateAcc();
}
break;
case CompleteReadData:
case CompleteWriteData:
{
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Trying to Complete Data Access.\n",
tid, inst->seqNum);
if (cache_req->isMemAccComplete()) {
cache_req->done();
} else {
DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
tid, cache_req->inst->getMemAddr());
cache_req->setCompleted(false);
}
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
Fault
CacheUnit::doDataAccess(DynInstPtr inst)
{
Fault fault = NoFault;
int tid = 0;
tid = inst->readTid();
CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
assert(cache_req);
cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd,
Packet::Broadcast);
if (cache_req->dataPkt->isRead()) {
cache_req->dataPkt->dataStatic(cache_req->reqData);
} else if (cache_req->dataPkt->isWrite()) {
cache_req->dataPkt->dataStatic(&cache_req->inst->storeData);
}
cache_req->dataPkt->time = curTick;
bool do_access = true; // flag to suppress cache access
Request *memReq = cache_req->dataPkt->req;
if (cache_req->dataPkt->isWrite() && memReq->isLocked()) {
assert(cache_req->inst->isStoreConditional());
DPRINTF(InOrderCachePort, "Evaluating Store Conditional access.\n");
do_access = TheISA::handleLockedWrite(cpu, memReq);
}
DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] attempting to access cache..\n", tid, inst->seqNum);
//@TODO: If you want to ignore failed store conditional accesses, then
// enable this. However, this might skew memory stats because
// the failed store conditional access will get ignored.
// - Remove optionality here ...
if (1/*do_access*/) {
if (!cachePort->sendTiming(cache_req->dataPkt)) {
DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is waiting to retry request.\n", tid, inst->seqNum);
retrySlot = cache_req->getSlot();
retryReq = cache_req;
retryPkt = cache_req->dataPkt;
cacheStatus = cacheWaitRetry;
//cacheBlocked = true;
DPRINTF(InOrderStall, "STALL: \n");
cache_req->setCompleted(false);
} else {
DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is now waiting for cache response.\n", tid, inst->seqNum);
cache_req->setCompleted();
cache_req->setMemAccPending();
cacheStatus = cacheWaitResponse;
cacheBlocked = false;
}
} else if (!do_access && memReq->isLocked()){
// Store-Conditional instructions complete even if they "failed"
assert(cache_req->inst->isStoreConditional());
cache_req->setCompleted(true);
DPRINTF(LLSC, "[tid:%i]: T%i Ignoring Failed Store Conditional Access.\n",
tid, tid);
cache_req->dataPkt->req->setExtraData(0);
processCacheCompletion(cache_req->dataPkt);
// Automatically set these since we ignored the memory access
//cache_req->setMemAccPending(false);
//cache_req->setMemAccCompleted();
} else {
// Make cache request again since access due to
// inability to access
DPRINTF(InOrderStall, "STALL: \n");
cache_req->setCompleted(false);
}
return fault;
}
void
CacheUnit::processCacheCompletion(PacketPtr pkt)
{
// Cast to correct packet type
CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
assert(cache_pkt);
if (cache_pkt->cacheReq->isSquashed()) {
DPRINTF(InOrderCachePort,
"Ignoring completion of squashed access, [tid:%i] [sn:%i].\n",
cache_pkt->cacheReq->getInst()->readTid(),
cache_pkt->cacheReq->getInst()->seqNum);
cache_pkt->cacheReq->done();
return;
} else {
DPRINTF(InOrderCachePort,
"[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p.\n",
cache_pkt->cacheReq->getInst()->readTid(),
cache_pkt->cacheReq->getInst()->seqNum,
cache_pkt->cacheReq->getInst()->getMemAddr());
}
// Cast to correct request type
CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
findRequest(cache_pkt->cacheReq->getInst()));
assert(cache_req);
#if TRACING_ON
// Get resource request info
unsigned tid = 0;
#endif
//tid = pkt->req->getThreadNum();
unsigned stage_num = cache_req->getStageNum();
DynInstPtr inst = cache_req->inst;
if (!cache_req->isSquashed()) {
if (inst->resSched.top()->cmd == CompleteFetch) {
DPRINTF(InOrderCachePort,
"[tid:%u]: [sn:%i]: Processing fetch access.\n",
tid, inst->seqNum);
} else if (inst->staticInst && inst->isMemRef()) {
DPRINTF(InOrderCachePort,
"[tid:%u]: [sn:%i]: Processing cache access.\n",
tid, inst->seqNum);
inst->completeAcc(pkt);
if (inst->isLoad()) {
assert(cache_pkt->isRead());
if (cache_pkt->req->isLocked()) {
DPRINTF(InOrderCachePort, "[tid:%u]: Handling Load-Linked "
"access for [sn:%u].\n", tid, inst->seqNum);
TheISA::handleLockedRead(cpu, cache_pkt->req);
}
// @TODO: Hardcoded to for load instructions. Assumes that
// the dest. idx 0 is always where the data is loaded to.
DPRINTF(InOrderCachePort,
"[tid:%u]: [sn:%i]: Data loaded was: %08p.\n",
tid, inst->seqNum, inst->readIntResult(0));
} else if(inst->isStore()) {
assert(cache_pkt->isWrite());
DPRINTF(InOrderCachePort,
"[tid:%u]: [sn:%i]: Data stored was: %08p.\n",
tid, inst->seqNum,
getMemData(cache_pkt));
}
}
cache_req->setMemAccPending(false);
cache_req->setMemAccCompleted();
// Wake up the CPU (if it went to sleep and was waiting on this
// completion event).
cpu->wakeCPU();
DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n",
tid, cpu->pipelineStage[stage_num]->name());
cpu->switchToActive(stage_num);
} else {
DPRINTF(InOrderCachePort,
"[tid:%u] Cache miss on memory access to block @ %08p "
"completed, but squashed.\n", tid, cache_req->inst->readPC());
cache_req->setMemAccCompleted();
}
inst->unsetMemAddr();
}
void
CacheUnit::recvRetry()
{
DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i].\n",
retryReq->inst->readTid(), retryReq->inst->seqNum);
assert(retryPkt != NULL);
assert(cacheBlocked);
assert(cacheStatus == cacheWaitRetry);
if (cachePort->sendTiming(retryPkt)) {
cacheStatus = cacheWaitResponse;
retryPkt = NULL;
cacheBlocked = false;
} else {
DPRINTF(InOrderCachePort, "Retry Request for [tid:%i] [sn:%i] failed.\n",
retryReq->inst->readTid(), retryReq->inst->seqNum);
}
}
void
CacheUnit::squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, unsigned tid)
{
std::vector<int> slot_remove_list;
std::map<int, ResReqPtr>::iterator map_it = reqMap.begin();
std::map<int, ResReqPtr>::iterator map_end = reqMap.end();
while (map_it != map_end) {
ResReqPtr req_ptr = (*map_it).second;
if (req_ptr &&
req_ptr->getInst()->readTid() == tid &&
req_ptr->getInst()->seqNum > squash_seq_num) {
DPRINTF(InOrderCachePort,
"[tid:%i] Squashing request from [sn:%i].\n",
req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
req_ptr->setSquashed();
req_ptr->getInst()->setSquashed();
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr);
assert(cache_req);
if (!cache_req->isMemAccPending()) {
// Mark request for later removal
cpu->reqRemoveList.push(req_ptr);
// Mark slot for removal from resource
slot_remove_list.push_back(req_ptr->getSlot());
}
}
map_it++;
}
// Now Delete Slot Entry from Req. Map
for (int i = 0; i < slot_remove_list.size(); i++) {
freeSlot(slot_remove_list[i]);
}
}
uint64_t CacheUnit::getMemData(Packet *packet) {
switch (packet->getSize())
{
case 8:
return packet->get<uint8_t>();
case 16:
return packet->get<uint16_t>();
case 32:
return packet->get<uint32_t>();
case 864:
return packet->get<uint64_t>();
default:
std::cerr << "bad store data size = " << packet->getSize() << std::endl;
assert(0);
return 0;
}
}

View file

@ -0,0 +1,305 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_CACHE_UNIT_HH__
#define __CPU_INORDER_CACHE_UNIT_HH__
#include <vector>
#include <list>
#include <string>
//#include "cpu/inorder/params.hh"
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "mem/port.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "sim/sim_object.hh"
#include "params/InOrderCPU.hh"
class CacheRequest;
typedef CacheRequest* CacheReqPtr;
class CacheReqPacket;
typedef CacheReqPacket* CacheReqPktPtr;
class CacheUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
CacheUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~CacheUnit() {}
enum Command {
InitiateFetch,
CompleteFetch,
InitiateReadData,
CompleteReadData,
InitiateWriteData,
CompleteWriteData,
Fetch,
ReadData,
WriteData
};
public:
/** CachePort class for the Cache Unit. Handles doing the
* communication with the cache/memory.
*/
class CachePort : public Port
{
protected:
/** Pointer to cache port unit */
CacheUnit *cachePortUnit;
public:
/** Default constructor. */
CachePort(CacheUnit *_cachePortUnit)
: Port(_cachePortUnit->name() + "-cache-port", (MemObject*)_cachePortUnit->cpu),
cachePortUnit(_cachePortUnit)
{ }
bool snoopRangeSent;
protected:
/** Atomic version of receive. Panics. */
virtual Tick recvAtomic(PacketPtr pkt);
/** Functional version of receive. Panics. */
virtual void recvFunctional(PacketPtr pkt);
/** Receives status change. Other than range changing, panics. */
virtual void recvStatusChange(Status status);
/** Returns the address ranges of this device. */
virtual void getDeviceAddressRanges(AddrRangeList &resp,
AddrRangeList &snoop)
{ resp.clear(); snoop.clear(); }
/** Timing version of receive. Handles setting fetch to the
* proper status to start fetching. */
virtual bool recvTiming(PacketPtr pkt);
/** Handles doing a retry of a failed fetch. */
virtual void recvRetry();
};
enum CachePortStatus {
cacheWaitResponse,
cacheWaitRetry,
cacheAccessComplete
};
///virtual void init();
virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
int res_idx, int slot_num,
unsigned cmd);
void requestAgain(DynInstPtr inst, bool &try_request);
int getSlot(DynInstPtr inst);
void freeSlot(int slot_num);
/** Execute the function of this resource. The Default is action
* is to do nothing. More specific models will derive from this
* class and define their own execute function.
*/
void execute(int slot_num);
void squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, unsigned tid);
/** Processes cache completion event. */
void processCacheCompletion(PacketPtr pkt);
void recvRetry();
/** Align a PC to the start of an I-cache block. */
Addr cacheBlockAlignPC(Addr addr)
{
//addr = TheISA::realPCToFetchPC(addr);
return (addr & ~(cacheBlkMask));
}
/** Returns a specific port. */
Port *getPort(const std::string &if_name, int idx);
/** Fetch on behalf of an instruction. Will check to see
* if instruction is actually in resource before
* trying to fetch.
*/
//Fault doFetchAccess(DynInstPtr inst);
/** Read/Write on behalf of an instruction.
* curResSlot needs to be a valid value in instruction.
*/
Fault doDataAccess(DynInstPtr inst);
uint64_t getMemData(Packet *packet);
protected:
/** Cache interface. */
CachePort *cachePort;
CachePortStatus cacheStatus;
CacheReqPtr retryReq;
PacketPtr retryPkt;
int retrySlot;
bool cacheBlocked;
std::vector<Addr> addrList;
std::map<Addr, InstSeqNum> addrMap;
public:
int cacheBlkSize;
int cacheBlkMask;
/** Align a PC to the start of the Cache block. */
Addr cacheBlockAlign(Addr addr)
{
return (addr & ~(cacheBlkMask));
}
/** THINGS USED FOR FETCH */
// NO LONGER USED BY COMMENT OUT UNTIL FULL VERIFICATION
/** The mem line being fetched. */
//uint8_t *cacheData[ThePipeline::MaxThreads];
/** The Addr of the cacheline that has been loaded. */
//Addr cacheBlockAddr[ThePipeline::MaxThreads];
//unsigned fetchOffset[ThePipeline::MaxThreads];
/** @todo: Add Resource Stats Here */
};
struct CacheSchedEntry : public ThePipeline::ScheduleEntry {
enum EntryType {
FetchAccess,
DataAccess
};
CacheSchedEntry(int stage_num, int _priority, int res_num, MemCmd::Command pkt_cmd,
EntryType _type = FetchAccess) :
ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd),
type(_type)
{ }
MemCmd::Command pktCmd;
EntryType type;
};
class CacheRequest : public ResourceRequest {
public:
CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd, int req_size,
MemCmd::Command pkt_cmd, unsigned flags, int cpu_id)
: ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd),
pktCmd(pkt_cmd), memAccComplete(false), memAccPending(false)
{
memReq = inst->memReq;
reqData = new uint8_t[req_size];
retryPkt = NULL;
}
virtual ~CacheRequest()
{
/*
delete reqData;
Can get rid of packet and packet request now
if (*dataPkt) {
if (*dataPkt->req) {
delete dataPkt->req;
}
delete dataPkt;
}
// Can get rid of packet and packet request now
if (retryPkt) {
if (retryPkt->req) {
delete retryPkt->req;
}
delete retryPkt;
}*/
if (memReq) {
delete memReq;
}
}
virtual PacketDataPtr getData()
{ return reqData; }
void setMemAccCompleted(bool completed = true) { memAccComplete = completed; }
bool isMemAccComplete() { return memAccComplete; }
void setMemAccPending(bool pending = true) { memAccPending = pending; }
bool isMemAccPending() { return memAccPending; }
//Make this data private/protected!
MemCmd::Command pktCmd;
RequestPtr memReq;
PacketDataPtr reqData;
PacketPtr dataPkt;
PacketPtr retryPkt;
bool memAccComplete;
bool memAccPending;
};
class CacheReqPacket : public Packet {
public:
CacheReqPacket(CacheRequest *_req,
Command _cmd, short _dest)
: Packet(_req->memReq, _cmd, _dest), cacheReq(_req)
{
}
CacheRequest *cacheReq;
};
#endif //__CPU_CACHE_UNIT_HH__

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resources/decode_unit.hh"
using namespace TheISA;
using namespace ThePipeline;
using namespace std;
DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{
for (int tid = 0; tid < MaxThreads; tid++) {
regDepMap[tid] = &cpu->archRegDepMap[tid];
}
}
void
DecodeUnit::execute(int slot_num)
{
ResourceRequest* decode_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
Fault fault = reqMap[slot_num]->fault;
int tid, seq_num;
tid = inst->readTid();
seq_num = inst->seqNum;
decode_req->fault = NoFault;
switch (decode_req->cmd)
{
case DecodeInst:
{
bool done_sked = ThePipeline::createBackEndSchedule(inst);
if (done_sked) {
DPRINTF(Resource, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n",
tid, seq_num);
regDepMap[tid]->insert(inst);
decode_req->done();
} else {
DPRINTF(Resource,"[tid:%i] Static Inst not available to decode. Unable to create "
"schedule for instruction [sn:%i] \n", tid, inst->seqNum);
DPRINTF(InOrderStall, "STALL: \n");
decode_req->done(false);
}
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
void
DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
{
DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n",
tid, stage_num, squash_seq_num);
//cpu->removeInstsUntil(squash_seq_num, tid);
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_DECODE_UNIT_HH__
#define __CPU_INORDER_DECODE_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
#include "cpu/inorder/reg_dep_map.hh"
class DecodeUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
DecodeUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~DecodeUnit() {}
enum Command {
DecodeInst
};
virtual void execute(int slot_num);
void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
RegDepMap *regDepMap[ThePipeline::MaxThreads];
protected:
/** @todo: Add Resource Stats Here */
};
#endif //__CPU_INORDER_DECODE_UNIT_HH__

View file

@ -0,0 +1,182 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "cpu/inorder/resources/execution_unit.hh"
#include "cpu/inorder/resource_pool.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace ThePipeline;
ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{ }
void
ExecutionUnit::regStats()
{
predictedTakenIncorrect
.name(name() + ".predictedTakenIncorrect")
.desc("Number of Branches Incorrectly Predicted As Taken.");
predictedNotTakenIncorrect
.name(name() + ".predictedNotTakenIncorrect")
.desc("Number of Branches Incorrectly Predicted As Not Taken).");
Resource::regStats();
}
void
ExecutionUnit::execute(int slot_num)
{
ResourceRequest* exec_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
Fault fault = reqMap[slot_num]->fault;
int tid = inst->readTid();
int seq_num = inst->seqNum;
exec_req->fault = NoFault;
DPRINTF(Resource, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n",
tid, seq_num, inst->readPC());
switch (exec_req->cmd)
{
case ExecuteInst:
{
if (inst->isMemRef()) {
fatal("%s not configured to handle memory ops.\n", resName);
} else if (inst->isControl()) {
// Evaluate Branch
fault = inst->execute();
inst->setExecuted();
if (fault == NoFault) {
// If branch is mispredicted, then signal squash
// throughout all stages behind the pipeline stage
// that got squashed.
if (inst->mispredicted()) {
int stage_num = exec_req->getStageNum();
int tid = inst->readTid();
// If it's a branch ...
if (inst->isDirectCtrl()) {
assert(!inst->isIndirectCtrl());
if (inst->predTaken() && inst->isCondDelaySlot()) {
inst->bdelaySeqNum = seq_num;
inst->setPredTarg(inst->nextPC);
DPRINTF(Resource, "[tid:%i]: Conditional branch inst"
"[sn:%i] PC %#x mispredicted as taken.\n", tid,
seq_num, inst->PC);
} else if (!inst->predTaken() && inst->isCondDelaySlot()) {
inst->bdelaySeqNum = seq_num;
inst->setPredTarg(inst->nextPC);
inst->procDelaySlotOnMispred = true;
DPRINTF(Resource, "[tid:%i]: Conditional branch inst."
"[sn:%i] PC %#x mispredicted as not taken.\n", tid,
seq_num, inst->PC);
} else {
inst->bdelaySeqNum = seq_num + 1;
DPRINTF(Resource, "[tid:%i]: Misprediction detected at "
"[sn:%i] PC %#x,\n\t squashing after delay slot "
"instruction [sn:%i].\n",
tid, seq_num, inst->PC, inst->bdelaySeqNum);
DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch "
"misprediction at %#x\n", tid, inst->PC);
inst->setPredTarg(inst->nextNPC);
}
DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid,
inst->readPredTarg());
} else if(inst->isIndirectCtrl()){
inst->setPredTarg(inst->nextNPC);
inst->bdelaySeqNum = seq_num + 1;
DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid,
inst->readPredTarg());
} else {
panic("Non-control instruction (%s) mispredicting?!!",
inst->staticInst->getName());
}
DPRINTF(Resource, "[tid:%i] Squashing will start from stage %i.\n",
tid, stage_num);
cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
inst->squashingStage = stage_num;
// Squash throughout other resources
cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll,
inst, 0, 0, tid);
if (inst->predTaken()) {
predictedTakenIncorrect++;
} else {
predictedNotTakenIncorrect++;
}
}
exec_req->done();
} else {
warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
}
} else {
// Regular ALU instruction
fault = inst->execute();
if (fault == NoFault) {
inst->setExecuted();
exec_req->done();
DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
inst->readTid(), inst->readIntResult(0));
} else {
warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
cpu->trap(fault, tid);
}
}
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}

View file

@ -0,0 +1,77 @@
/*
* 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 <vector>
#include <list>
#include <string>
#include "cpu/func_unit.hh"
#include "cpu/inorder/first_stage.hh"
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
class ExecutionUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
enum Command {
ExecuteInst
};
public:
ExecutionUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~ExecutionUnit() {}
public:
virtual 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.
*/
virtual void execute(int slot_num);
protected:
/////////////////////////////////////////////////////////////////
//
// RESOURCE STATISTICS
//
/////////////////////////////////////////////////////////////////
Stats::Scalar<> predictedTakenIncorrect;
Stats::Scalar<> predictedNotTakenIncorrect;
};
#endif //__CPU_INORDER_EXCUTION_UNIT_HH__

View file

@ -0,0 +1,324 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resources/fetch_seq_unit.hh"
#include "cpu/inorder/resource_pool.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{
instSize = sizeof(MachInst);
for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
delaySlotInfo[tid].numInsts = 0;
delaySlotInfo[tid].targetReady = false;
pcValid[tid] = false;
pcBlockStage[tid] = 0;
squashSeqNum[tid] = (InstSeqNum)-1;
lastSquashCycle[tid] = 0;
}
}
void
FetchSeqUnit::init()
{
resourceEvent = new FetchSeqEvent[width];
initSlots();
}
void
FetchSeqUnit::execute(int slot_num)
{
// After this is working, change this to a reinterpret cast
// for performance considerations
ResourceRequest* fs_req = reqMap[slot_num];
DynInstPtr inst = fs_req->inst;
int tid = inst->readTid();
int stage_num = fs_req->getStageNum();
int seq_num = inst->seqNum;
fs_req->fault = NoFault;
switch (fs_req->cmd)
{
case AssignNextPC:
{
if (pcValid[tid]) {
if (delaySlotInfo[tid].targetReady &&
delaySlotInfo[tid].numInsts == 0) {
// Set PC to target
PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC
nextPC[tid] = PC[tid] + instSize; //next_NPC
nextNPC[tid] = PC[tid] + (2 * instSize);
delaySlotInfo[tid].targetReady = false;
DPRINTF(Resource, "[tid:%i]: Setting PC to delay slot target\n",tid);
}
inst->setPC(PC[tid]);
inst->setNextPC(PC[tid] + instSize);
inst->setNextNPC(PC[tid] + (instSize * 2));
inst->setPredTarg(inst->readNextNPC());
inst->setMemAddr(PC[tid]);
inst->setSeqNum(cpu->getAndIncrementInstSeq(tid));
DPRINTF(Resource, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid,
inst->seqNum, inst->readPC());
if (delaySlotInfo[tid].numInsts > 0) {
--delaySlotInfo[tid].numInsts;
// It's OK to set PC to target of branch
if (delaySlotInfo[tid].numInsts == 0) {
delaySlotInfo[tid].targetReady = true;
}
DPRINTF(Resource, "[tid:%i]: %i delay slot inst(s) left to"
" process.\n", tid, delaySlotInfo[tid].numInsts);
}
PC[tid] = nextPC[tid];
nextPC[tid] = nextNPC[tid];
nextNPC[tid] += instSize;
fs_req->done();
} else {
DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid);
fs_req->setCompleted(false);
}
}
break;
case UpdateTargetPC:
{
if (inst->isControl()) {
// If it's a return, then we must wait for resolved address.
if (inst->isReturn() && !inst->predTaken()) {
cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true;
pcValid[tid] = false;
pcBlockStage[tid] = stage_num;
} else if (inst->isCondDelaySlot() && !inst->predTaken()) {
// Not-Taken AND Conditional Control
DPRINTF(Resource, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. "
"Delay inst. Skipping delay slot and Updating PC to %08p\n",
tid, inst->seqNum, inst->readPC(), inst->readPredTarg());
DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
tid, stage_num, seq_num);
inst->bdelaySeqNum = seq_num;
inst->squashingStage = stage_num;
squashAfterInst(inst, stage_num, tid);
} else if (!inst->isCondDelaySlot() && !inst->predTaken()) {
// Not-Taken Control
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control "
"inst. updating PC to %08p\n", tid, inst->seqNum,
inst->readNextPC());
++delaySlotInfo[tid].numInsts;
delaySlotInfo[tid].targetReady = false;
delaySlotInfo[tid].targetAddr = inst->readNextNPC();
} else if (inst->predTaken()) {
// Taken Control
++delaySlotInfo[tid].numInsts;
delaySlotInfo[tid].targetReady = false;
delaySlotInfo[tid].targetAddr = inst->readPredTarg();
DPRINTF(Resource, "[tid:%i]: [sn:%i] Updating delay slot target "
"to PC %08p\n", tid, inst->seqNum, inst->readPredTarg());
// Set-Up Squash Through-Out Pipeline
DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
tid, stage_num, seq_num + 1);
inst->bdelaySeqNum = seq_num + 1;
inst->squashingStage = stage_num;
// Do Squashing
squashAfterInst(inst, stage_num, tid);
}
} else {
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Ignoring branch target update "
"since then is not a control instruction.\n", tid, inst->seqNum);
}
fs_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
inline void
FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid)
{
// Squash In Pipeline Stage
cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
// Squash inside current resource, so if there needs to be fetching on same cycle
// the fetch information will be correct.
// squash(inst, stage_num, inst->bdelaySeqNum, tid);
// Schedule Squash Through-out Resource Pool
cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
}
void
FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
InstSeqNum squash_seq_num, unsigned tid)
{
DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i.\n",
tid, squash_stage);
InstSeqNum done_seq_num = inst->bdelaySeqNum;
Addr new_PC = inst->readPredTarg();
if (squashSeqNum[tid] <= done_seq_num &&
lastSquashCycle[tid] == curTick) {
DPRINTF(Resource, "[tid:%i]: Ignoring squash from stage %i, since"
"there is an outstanding squash that is older.\n",
tid, squash_stage);
} else {
squashSeqNum[tid] = done_seq_num;
lastSquashCycle[tid] = curTick;
// If The very next instruction number is the done seq. num,
// then we haven't seen the delay slot yet ... if it isn't
// the last done_seq_num then this is the delay slot inst.
if (cpu->nextInstSeqNum(tid) != done_seq_num &&
!inst->procDelaySlotOnMispred) {
delaySlotInfo[tid].numInsts = 0;
delaySlotInfo[tid].targetReady = false;
// Reset PC
PC[tid] = new_PC;
nextPC[tid] = new_PC + instSize;
nextNPC[tid] = new_PC + (2 * instSize);
DPRINTF(Resource, "[tid:%i]: Setting PC to %08p.\n",
tid, PC[tid]);
} else {
delaySlotInfo[tid].numInsts = 1;
delaySlotInfo[tid].targetReady = false;
delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ? inst->branchTarget() : new_PC;
// Reset PC to Delay Slot Instruction
if (inst->procDelaySlotOnMispred) {
PC[tid] = new_PC;
nextPC[tid] = new_PC + instSize;
nextNPC[tid] = new_PC + (2 * instSize);
}
}
// Unblock Any Stages Waiting for this information to be updated ...
if (!pcValid[tid]) {
cpu->pipelineStage[pcBlockStage[tid]]->toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
}
pcValid[tid] = true;
}
Resource::squash(inst, squash_stage, squash_seq_num, tid);
}
FetchSeqUnit::FetchSeqEvent::FetchSeqEvent()
: ResourceEvent()
{ }
void
FetchSeqUnit::FetchSeqEvent::process()
{
FetchSeqUnit* fs_res = dynamic_cast<FetchSeqUnit*>(resource);
assert(fs_res);
for (int i=0; i < MaxThreads; i++) {
fs_res->PC[i] = fs_res->cpu->readPC(i);
fs_res->nextPC[i] = fs_res->cpu->readNextPC(i);
fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i);
DPRINTF(Resource, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n",
fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]);
fs_res->pcValid[i] = true;
}
//cpu->fetchPriorityList.push_back(tid);
}
void
FetchSeqUnit::activateThread(unsigned tid)
{
pcValid[tid] = true;
PC[tid] = cpu->readPC(tid);
nextPC[tid] = cpu->readNextPC(tid);
nextNPC[tid] = cpu->readNextNPC(tid);
cpu->fetchPriorityList.push_back(tid);
DPRINTF(Resource, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n",
tid, PC[tid], nextPC[tid], nextNPC[tid]);
}
void
FetchSeqUnit::deactivateThread(unsigned tid)
{
delaySlotInfo[tid].numInsts = 0;
delaySlotInfo[tid].targetReady = false;
pcValid[tid] = false;
pcBlockStage[tid] = 0;
squashSeqNum[tid] = (InstSeqNum)-1;
lastSquashCycle[tid] = 0;
std::list<unsigned>::iterator thread_it = find(cpu->fetchPriorityList.begin(),
cpu->fetchPriorityList.end(),
tid);
if (thread_it != cpu->fetchPriorityList.end())
cpu->fetchPriorityList.erase(thread_it);
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_FETCH_SEQ_UNIT_HH__
#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
using namespace ThePipeline;
class FetchSeqUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
enum Command {
AssignNextPC,
UpdateTargetPC
};
public:
FetchSeqUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~FetchSeqUnit() {}
virtual void init();
virtual void activateThread(unsigned tid);
virtual void deactivateThread(unsigned tid);
virtual void execute(int slot_num);
/** Override default Resource squash sequence. This actually,
* looks in the global communication buffer to get squash
* info
*/
virtual void squash(DynInstPtr inst, int squash_stage,
InstSeqNum squash_seq_num, unsigned tid);
inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid);
protected:
unsigned instSize;
bool pcValid[ThePipeline::MaxThreads];
int pcBlockStage[ThePipeline::MaxThreads];
TheISA::IntReg PC[ThePipeline::MaxThreads];
TheISA::IntReg nextPC[ThePipeline::MaxThreads];
TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
/** Tracks delay slot information for threads in ISAs which use
* delay slots;
*/
struct DelaySlotInfo {
InstSeqNum delaySlotSeqNum;
InstSeqNum branchSeqNum;
int numInsts;
Addr targetAddr;
bool targetReady;
};
DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads];
/** Squash Seq. Nums*/
InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
/** Squash Seq. Nums*/
Tick lastSquashCycle[ThePipeline::MaxThreads];
/** @todo: Add Resource Stats Here */
public:
class FetchSeqEvent : public ResourceEvent {
public:
/** Constructs a resource event. */
FetchSeqEvent();
virtual ~FetchSeqEvent() {}
/** Processes a resource event. */
virtual void process();
};
};
#endif

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "cpu/inorder/resources/graduation_unit.hh"
using namespace ThePipeline;
GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{
lastCycleGrad = 0;
numCycleGrad = 0;
for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
}
}
void
GraduationUnit::execute(int slot_num)
{
ResourceRequest* grad_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
Fault fault = reqMap[slot_num]->fault;
int tid, seq_num;
tid = inst->readTid();
seq_num = inst->seqNum;
int stage_num = inst->resSched.top()->stageNum;
grad_req->fault = NoFault;
switch (grad_req->cmd)
{
case GraduateInst:
{
// @TODO: Instructions should never really get to this point since this should be handled
// through the request interface. Check to make sure this happens and delete this
// code.
if (lastCycleGrad != curTick) {
lastCycleGrad = curTick;
numCycleGrad = 0;
} else if (numCycleGrad > width) {
DPRINTF(Resource, "Graduation bandwidth reached for this cycle.\n");
return;
}
// Make sure this is the last thing on the resource schedule
assert(inst->resSched.size() == 1);
DPRINTF(Resource, "[tid:%i] Graduating instruction [sn:%i].\n",
tid, seq_num);
DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/);
// Release Non-Speculative "Block" on instructions that could not execute
// because there was a non-speculative inst. active.
// @TODO: Fix this functionality. Probably too conservative.
if (inst->isNonSpeculative()) {
*nonSpecInstActive[tid] = false;
DPRINTF(Resource, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n",
tid, seq_num);
}
if (inst->traceData) {
inst->traceData->setStageCycle(stage_num, curTick);
}
// Tell CPU that instruction is finished processing
cpu->instDone(inst, tid);
//cpu->pipelineStage[stage_num]->toPrevStages->
//stageInfo[stage_num][tid].doneSeqNum = inst->seqNum;
grad_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}

View file

@ -0,0 +1,70 @@
/*
* 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 <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
class GraduationUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
enum Command {
GraduateInst
};
public:
GraduationUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~GraduationUnit() {}
virtual void execute(int slot_num);
protected:
Tick lastCycleGrad;
int numCycleGrad;
bool *nonSpecInstActive[ThePipeline::MaxThreads];
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
/** @todo: Add Resource Stats Here */
};
#endif //__CPU_INORDER_GRAD_UNIT_HH__

View file

@ -0,0 +1,222 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "arch/isa_traits.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/resources/inst_buffer.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{ }
void
InstBuffer::regStats()
{
instsBypassed
.name(name() + ".instsBypassed")
.desc("Number of Instructions Bypassed.");
Resource::regStats();
}
void
InstBuffer::execute(int slot_idx)
{
ResReqPtr ib_req = reqMap[slot_idx];
DynInstPtr inst = ib_req->inst;
int tid, seq_num, stage_num;
tid = inst->readTid();
seq_num = inst->seqNum;
stage_num = ib_req->getStageNum();
ib_req->fault = NoFault;
switch (ib_req->cmd)
{
case ScheduleOrBypass:
{
int next_stage = stage_num + 1;
int bypass_stage = stage_num + 2;
bool do_bypass = true;
if (!instList.empty()) {
DPRINTF(Resource, "[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(Resource, "[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(Resource, "[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(Resource, "Scheduling [sn:%i] for buffer insertion in stage %i\n",
inst->seqNum, next_stage);
// Add to schedule: Insert into buffer in next stage
int stage_pri = ThePipeline::getNextPriority(inst, next_stage);
inst->resSched.push(new ScheduleEntry(next_stage, stage_pri, id,
InstBuffer::InsertInst));
// Add to schedule: Remove from buffer in next next (bypass) stage
stage_pri = ThePipeline::getNextPriority(inst, bypass_stage);
inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id,
InstBuffer::RemoveInst));
} else { // BYPASS BUFFER & NEXT STAGE
DPRINTF(Resource, "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(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
tid, seq_num);
insert(inst);
inserted = true;
} else {
DPRINTF(Resource, "[tid:%i]: Denying [sn:%i] request because "
"buffer is full.\n", tid, seq_num);
std::list<DynInstPtr>::iterator list_it = instList.begin();
std::list<DynInstPtr>::iterator list_end = instList.end();
while (list_it != list_end) {
DPRINTF(Resource,"Serving [tid:%i] [sn:%i].\n", (*list_it)->readTid(), (*list_it)->seqNum);
list_it++;
}
}
ib_req->done(inserted);
}
break;
case RemoveInst:
{
DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n",
tid, seq_num);
remove(inst);
ib_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size());
}
void
InstBuffer::insert(DynInstPtr inst)
{
instList.push_back(inst);
}
void
InstBuffer::remove(DynInstPtr inst)
{
std::list<DynInstPtr>::iterator list_it = instList.begin();
std::list<DynInstPtr>::iterator list_end = instList.end();
while (list_it != list_end) {
if((*list_it) == inst) {
instList.erase(list_it);
break;
}
list_it++;
}
}
void
InstBuffer::pop(unsigned tid)
{
instList.pop_front();
}
ThePipeline::DynInstPtr
InstBuffer::top(unsigned tid)
{
return instList.front();
}
void
InstBuffer::squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, unsigned tid)
{
queue<list<DynInstPtr>::iterator> remove_list;
list<DynInstPtr>::iterator list_it = instList.begin();
list<DynInstPtr>::iterator list_end = instList.end();
// Collect All Instructions to be Removed in Remove List
while (list_it != list_end) {
if((*list_it)->readTid() == tid &&
(*list_it)->seqNum > squash_seq_num) {
(*list_it)->setSquashed();
remove_list.push(list_it);
}
list_it++;
}
// Removed Instructions from InstList & Clear Remove List
while (!remove_list.empty()) {
DPRINTF(Resource, "[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

@ -0,0 +1,93 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
#define __CPU_INORDER_INST_BUFF_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
class InstBuffer : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
enum Command {
InsertInst,
InsertAddr,
RemoveInst,
RemoveAddr,
ScheduleOrBypass
};
public:
InstBuffer(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~InstBuffer() {}
virtual void regStats();
virtual void execute(int slot_num);
virtual void insert(DynInstPtr inst);
virtual void remove(DynInstPtr inst);
virtual void pop(unsigned tid);
virtual DynInstPtr top(unsigned tid);
virtual void squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, unsigned tid);
protected:
/** List of instructions this resource is currently
* processing.
*/
std::list<DynInstPtr> instList;
public:
/////////////////////////////////////////////////////////////////
//
// RESOURCE STATISTICS
//
/////////////////////////////////////////////////////////////////
/** Number of Instruction Requests the Resource Processes */
Stats::Scalar<> instsBypassed;
};
#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "arch/isa_traits.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/resources/inst_buffer.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{ }
ResReqPtr
InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num)
{
// After this is working, change this to a reinterpret cast
// for performance considerations
InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top());
assert(ib_entry);
return new InstBufferRequest(this, inst, stage_num, id, slot_num,
ib_entry->cmd);
}
void
InstBuffer::execute(int slot_idx)
{
// After this is working, change this to a reinterpret cast
// for performance considerations
InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]);
assert(ib_req);
DynInstPtr inst = ib_req->inst;
int tid = inst->readTid();
int seq_num = inst->seqNum;
ib_req->fault = NoFault;
switch (ib_req->cmd)
{
case InsertInst:
{
DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
tid, seq_num);
insert(inst);
ib_req->done();
}
break;
case RemoveInst:
{
DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n",
tid, seq_num);
remove(inst);
ib_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size());
}
void
InstBuffer::insert(DynInstPtr inst)
{
instList.push_back(inst);
}
void
InstBuffer::remove(DynInstPtr inst)
{
std::list<DynInstPtr>::iterator list_it = instList.begin();
std::list<DynInstPtr>::iterator list_end = instList.end();
while (list_it != list_end) {
if((*list_it) == inst) {
instList.erase(list_it);
break;
}
list_it++;
}
}
void
InstBuffer::pop()
{ instList.pop_front(); }
ThePipeline::DynInstPtr
InstBuffer::top()
{ return instList.front(); }
void
InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid)
{
list<DynInstPtr>::iterator list_it = instList.begin();
list<DynInstPtr>::iterator list_end = instList.end();
queue<list<DynInstPtr>::iterator> remove_list;
// Collect All Instructions to be Removed in Remove List
while (list_it != list_end) {
if((*list_it)->seqNum > squash_seq_num) {
DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n",
tid, (*list_it)->seqNum);
(*list_it)->setSquashed();
remove_list.push(list_it);
}
list_it++;
}
// Removed Instructions from InstList & Clear Remove List
while (!remove_list.empty()) {
instList.erase(remove_list.front());
remove_list.pop();
}
Resource::squash(squash_seq_num, tid);
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__
#define __CPU_INORDER_INST_BUFF_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
class InstBuffer : public Resource {
public:
typedef InOrderDynInst::DynInstPtr DynInstPtr;
public:
enum Command {
InsertInst,
InsertAddr,
RemoveInst,
RemoveAddr
};
public:
InstBuffer(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu);
virtual ~InstBuffer() {}
virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
int res_idx, int slot_num);
virtual void execute(int slot_num);
virtual void insert(DynInstPtr inst);
virtual void remove(DynInstPtr inst);
virtual void pop();
virtual DynInstPtr top();
virtual void squash(InstSeqNum squash_seq_num, unsigned tid);
protected:
/** List of instructions this resource is currently
* processing.
*/
std::list<DynInstPtr> instList;
/** @todo: Add Resource Stats Here */
};
struct InstBufferEntry : public ThePipeline::ScheduleEntry {
InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) :
ScheduleEntry(stage_num, res_num), cmd(_cmd)
{ }
InstBuffer::Command cmd;
};
class InstBufferRequest : public ResourceRequest {
public:
typedef InOrderDynInst::DynInstPtr DynInstPtr;
public:
InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
InstBuffer::Command _cmd)
: ResourceRequest(res, inst, stage_num, res_idx, slot_num),
cmd(_cmd)
{ }
InstBuffer::Command cmd;
};
#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_GRAD_UNIT_HH__
#define __CPU_INORDER_GRAD_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
class MemDepUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
MemDepUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu);
virtual ~MemDepUnit() {}
virtual void execute(int slot_num);
protected:
Tick lastCycleGrad;
int numCycleGrad;
bool *nonSpecInstActive[ThePipeline::MaxThreads];
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
/** @todo: Add Resource Stats Here */
};
#endif //__CPU_INORDER_GRAD_UNIT_HH__

View file

@ -0,0 +1,291 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "cpu/inorder/resources/mult_div_unit.hh"
#include "cpu/inorder/resource_pool.hh"
#include "cpu/inorder/cpu.hh"
#include "cpu/op_class.hh"
using namespace std;
using namespace ThePipeline;
MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{
multRepeatRate = params->multRepeatRate;
multLatency = params->multLatency;
div8RepeatRate = params->div8RepeatRate;
div8Latency = params->div8Latency;
div16RepeatRate = params->div16RepeatRate;
div16Latency = params->div16Latency;
div24RepeatRate = params->div24RepeatRate;
div24Latency = params->div24Latency;
div32RepeatRate = params->div32RepeatRate;
div32Latency = params->div32Latency;
}
void
MultDivUnit::regStats()
{
multInstReqsProcessed
.name(name() + ".multInstReqsProcessed")
.desc("Number of Multiply Requests Processed.");
divInstReqsProcessed
.name(name() + ".divInstReqsProcessed")
.desc("Number of Divide Requests Processed.");
Resource::regStats();
}
void
MultDivUnit::init()
{
// Set Up Resource Events to Appropriate Resource BandWidth
resourceEvent = new MDUEvent[width];
initSlots();
}
int
MultDivUnit::findSlot(DynInstPtr inst)
{
DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
inst->seqNum, slotsAvail(), slotsInUse());
return Resource::findSlot(inst);
}
void
MultDivUnit::freeSlot(int slot_idx)
{
DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse());
Resource::freeSlot(slot_idx);
}
int
MultDivUnit::getSlot(DynInstPtr inst)
{
// If MDU already has instruction, return current slot.
int slot_num = findSlot(inst);
// If we have this instruction's request already then return
if (slot_num != -1 &&
inst->resSched.top()->cmd == reqMap[slot_num]->cmd)
return slot_num;
unsigned repeat_rate = 0;
/** Enforce MDU dependencies after a multiply is seen last */
if (lastOpType == IntMultOp) {
repeat_rate = multRepeatRate;
}
/** Enforce dependencies after a divide is seen last */
if (lastOpType == IntDivOp) {
switch (lastDivSize) {
case 8:
repeat_rate = div8RepeatRate;
break;
case 16:
repeat_rate = div16RepeatRate;
break;
case 24:
repeat_rate = div24RepeatRate;
break;
case 32:
repeat_rate = div32RepeatRate;
break;
}
}
if (lastMDUCycle + repeat_rate > curTick) {
DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n",
lastMDUCycle + repeat_rate);
return -1;
} else {
int rval = Resource::getSlot(inst);
DPRINTF(InOrderMDU, "MDU request should pass: %i.\n",
rval);
if (rval != -1) {
}
return rval;
}
}
int
MultDivUnit::getDivOpSize(DynInstPtr inst)
{
// Get RT Register from instruction (index #1)
uint32_t div_op = inst->readIntSrc(1);
if (div_op <= 0xFF) {
return 8;
} else if (div_op <= 0xFFFF) {
return 16;
} else if (div_op <= 0xFFFFFF) {
return 24;
} else {
return 32;
}
}
void
MultDivUnit::execute(int slot_num)
{
ResourceRequest* mult_div_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
Fault fault = reqMap[slot_num]->fault;
//int tid = inst->readTid();
//int seq_num = inst->seqNum;
switch (mult_div_req->cmd)
{
case StartMultDiv:
DPRINTF(InOrderMDU, "Start MDU called ...\n");
if (inst->opClass() == IntMultOp) {
scheduleEvent(slot_num, multLatency);
multInstReqsProcessed++;
} else if (inst->opClass() == IntDivOp) {
int op_size = getDivOpSize(inst);
switch (op_size)
{
case 8:
scheduleEvent(slot_num, div8Latency);
break;
case 16:
scheduleEvent(slot_num, div16Latency);
break;
case 24:
scheduleEvent(slot_num, div24Latency);
break;
case 32:
scheduleEvent(slot_num, div32Latency);
break;
}
lastDivSize = op_size;
divInstReqsProcessed++;
}
// Allow to pass through to next stage while
// event processes
mult_div_req->setCompleted();
break;
case MultDiv:
DPRINTF(InOrderMDU, "Execute MDU called ...\n");
exeMulDiv(slot_num);
mult_div_req->done();
break;
case EndMultDiv:
//@TODO: Why not allow high-latency requests to sleep
// within stage until event wakes up????
// Seems wasteful to continually check to see if
// this is done when we have a event in parallel
// counting down the time
{
DPRINTF(InOrderMDU, "End MDU called ...\n");
if (mult_div_req->getInst()->isExecuted())
mult_div_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
void
MultDivUnit::exeMulDiv(int slot_num)
{
ResourceRequest* mult_div_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
Fault fault = reqMap[slot_num]->fault;
int tid = inst->readTid();
int seq_num = inst->seqNum;
fault = inst->execute();
if (fault == NoFault) {
inst->setExecuted();
mult_div_req->setCompleted();
DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
inst->readTid(), inst->readIntResult(0));
} else {
warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
cpu->trap(fault, tid);
}
}
MDUEvent::MDUEvent()
: ResourceEvent()
{ }
void
MDUEvent::process()
{
MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
mdu_res->exeMulDiv(slotIdx);
ResourceRequest* mult_div_req = resource->reqMap[slotIdx];
mult_div_req->done();
}

View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_MULT_DIV_UNIT_HH__
#define __CPU_INORDER_MULT_DIV_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/func_unit.hh"
#include "cpu/op_class.hh"
#include "cpu/inorder/first_stage.hh"
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
class MDUEvent;
class MultDivUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
enum Command {
StartMultDiv,
EndMultDiv,
MultDiv
};
public:
MultDivUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~MultDivUnit() {}
public:
/** Override default Resource getSlot(). Will only getSlot if
* valid mult/div sequence is being maintained
*/
virtual int getSlot(DynInstPtr inst);
virtual int findSlot(DynInstPtr inst);
virtual void freeSlot(int slot_idx);
virtual void init();
/** Get Operand Size For A Division Operation */
int getDivOpSize(DynInstPtr inst);
/** Override default Resource execute */
virtual void execute(int slot_num);
void exeMulDiv(int slot_num);
/** Register extra resource stats */
virtual void regStats();
protected:
/** Latency & Repeat Rate for Multiply Insts */
unsigned multLatency;
unsigned multRepeatRate;
/** Latency & Repeat Rate for 8-bit Divide Insts */
unsigned div8Latency;
unsigned div8RepeatRate;
/** Latency & Repeat Rate for 16-bit Divide Insts */
unsigned div16Latency;
unsigned div16RepeatRate;
/** Latency & Repeat Rate for 24-bit Divide Insts */
unsigned div24Latency;
unsigned div24RepeatRate;
/** Latency & Repeat Rate for 32-bit Divide Insts */
unsigned div32Latency;
unsigned div32RepeatRate;
/** Last cycle that MDU was used */
Tick lastMDUCycle;
/** Last type of instruction MDU started processing */
OpClass lastOpType;
/** Last Division Operand of instruction MDU was processing */
uint32_t lastDivSize;
/** Last instruction name the MDU used */
std::string lastInstName;
/** Number of Instruction Requests the Resource Processes */
Stats::Scalar<> multInstReqsProcessed;
/** Number of Instruction Requests the Resource Processes */
Stats::Scalar<> divInstReqsProcessed;
MDUEvent *mduEvent;
};
class MDUEvent : public ResourceEvent
{
public:
MDUEvent();
virtual ~MDUEvent() { }
virtual void process();
};
#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__

View file

@ -0,0 +1,47 @@
/*
* 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/cache_unit.hh"
#include "cpu/inorder/resources/execution_unit.hh"
#include "cpu/inorder/resources/use_def.hh"
#include "cpu/inorder/resources/inst_buffer.hh"
#include "cpu/inorder/resources/decode_unit.hh"
#include "cpu/inorder/resources/graduation_unit.hh"
#include "cpu/inorder/resources/tlb_unit.hh"
#include "cpu/inorder/resources/fetch_seq_unit.hh"
#include "cpu/inorder/resources/branch_predictor.hh"
#include "cpu/inorder/resources/agen_unit.hh"
#include "cpu/inorder/resources/mult_div_unit.hh"
#endif

View file

@ -0,0 +1,186 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "arch/isa_traits.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/resources/tlb_unit.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
TLBUnit::TLBUnit(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: InstBuffer(res_name, res_id, res_width, res_latency, _cpu, params)
{
for (int i=0; i < MaxThreads; i++) {
tlbBlocked[i] = false;
}
}
void
TLBUnit::init()
{
resourceEvent = new TLBUnitEvent[width];
initSlots();
}
int
TLBUnit::getSlot(DynInstPtr inst)
{
if (tlbBlocked[inst->threadNumber]) {
return -1;
} else {
return Resource::getSlot(inst);
}
}
ResourceRequest*
TLBUnit::getRequest(DynInstPtr _inst, int stage_num,
int res_idx, int slot_num,
unsigned cmd)
{
return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num,
cmd);
}
void
TLBUnit::execute(int slot_idx)
{
// After this is working, change this to a reinterpret cast
// for performance considerations
TLBUnitRequest* tlb_req = dynamic_cast<TLBUnitRequest*>(reqMap[slot_idx]);
assert(tlb_req);
DynInstPtr inst = tlb_req->inst;
int tid, seq_num, stage_num;
tid = inst->readTid();
seq_num = inst->seqNum;
stage_num = tlb_req->getStageNum();
tlb_req->fault = NoFault;
switch (tlb_req->cmd)
{
case FetchLookup:
{
tlb_req->fault =
this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]);
if (tlb_req->fault != NoFault) {
DPRINTF(Resource, "[tid:%i]: %s encountered while translating "
"addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
tlb_req->memReq->getVaddr(), seq_num);
//insert(inst);
cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
tlbBlocked[tid] = true;
scheduleEvent(slot_idx, 1);
// @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault
// Let CPU handle the fault
cpu->trap(tlb_req->fault, tid);
} else {
DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated "
"to phys. addr:%08p.\n", tid, seq_num,
tlb_req->memReq->getVaddr(),
tlb_req->memReq->getPaddr());
tlb_req->done();
}
}
break;
case DataLookup:
{
DPRINTF(Resource, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
tid, seq_num, tlb_req->memReq->getVaddr());
tlb_req->fault =
this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]);
if (tlb_req->fault != NoFault) {
DPRINTF(Resource, "[tid:%i]: %s encountered while translating "
"addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
tlb_req->memReq->getVaddr(), seq_num);
//insert(inst);
cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
tlbBlocked[tid] = true;
scheduleEvent(slot_idx, 1);
// Let CPU handle the fault
cpu->trap(tlb_req->fault, tid);
} else {
DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated "
"to phys. addr:%08p.\n", tid, seq_num,
tlb_req->memReq->getVaddr(),
tlb_req->memReq->getPaddr());
tlb_req->done();
}
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
TLBUnitEvent::TLBUnitEvent()
: ResourceEvent()
{ }
void
TLBUnitEvent::process()
{
DynInstPtr inst = resource->reqMap[slotIdx]->inst;
int stage_num = resource->reqMap[slotIdx]->getStageNum();
int tid = inst->threadNumber;
DPRINTF(Resource, "Waking up from TLB Miss caused by [sn:%i].\n",
inst->seqNum);
TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource);
assert(tlb_res);
tlb_res->tlbBlocked[tid] = false;
tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid);
// Effectively NOP the instruction but still allow it
// to commit
//while (!inst->resSched.empty() &&
// inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) {
//inst->resSched.pop();
//}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_TLB_UNIT_HH__
#define __CPU_INORDER_TLB_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/inorder/resources/inst_buffer.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/cpu.hh"
class TLBUnit : public InstBuffer {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
enum TLBCommand {
FetchLookup,
DataLookup
};
public:
TLBUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~TLBUnit() {}
void init();
int getSlot(DynInstPtr inst);
virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
int res_idx, int slot_num,
unsigned cmd);
virtual void execute(int slot_num);
bool tlbBlocked[ThePipeline::MaxThreads];
protected:
/** List of instructions this resource is currently
* processing.
*/
std::list<DynInstPtr> instList;
/** @todo: Add Resource Stats Here */
};
class TLBUnitEvent : public ResourceEvent {
public:
/** Constructs a resource event. */
TLBUnitEvent();
virtual ~TLBUnitEvent() {}
/** Processes a resource event. */
virtual void process();
};
class TLBUnitRequest : public ResourceRequest {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
unsigned _cmd)
: ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd)
{
Addr aligned_addr;
int req_size;
unsigned flags;
if (_cmd == TLBUnit::FetchLookup) {
aligned_addr = inst->getMemAddr();
req_size = sizeof(MachInst);
flags = 0;
} else {
aligned_addr = inst->getMemAddr();;
req_size = inst->getMemAccSize();
flags = inst->getMemFlags();
}
// @TODO: Add Vaddr & Paddr functions
inst->memReq = new Request(inst->readTid(), aligned_addr, req_size,
flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid());
memReq = inst->memReq;
}
RequestPtr memReq;
};
#endif //__CPU_INORDER_TLB_UNIT_HH__

View file

@ -0,0 +1,326 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <vector>
#include <list>
#include "arch/isa_traits.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/resources/use_def.hh"
#include "cpu/inorder/cpu.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu),
maxSeqNum((InstSeqNum)-1)
{
for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
outReadSeqNum[tid] = maxSeqNum;
outWriteSeqNum[tid] = maxSeqNum;
regDepMap[tid] = &cpu->archRegDepMap[tid];
}
}
ResReqPtr
UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd,
inst->resSched.top()->idx);
}
ResReqPtr
UseDefUnit::findRequest(DynInstPtr inst)
{
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
map<int, ResReqPtr>::iterator map_end = reqMap.end();
while (map_it != map_end) {
UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>((*map_it).second);
assert(ud_req);
if (ud_req &&
ud_req->getInst() == inst &&
ud_req->cmd == inst->resSched.top()->cmd &&
ud_req->useDefIdx == inst->resSched.top()->idx) {
return ud_req;
}
map_it++;
}
return NULL;
}
void
UseDefUnit::execute(int slot_idx)
{
// After this is working, change this to a reinterpret cast
// for performance considerations
UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqMap[slot_idx]);
assert(ud_req);
DynInstPtr inst = ud_req->inst;
int tid = inst->readTid();
int seq_num = inst->seqNum;
int ud_idx = ud_req->useDefIdx;
// If there is a non-speculative instruction
// in the pipeline then stall instructions here
if (*nonSpecInstActive[tid] == true &&
seq_num > *nonSpecSeqNum[tid]) {
DPRINTF(Resource, "[tid:%i]: [sn:%i] cannot execute because there is "
"non-speculative instruction [sn:%i] has not graduated.\n",
tid, seq_num, *nonSpecSeqNum[tid]);
return;
} else if (inst->isNonSpeculative()) {
*nonSpecInstActive[tid] = true;
*nonSpecSeqNum[tid] = seq_num;
}
switch (ud_req->cmd)
{
case ReadSrcReg:
{
int reg_idx = inst->_srcRegIdx[ud_idx];
DPRINTF(Resource, "[tid:%i]: Attempting to read source register idx %i.\n",
tid, ud_idx);
// Ask register dependency map if it is OK to read from Arch. Reg. File
if (regDepMap[tid]->canRead(reg_idx, inst)) {
// Read From Register File
if (inst->seqNum <= outReadSeqNum[tid]) {
if (reg_idx <= FP_Base_DepTag) {
DPRINTF(Resource, "[tid:%i]: Reading Int Reg %i from Register File.\n",
tid, reg_idx);
inst->setIntSrc(ud_idx,
cpu->readIntReg(reg_idx,inst->readTid()));
} else if (reg_idx <= Ctrl_Base_DepTag) {
reg_idx -= FP_Base_DepTag;
DPRINTF(Resource, "[tid:%i]: Reading Float Reg %i from Register File.\n",
tid, reg_idx);
inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now
cpu->readFloatRegBits(reg_idx, inst->readTid()));
} else {
reg_idx -= Ctrl_Base_DepTag;
DPRINTF(Resource, "[tid:%i]: Reading Misc Reg %i from Register File.\n",
tid, reg_idx);
inst->setIntSrc(ud_idx,
cpu->readMiscReg(reg_idx, inst->readTid()));
}
outReadSeqNum[tid] = maxSeqNum;
ud_req->done();
} else {
DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's"
" registers yet.\n", tid, outReadSeqNum[tid]);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n",
tid, outReadSeqNum[tid]);
}
} else {
DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx, ud_idx, inst);
if (forward_inst) {
if (inst->seqNum <= outReadSeqNum[tid]) {
int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx);
if (reg_idx <= FP_Base_DepTag) {
DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from "
"[sn:%i] to [sn:%i] source #%i.\n",
tid, forward_inst->readIntResult(dest_reg_idx) ,
forward_inst->seqNum, inst->seqNum, ud_idx);
inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx));
} else if (reg_idx <= Ctrl_Base_DepTag) {
DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from "
"[sn:%i] to [sn:%i] source #%i.\n",
tid, forward_inst->readFloatResult(dest_reg_idx) ,
forward_inst->seqNum, inst->seqNum, ud_idx);
inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx));
} else {
DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from "
"[sn:%i] to [sn:%i] source #%i.\n",
tid, forward_inst->readIntResult(dest_reg_idx) ,
forward_inst->seqNum, inst->seqNum, ud_idx);
inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx));
}
outReadSeqNum[tid] = maxSeqNum;
ud_req->done();
} else {
DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's"
" registers yet.\n", tid, outReadSeqNum[tid]);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n",
tid, outReadSeqNum[tid]);
}
} else {
DPRINTF(Resource, "[tid:%i]: Source register idx: %i is not ready to read.\n",
tid, reg_idx);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n",
tid, reg_idx);
outReadSeqNum[tid] = inst->seqNum;
}
}
}
break;
case WriteDestReg:
{
int reg_idx = inst->_destRegIdx[ud_idx];
if (regDepMap[tid]->canWrite(reg_idx, inst)) {
DPRINTF(Resource, "[tid:%i]: Attempting to write to Register File.\n",
tid);
if (inst->seqNum <= outReadSeqNum[tid]) {
if (reg_idx <= FP_Base_DepTag) {
DPRINTF(Resource, "[tid:%i]: Writing 0x%x to register idx %i.\n",
tid, inst->readIntResult(ud_idx), reg_idx);
// Remove Dependencies
regDepMap[tid]->removeFront(reg_idx, inst);
cpu->setIntReg(reg_idx,
inst->readIntResult(ud_idx),
inst->readTid());
} else if(reg_idx <= Ctrl_Base_DepTag) {
// Remove Dependencies
regDepMap[tid]->removeFront(reg_idx, inst);
reg_idx -= FP_Base_DepTag;
cpu->setFloatReg(reg_idx, // Check for FloatRegBits Here
inst->readFloatResult(ud_idx),
inst->readTid());
} else {
// Remove Dependencies
regDepMap[tid]->removeFront(reg_idx, inst);
reg_idx -= Ctrl_Base_DepTag;
cpu->setMiscReg(reg_idx,
inst->readIntResult(ud_idx),
inst->readTid());
}
outWriteSeqNum[tid] = maxSeqNum;
ud_req->done();
} else {
DPRINTF(Resource, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's"
" registers yet.\n", tid, outReadSeqNum);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n",
tid, outReadSeqNum);
}
} else {
DPRINTF(Resource, "[tid:%i]: Dest. register idx: %i is not ready to write.\n",
tid, reg_idx);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n",
tid, reg_idx);
outWriteSeqNum[tid] = inst->seqNum;
}
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
void
UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
{
DPRINTF(Resource, "[tid:%i]: Updating Due To Squash After [sn:%i].\n",
tid, squash_seq_num);
std::vector<int> slot_remove_list;
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
map<int, ResReqPtr>::iterator map_end = reqMap.end();
while (map_it != map_end) {
ResReqPtr req_ptr = (*map_it).second;
if (req_ptr &&
req_ptr->getInst()->readTid() == tid &&
req_ptr->getInst()->seqNum > squash_seq_num) {
DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
req_ptr->getInst()->readTid(),
req_ptr->getInst()->seqNum);
regDepMap[tid]->remove(req_ptr->getInst());
int req_slot_num = req_ptr->getSlot();
if (latency > 0)
unscheduleEvent(req_slot_num);
// Mark slot for removal from resource
slot_remove_list.push_back(req_ptr->getSlot());
}
map_it++;
}
// Now Delete Slot Entry from Req. Map
for (int i = 0; i < slot_remove_list.size(); i++) {
freeSlot(slot_remove_list[i]);
}
if (outReadSeqNum[tid] >= squash_seq_num) {
DPRINTF(Resource, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid);
outReadSeqNum[tid] = maxSeqNum;
} else if (outReadSeqNum[tid] != maxSeqNum) {
DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n",
tid, outReadSeqNum[tid]);
}
if (outWriteSeqNum[tid] >= squash_seq_num) {
DPRINTF(Resource, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid);
outWriteSeqNum[tid] = maxSeqNum;
} else if (outWriteSeqNum[tid] != maxSeqNum) {
DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n",
tid, outWriteSeqNum[tid]);
}
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_USE_DEF_UNIT_HH__
#define __CPU_INORDER_USE_DEF_UNIT_HH__
#include <vector>
#include <list>
#include <string>
#include "cpu/func_unit.hh"
#include "cpu/inorder/first_stage.hh"
#include "cpu/inorder/resource.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/reg_dep_map.hh"
class UseDefUnit : public Resource {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
enum Command {
ReadSrcReg,
WriteDestReg
};
public:
UseDefUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
virtual ~UseDefUnit() {}
virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
int res_idx, int slot_num,
unsigned cmd);
virtual ResReqPtr findRequest(DynInstPtr inst);
virtual void execute(int slot_num);
virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
const InstSeqNum maxSeqNum;
protected:
RegDepMap *regDepMap[ThePipeline::MaxThreads];
/** Outstanding Seq. Num. Trying to Read from Register File */
InstSeqNum outReadSeqNum[ThePipeline::MaxThreads];
InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads];
bool *nonSpecInstActive[ThePipeline::MaxThreads];
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
/** @todo: Add Resource Stats Here */
public:
class UseDefRequest : public ResourceRequest {
public:
typedef ThePipeline::DynInstPtr DynInstPtr;
public:
UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd, int use_def_idx)
: ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd),
useDefIdx(use_def_idx)
{ }
int useDefIdx;
};
};
#endif //__CPU_INORDER_USE_DEF_UNIT_HH__

View file

@ -0,0 +1,371 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include "arch/isa_traits.hh"
#include "cpu/exetrace.hh"
#include "cpu/inorder/thread_context.hh"
using namespace TheISA;
void
InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
{
// some things should already be set up
assert(getProcessPtr() == old_context->getProcessPtr());
// copy over functional state
setStatus(old_context->status());
copyArchRegs(old_context);
//setCpuId(0/*old_context->readCpuId()*/);
thread->funcExeInst = old_context->readFuncExeInst();
old_context->setStatus(ThreadContext::Unallocated);
thread->inSyscall = false;
thread->trapPending = false;
}
void
InOrderThreadContext::activate(int delay)
{
DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Active)
return;
// @TODO: Make this process useful again...
//if (thread->status() == ThreadContext::Unallocated) {
// Allows the CPU to drain partitioned resources
// before inserting thread into the CPU
// (e.g. bind physical registers)
//cpu->activateWhenReady(thread->readTid());
//return;
//}
thread->setStatus(ThreadContext::Active);
// status() == Suspended
cpu->activateContext(thread->readTid(), delay);
}
void
InOrderThreadContext::suspend(int delay)
{
DPRINTF(InOrderCPU, "Calling suspend on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Suspended)
return;
thread->setStatus(ThreadContext::Suspended);
cpu->suspendContext(thread->readTid(), delay);
}
void
InOrderThreadContext::deallocate(int delay)
{
DPRINTF(InOrderCPU, "Calling deallocate on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Unallocated)
return;
thread->setStatus(ThreadContext::Unallocated);
cpu->deallocateContext(thread->readTid(), delay);
}
void
InOrderThreadContext::halt(int delay)
{
DPRINTF(InOrderCPU, "Calling halt on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Halted)
return;
thread->setStatus(ThreadContext::Halted);
cpu->haltContext(thread->readTid(), delay);
}
void
InOrderThreadContext::regStats(const std::string &name)
{
#if FULL_SYSTEM
thread->kernelStats = new Kernel::Statistics(cpu->system);
thread->kernelStats->regStats(name + ".kern");
#endif
;
}
void
InOrderThreadContext::serialize(std::ostream &os)
{
#if FULL_SYSTEM
if (thread->kernelStats)
thread->kernelStats->serialize(os);
#endif
;
}
void
InOrderThreadContext::unserialize(Checkpoint *cp, const std::string &section)
{
#if FULL_SYSTEM
if (thread->kernelStats)
thread->kernelStats->unserialize(cp, section);
#endif
;
}
TheISA::MachInst
InOrderThreadContext:: getInst()
{
return thread->getInst();
}
void
InOrderThreadContext::copyArchRegs(ThreadContext *tc)
{
unsigned tid = thread->readTid();
PhysRegIndex renamed_reg;
// First loop through the integer registers.
for (int i = 0; i < TheISA::NumIntRegs; ++i) {
renamed_reg = cpu->renameMap[tid].lookup(i);
DPRINTF(InOrderCPU, "Copying over register %i, had data %lli, "
"now has data %lli.\n",
renamed_reg, cpu->readIntReg(renamed_reg, tid),
tc->readIntReg(i));
cpu->setIntReg(renamed_reg, tc->readIntReg(i), tid);
}
// Then loop through the floating point registers.
for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag);
cpu->setFloatRegBits(renamed_reg, tc->readFloatRegBits(i), tid);
}
// Copy the misc regs.
TheISA::copyMiscRegs(tc, this);
// Then finally set the PC and the next PC.
cpu->setPC(tc->readPC(), tid);
cpu->setNextPC(tc->readNextPC(), tid);
cpu->setNextNPC(tc->readNextNPC(), tid);
this->thread->funcExeInst = tc->readFuncExeInst();
}
void
InOrderThreadContext::clearArchRegs()
{}
uint64_t
InOrderThreadContext::readIntReg(int reg_idx)
{
return cpu->readIntReg(reg_idx, thread->readTid());
}
FloatReg
InOrderThreadContext::readFloatReg(int reg_idx, int width)
{
return cpu->readFloatReg(reg_idx, thread->readTid(), width);
}
FloatReg
InOrderThreadContext::readFloatReg(int reg_idx)
{
return cpu->readFloatReg(reg_idx, thread->readTid());
}
FloatRegBits
InOrderThreadContext::readFloatRegBits(int reg_idx, int width)
{
return cpu->readFloatRegBits(reg_idx, thread->readTid(), width);
}
FloatRegBits
InOrderThreadContext::readFloatRegBits(int reg_idx)
{
return cpu->readFloatRegBits(reg_idx, thread->readTid());
}
uint64_t
InOrderThreadContext::readRegOtherThread(int reg_idx, unsigned tid)
{
return cpu->readRegOtherThread(reg_idx, tid);
}
void
InOrderThreadContext::setIntReg(int reg_idx, uint64_t val)
{
cpu->setIntReg(reg_idx, val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
// cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width)
{
cpu->setFloatReg(reg_idx, val, thread->readTid(), width);
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val)
{
cpu->setFloatReg(reg_idx, val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val,
int width)
{
cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width);
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val)
{
cpu->setFloatRegBits(reg_idx, val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid)
{
cpu->setRegOtherThread(misc_reg, val, tid);
}
void
InOrderThreadContext::setPC(uint64_t val)
{
DPRINTF(InOrderCPU, "Setting PC to %08p\n", val);
cpu->setPC(val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setNextPC(uint64_t val)
{
DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val);
cpu->setNextPC(val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setNextNPC(uint64_t val)
{
DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val);
cpu->setNextNPC(val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
void
InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val)
{
cpu->setMiscReg(misc_reg, val, thread->readTid());
// Squash if we're not already in a state update mode.
//if (!thread->trapPending && !thread->inSyscall) {
//cpu->squashFromTC(thread->readTid());
//}
}
TheISA::IntReg
InOrderThreadContext::getSyscallArg(int i)
{
return cpu->getSyscallArg(i, thread->readTid());
}
void
InOrderThreadContext::setSyscallArg(int i, IntReg val)
{
cpu->setSyscallArg(i, val, thread->readTid());
}
void
InOrderThreadContext::setSyscallReturn(SyscallReturn return_value)
{
cpu->setSyscallReturn(return_value, thread->readTid());
}

View file

@ -0,0 +1,286 @@
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#ifndef __CPU_INORDER_THREAD_CONTEXT_HH__
#define __CPU_INORDER_THREAD_CONTEXT_HH__
#include "cpu/exetrace.hh"
#include "cpu/thread_context.hh"
#include "cpu/inorder/thread_state.hh"
#include "cpu/inorder/cpu.hh"
class TranslatingPort;
/**
* Derived ThreadContext class for use with the InOrderCPU. It
* provides the interface for any external objects to access a
* single thread's state and some general CPU state. Any time
* external objects try to update state through this interface,
* the CPU will create an event to squash all in-flight
* instructions in order to ensure state is maintained correctly.
* It must be defined specifically for the InOrderCPU because
* not all architectural state is located within the O3ThreadState
* (such as the commit PC, and registers), and specific actions
* must be taken when using this interface (such as squashing all
* in-flight instructions when doing a write to this interface).
*/
class InOrderThreadContext : public ThreadContext
{
public:
InOrderThreadContext() { }
/** Pointer to the CPU. */
InOrderCPU *cpu;
/** Pointer to the thread state that this TC corrseponds to. */
InOrderThreadState *thread;
/** Returns a pointer to the ITB. */
TheISA::ITB *getITBPtr() { return cpu->itb; }
/** Returns a pointer to the DTB. */
TheISA::DTB *getDTBPtr() { return cpu->dtb; }
System *getSystemPtr() { return cpu->system; }
/** Returns a pointer to this CPU. */
virtual BaseCPU *getCpuPtr() { return cpu; }
/** Returns a pointer to this CPU. */
virtual std::string getCpuName() { return cpu->name(); }
/** Reads this CPU's ID. */
virtual int cpuId() { return cpu->cpuId(); }
virtual int contextId() { return thread->contextId(); }
virtual void setContextId(int id) { thread->setContextId(id); }
/** Returns this thread's ID number. */
virtual int threadId() { return thread->threadId(); }
virtual void setThreadId(int id) { return thread->setThreadId(id); }
virtual uint64_t readMicroPC()
{ return 0; }
virtual void setMicroPC(uint64_t val) { };
virtual uint64_t readNextMicroPC()
{ return 0; }
virtual void setNextMicroPC(uint64_t val) { };
virtual TranslatingPort *getMemPort() { return thread->getMemPort(); }
/** Returns a pointer to this thread's process. */
virtual Process *getProcessPtr() { return thread->getProcessPtr(); }
/** Returns this thread's status. */
virtual Status status() const { return thread->status(); }
/** Sets this thread's status. */
virtual void setStatus(Status new_status)
{ thread->setStatus(new_status); }
/** Returns a pointer to the last graduated/committed instruction in the thread */
//DynInstPtr getLastGradInst() { return thread->getLastGradInst(); }
/** Set the status to Active. Optional delay indicates number of
* cycles to wait before beginning execution. */
virtual void activate(int delay = 1);
/** Set the status to Suspended. */
virtual void suspend(int delay = 0);
/** Set the status to Unallocated. */
virtual void deallocate(int delay = 1);
/** Set the status to Halted. */
virtual void halt(int delay = 0);
/** Takes over execution of a thread from another CPU. */
virtual void takeOverFrom(ThreadContext *old_context);
/** Registers statistics associated with this TC. */
virtual void regStats(const std::string &name);
/** Serializes state. */
virtual void serialize(std::ostream &os);
/** Unserializes state. */
virtual void unserialize(Checkpoint *cp, const std::string &section);
/** Returns this thread's ID number. */
virtual int getThreadNum() { return thread->readTid(); }
/** Returns the instruction this thread is currently committing.
* Only used when an instruction faults.
*/
virtual TheISA::MachInst getInst();
/** Copies the architectural registers from another TC into this TC. */
virtual void copyArchRegs(ThreadContext *tc);
/** Resets all architectural registers to 0. */
virtual void clearArchRegs();
/** Reads an integer register. */
virtual uint64_t readIntReg(int reg_idx);
virtual FloatReg readFloatReg(int reg_idx, int width);
virtual FloatReg readFloatReg(int reg_idx);
virtual FloatRegBits readFloatRegBits(int reg_idx, int width);
virtual FloatRegBits readFloatRegBits(int reg_idx);
virtual uint64_t readRegOtherThread(int misc_reg, unsigned tid);
/** Sets an integer register to a value. */
virtual void setIntReg(int reg_idx, uint64_t val);
virtual void setFloatReg(int reg_idx, FloatReg val, int width);
virtual void setFloatReg(int reg_idx, FloatReg val);
virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width);
virtual void setFloatRegBits(int reg_idx, FloatRegBits val);
virtual void setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid);
/** Reads this thread's PC. */
virtual uint64_t readPC()
{ return cpu->readPC(thread->readTid()); }
/** Sets this thread's PC. */
virtual void setPC(uint64_t val);
/** Reads this thread's next PC. */
virtual uint64_t readNextPC()
{ return cpu->readNextPC(thread->readTid()); }
/** Sets this thread's next PC. */
virtual void setNextPC(uint64_t val);
virtual uint64_t readNextNPC()
{ return cpu->readNextNPC(thread->readTid()); }
virtual void setNextNPC(uint64_t val);
/** Reads a miscellaneous register. */
virtual MiscReg readMiscRegNoEffect(int misc_reg)
{ return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); }
/** Reads a misc. register, including any side-effects the
* read might have as defined by the architecture. */
virtual MiscReg readMiscReg(int misc_reg)
{ return cpu->readMiscReg(misc_reg, thread->readTid()); }
/** Sets a misc. register. */
virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
/** Sets a misc. register, including any side-effects the
* write might have as defined by the architecture. */
virtual void setMiscReg(int misc_reg, const MiscReg &val);
virtual void activateContext(int delay)
{ cpu->activateContext(thread->readTid(), delay); }
virtual void deallocateContext()
{ cpu->deallocateContext(thread->readTid()); }
/** Returns the number of consecutive store conditional failures. */
// @todo: Figure out where these store cond failures should go.
virtual unsigned readStCondFailures()
{ return thread->storeCondFailures; }
/** Sets the number of consecutive store conditional failures. */
virtual void setStCondFailures(unsigned sc_failures)
{ thread->storeCondFailures = sc_failures; }
// Only really makes sense for old CPU model. Lots of code
// outside the CPU still checks this function, so it will
// always return false to keep everything working.
/** Checks if the thread is misspeculating. Because it is
* very difficult to determine if the thread is
* misspeculating, this is set as false. */
virtual bool misspeculating() { return false; }
/** Gets a syscall argument by index. */
virtual IntReg getSyscallArg(int i);
/** Sets a syscall argument. */
virtual void setSyscallArg(int i, IntReg val);
/** Sets the syscall return value. */
virtual void setSyscallReturn(SyscallReturn return_value);
/** Executes a syscall in SE mode. */
virtual void syscall(int64_t callnum)
{ return cpu->syscall(callnum, thread->readTid()); }
/** Reads the funcExeInst counter. */
virtual Counter readFuncExeInst() { return thread->funcExeInst; }
virtual void changeRegFileContext(unsigned param,
unsigned val)
{ panic("Not supported!"); }
/** This function exits the thread context in the CPU and returns
* 1 if the CPU has no more active threads (meaning it's OK to exit);
* Used in syscall-emulation mode when a thread executes the 'exit'
* syscall.
*/
virtual int exit()
{
this->deallocate();
// If there are still threads executing in the system (for now
// this single cpu)
if (this->cpu->numActiveThreads() - 1 > 0)
return 0; // don't exit simulation
else
return 1; // exit simulation
}
virtual void setThreadRescheduleCondition(uint64_t cond)
{
this->deallocate();
this->setStatus(ThreadContext::Suspended);
activateContext(cond);
}
};
#endif

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
*/
#ifndef __CPU_INORDER_THREAD_STATE_HH__
#define __CPU_INORDER_THREAD_STATE_HH__
#include "arch/faults.hh"
#include "arch/isa_traits.hh"
#include "cpu/thread_context.hh"
#include "cpu/thread_state.hh"
class Event;
class FunctionalMemory;
class Process;
class InOrderCPU;
/**
* Class that has various thread state, such as the status, the
* current instruction being processed, whether or not the thread has
* a trap pending or is being externally updated, the ThreadContext
* pointer, etc. It also handles anything related to a specific
* thread's process, such as syscalls and checking valid addresses.
*/
class InOrderThreadState : public ThreadState {
typedef ThreadContext::Status Status;
private:
/** Pointer to the CPU. */
InOrderCPU *cpu;
public:
/** Whether or not the thread is currently in syscall mode, and
* thus able to be externally updated without squashing.
*/
bool inSyscall;
/** Whether or not the thread is currently waiting on a trap, and
* thus able to be externally updated without squashing.
*/
bool trapPending;
InOrderThreadState(InOrderCPU *_cpu, int _thread_num, Process *_process, int _asid)
: ThreadState(reinterpret_cast<BaseCPU*>(_cpu), 0/*_thread_num*/, _process, 0/*_asid*/),
cpu(_cpu), inSyscall(0), trapPending(0)
{ }
/** Handles the syscall. */
void syscall(int64_t callnum) { process->syscall(callnum, tc); }
/** Pointer to the ThreadContext of this thread. */
ThreadContext *tc;
/** Returns a pointer to the TC of this thread. */
ThreadContext *getTC() { return tc; }
int readTid() { return 0; }
/** Pointer to the last graduated instruction in the thread */
//DynInstPtr lastGradInst;
};
#endif // __CPU_INORDER_THREAD_STATE_HH__