CPU: Moving towards a more general port across CPU models
This patch performs minimal changes to move the instruction and data ports from specialised subclasses to the base CPU (to the largest degree possible). Ultimately it servers to make the CPU(s) have a well-defined interface to the memory sub-system.
This commit is contained in:
parent
f85286b3de
commit
b3f930c884
18 changed files with 409 additions and 402 deletions
|
@ -152,9 +152,12 @@ class BaseCPU(MemObject):
|
||||||
|
|
||||||
tracer = Param.InstTracer(default_tracer, "Instruction tracer")
|
tracer = Param.InstTracer(default_tracer, "Instruction tracer")
|
||||||
|
|
||||||
_cached_ports = []
|
icache_port = Port("Instruction Port")
|
||||||
|
dcache_port = Port("Data Port")
|
||||||
|
_cached_ports = ['icache_port', 'dcache_port']
|
||||||
|
|
||||||
if buildEnv['TARGET_ISA'] in ['x86', 'arm'] and buildEnv['FULL_SYSTEM']:
|
if buildEnv['TARGET_ISA'] in ['x86', 'arm'] and buildEnv['FULL_SYSTEM']:
|
||||||
_cached_ports = ["itb.walker.port", "dtb.walker.port"]
|
_cached_ports += ["itb.walker.port", "dtb.walker.port"]
|
||||||
|
|
||||||
_uncached_ports = []
|
_uncached_ports = []
|
||||||
if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']:
|
if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']:
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
* Copyright (c) 2011 Regents of the University of California
|
* Copyright (c) 2011 Regents of the University of California
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -485,3 +497,53 @@ BaseCPU::traceFunctionsInternal(Addr pc)
|
||||||
functionEntryTick = curTick();
|
functionEntryTick = curTick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BaseCPU::CpuPort::recvTiming(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
panic("BaseCPU doesn't expect recvTiming callback!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BaseCPU::CpuPort::recvRetry()
|
||||||
|
{
|
||||||
|
panic("BaseCPU doesn't expect recvRetry callback!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Tick
|
||||||
|
BaseCPU::CpuPort::recvAtomic(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
panic("BaseCPU doesn't expect recvAtomic callback!");
|
||||||
|
return curTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BaseCPU::CpuPort::recvFunctional(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
// No internal storage to update (in the general case). In the
|
||||||
|
// long term this should never be called, but that assumed a split
|
||||||
|
// into master/slave and request/response.
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BaseCPU::CpuPort::recvStatusChange(Status status)
|
||||||
|
{
|
||||||
|
if (status == RangeChange) {
|
||||||
|
if (!snoopRangeSent) {
|
||||||
|
snoopRangeSent = true;
|
||||||
|
sendStatusChange(Port::RangeChange);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("BaseCPU doesn't expect recvStatusChange callback!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BaseCPU::CpuPort::getDeviceAddressRanges(AddrRangeList& resp,
|
||||||
|
bool& snoop)
|
||||||
|
{
|
||||||
|
resp.clear();
|
||||||
|
snoop = false;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
* Copyright (c) 2011 Regents of the University of California
|
* Copyright (c) 2011 Regents of the University of California
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -95,6 +107,57 @@ class BaseCPU : public MemObject
|
||||||
// therefore no setCpuId() method is provided
|
// therefore no setCpuId() method is provided
|
||||||
int _cpuId;
|
int _cpuId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a base class for the CPU ports (instruction and data)
|
||||||
|
* that is refined in the subclasses. This class handles the
|
||||||
|
* common cases, i.e. the functional accesses and the status
|
||||||
|
* changes and address range queries. The default behaviour for
|
||||||
|
* both atomic and timing access is to panic and the corresponding
|
||||||
|
* subclasses have to override these methods.
|
||||||
|
*/
|
||||||
|
class CpuPort : public Port
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a CPU port with a name and a structural owner.
|
||||||
|
*
|
||||||
|
* @param _name port name including the owner
|
||||||
|
* @param _name structural owner of this port
|
||||||
|
*/
|
||||||
|
CpuPort(const std::string& _name, MemObject* _owner) :
|
||||||
|
Port(_name, _owner), snoopRangeSent(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual bool recvTiming(PacketPtr pkt);
|
||||||
|
|
||||||
|
virtual Tick recvAtomic(PacketPtr pkt);
|
||||||
|
|
||||||
|
virtual void recvRetry();
|
||||||
|
|
||||||
|
void recvFunctional(PacketPtr pkt);
|
||||||
|
|
||||||
|
void recvStatusChange(Status status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add CPU ports are master ports and do not respond to any
|
||||||
|
* address ranges. Note that the LSQ snoops for specific ISAs
|
||||||
|
* and thus has to override this method.
|
||||||
|
*
|
||||||
|
* @param resp list of ranges this port responds to
|
||||||
|
* @param snoop indicating if the port snoops or not
|
||||||
|
*/
|
||||||
|
virtual void getDeviceAddressRanges(AddrRangeList& resp,
|
||||||
|
bool& snoop);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool snoopRangeSent;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Reads this CPU's ID. */
|
/** Reads this CPU's ID. */
|
||||||
int cpuId() { return _cpuId; }
|
int cpuId() { return _cpuId; }
|
||||||
|
|
|
@ -44,9 +44,6 @@ class InOrderCPU(BaseCPU):
|
||||||
|
|
||||||
fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from")
|
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")
|
dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from")
|
||||||
icache_port = Port("Instruction Port")
|
|
||||||
dcache_port = Port("Data Port")
|
|
||||||
_cached_ports = ['icache_port', 'dcache_port']
|
|
||||||
|
|
||||||
fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)")
|
fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)")
|
||||||
memBlockSize = Param.Unsigned(64, "Memory Block Size")
|
memBlockSize = Param.Unsigned(64, "Memory Block Size")
|
||||||
|
|
|
@ -53,9 +53,6 @@ class DerivO3CPU(BaseCPU):
|
||||||
checker.dtb = Parent.dtb
|
checker.dtb = Parent.dtb
|
||||||
|
|
||||||
cachePorts = Param.Unsigned(200, "Cache Ports")
|
cachePorts = Param.Unsigned(200, "Cache Ports")
|
||||||
icache_port = Port("Instruction Port")
|
|
||||||
dcache_port = Port("Data Port")
|
|
||||||
_cached_ports = BaseCPU._cached_ports + ['icache_port', 'dcache_port']
|
|
||||||
|
|
||||||
decodeToFetchDelay = Param.Unsigned(1, "Decode to fetch delay")
|
decodeToFetchDelay = Param.Unsigned(1, "Decode to fetch delay")
|
||||||
renameToFetchDelay = Param.Unsigned(1 ,"Rename to fetch delay")
|
renameToFetchDelay = Param.Unsigned(1 ,"Rename to fetch delay")
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2004-2006 The Regents of The University of Michigan
|
* Copyright (c) 2004-2006 The Regents of The University of Michigan
|
||||||
* Copyright (c) 2011 Regents of the University of California
|
* Copyright (c) 2011 Regents of the University of California
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -79,6 +91,42 @@ BaseO3CPU::regStats()
|
||||||
BaseCPU::regStats();
|
BaseCPU::regStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Impl>
|
||||||
|
bool
|
||||||
|
FullO3CPU<Impl>::IcachePort::recvTiming(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
DPRINTF(O3CPU, "Fetch unit received timing\n");
|
||||||
|
if (pkt->isResponse()) {
|
||||||
|
// We shouldn't ever get a block in ownership state
|
||||||
|
assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
|
||||||
|
|
||||||
|
fetch->processCacheCompletion(pkt);
|
||||||
|
}
|
||||||
|
//else Snooped a coherence request, just return
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Impl>
|
||||||
|
void
|
||||||
|
FullO3CPU<Impl>::IcachePort::recvRetry()
|
||||||
|
{
|
||||||
|
fetch->recvRetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Impl>
|
||||||
|
bool
|
||||||
|
FullO3CPU<Impl>::DcachePort::recvTiming(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
return lsq->recvTiming(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Impl>
|
||||||
|
void
|
||||||
|
FullO3CPU<Impl>::DcachePort::recvRetry()
|
||||||
|
{
|
||||||
|
lsq->recvRetry();
|
||||||
|
}
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
|
FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
|
||||||
: Event(CPU_Tick_Pri), cpu(c)
|
: Event(CPU_Tick_Pri), cpu(c)
|
||||||
|
@ -194,6 +242,9 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
|
||||||
TheISA::NumMiscRegs * numThreads,
|
TheISA::NumMiscRegs * numThreads,
|
||||||
TheISA::ZeroReg),
|
TheISA::ZeroReg),
|
||||||
|
|
||||||
|
icachePort(&fetch, this),
|
||||||
|
dcachePort(&iew.ldstQueue, this),
|
||||||
|
|
||||||
timeBuffer(params->backComSize, params->forwardComSize),
|
timeBuffer(params->backComSize, params->forwardComSize),
|
||||||
fetchQueue(params->backComSize, params->forwardComSize),
|
fetchQueue(params->backComSize, params->forwardComSize),
|
||||||
decodeQueue(params->backComSize, params->forwardComSize),
|
decodeQueue(params->backComSize, params->forwardComSize),
|
||||||
|
@ -218,6 +269,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
|
||||||
if (params->checker) {
|
if (params->checker) {
|
||||||
BaseCPU *temp_checker = params->checker;
|
BaseCPU *temp_checker = params->checker;
|
||||||
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
|
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
|
||||||
|
checker->setIcachePort(&icachePort);
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
checker->setSystem(params->system);
|
checker->setSystem(params->system);
|
||||||
#endif
|
#endif
|
||||||
|
@ -528,9 +580,9 @@ Port *
|
||||||
FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
|
FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
|
||||||
{
|
{
|
||||||
if (if_name == "dcache_port")
|
if (if_name == "dcache_port")
|
||||||
return iew.getDcachePort();
|
return &dcachePort;
|
||||||
else if (if_name == "icache_port")
|
else if (if_name == "icache_port")
|
||||||
return fetch.getIcachePort();
|
return &icachePort;
|
||||||
else
|
else
|
||||||
panic("No Such Port\n");
|
panic("No Such Port\n");
|
||||||
}
|
}
|
||||||
|
@ -606,6 +658,13 @@ FullO3CPU<Impl>::init()
|
||||||
for (ThreadID tid = 0; tid < numThreads; ++tid)
|
for (ThreadID tid = 0; tid < numThreads; ++tid)
|
||||||
thread[tid]->inSyscall = true;
|
thread[tid]->inSyscall = true;
|
||||||
|
|
||||||
|
// this CPU could still be unconnected if we are restoring from a
|
||||||
|
// checkpoint and this CPU is to be switched in, thus we can only
|
||||||
|
// do this here if the instruction port is actually connected, if
|
||||||
|
// not we have to do it as part of takeOverFrom
|
||||||
|
if (icachePort.isConnected())
|
||||||
|
fetch.setIcache();
|
||||||
|
|
||||||
#if FULL_SYSTEM
|
#if FULL_SYSTEM
|
||||||
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
ThreadContext *src_tc = threadContexts[tid];
|
ThreadContext *src_tc = threadContexts[tid];
|
||||||
|
@ -1170,7 +1229,7 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
|
||||||
|
|
||||||
activityRec.reset();
|
activityRec.reset();
|
||||||
|
|
||||||
BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort());
|
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
|
||||||
|
|
||||||
fetch.takeOverFrom();
|
fetch.takeOverFrom();
|
||||||
decode.takeOverFrom();
|
decode.takeOverFrom();
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2004-2005 The Regents of The University of Michigan
|
* Copyright (c) 2004-2005 The Regents of The University of Michigan
|
||||||
* Copyright (c) 2011 Regents of the University of California
|
* Copyright (c) 2011 Regents of the University of California
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -118,6 +130,70 @@ class FullO3CPU : public BaseO3CPU
|
||||||
Status _threadStatus[Impl::MaxThreads];
|
Status _threadStatus[Impl::MaxThreads];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IcachePort class for instruction fetch.
|
||||||
|
*/
|
||||||
|
class IcachePort : public CpuPort
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/** Pointer to fetch. */
|
||||||
|
DefaultFetch<Impl> *fetch;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Default constructor. */
|
||||||
|
IcachePort(DefaultFetch<Impl> *_fetch, FullO3CPU<Impl>* _cpu)
|
||||||
|
: CpuPort(_fetch->name() + "-iport", _cpu), fetch(_fetch)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** 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();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DcachePort class for the load/store queue.
|
||||||
|
*/
|
||||||
|
class DcachePort : public CpuPort
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** Pointer to LSQ. */
|
||||||
|
LSQ<Impl> *lsq;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Default constructor. */
|
||||||
|
DcachePort(LSQ<Impl> *_lsq, FullO3CPU<Impl>* _cpu)
|
||||||
|
: CpuPort(_lsq->name() + "-dport", _cpu), lsq(_lsq)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** Timing version of receive. Handles writing back and
|
||||||
|
* completing the load or store that has returned from
|
||||||
|
* memory. */
|
||||||
|
virtual bool recvTiming(PacketPtr pkt);
|
||||||
|
|
||||||
|
/** Handles doing a retry of the previous send. */
|
||||||
|
virtual void recvRetry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As this CPU requires snooping to maintain the load store queue
|
||||||
|
* change the behaviour from the base CPU port.
|
||||||
|
*
|
||||||
|
* @param resp list of ranges this port responds to
|
||||||
|
* @param snoop indicating if the port snoops or not
|
||||||
|
*/
|
||||||
|
virtual void getDeviceAddressRanges(AddrRangeList& resp,
|
||||||
|
bool& snoop)
|
||||||
|
{ resp.clear(); snoop = true; }
|
||||||
|
};
|
||||||
|
|
||||||
class TickEvent : public Event
|
class TickEvent : public Event
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -566,6 +642,12 @@ class FullO3CPU : public BaseO3CPU
|
||||||
|
|
||||||
TheISA::ISA isa[Impl::MaxThreads];
|
TheISA::ISA isa[Impl::MaxThreads];
|
||||||
|
|
||||||
|
/** Instruction port. Note that it has to appear after the fetch stage. */
|
||||||
|
IcachePort icachePort;
|
||||||
|
|
||||||
|
/** Data port. Note that it has to appear after the iew stages */
|
||||||
|
DcachePort dcachePort;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Enum to give each stage a specific index, so when calling
|
/** Enum to give each stage a specific index, so when calling
|
||||||
* activateStage() or deactivateStage(), they can specify which stage
|
* activateStage() or deactivateStage(), they can specify which stage
|
||||||
|
@ -704,8 +786,11 @@ class FullO3CPU : public BaseO3CPU
|
||||||
data, store_idx);
|
data, store_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Used by the fetch unit to get a hold of the instruction port. */
|
||||||
|
Port* getIcachePort() { return &icachePort; }
|
||||||
|
|
||||||
/** Get the dcache port (used to find block size for translations). */
|
/** Get the dcache port (used to find block size for translations). */
|
||||||
Port *getDcachePort() { return this->iew.ldstQueue.getDcachePort(); }
|
Port* getDcachePort() { return &dcachePort; }
|
||||||
|
|
||||||
Addr lockAddr;
|
Addr lockAddr;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010 ARM Limited
|
* Copyright (c) 2010-2011 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -85,48 +85,6 @@ class DefaultFetch
|
||||||
typedef TheISA::MachInst MachInst;
|
typedef TheISA::MachInst MachInst;
|
||||||
typedef TheISA::ExtMachInst ExtMachInst;
|
typedef TheISA::ExtMachInst ExtMachInst;
|
||||||
|
|
||||||
/** IcachePort class for DefaultFetch. Handles doing the
|
|
||||||
* communication with the cache/memory.
|
|
||||||
*/
|
|
||||||
class IcachePort : public Port
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/** Pointer to fetch. */
|
|
||||||
DefaultFetch<Impl> *fetch;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Default constructor. */
|
|
||||||
IcachePort(DefaultFetch<Impl> *_fetch)
|
|
||||||
: Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool snoopRangeSent;
|
|
||||||
|
|
||||||
virtual void setPeer(Port *port);
|
|
||||||
|
|
||||||
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,
|
|
||||||
bool &snoop)
|
|
||||||
{ resp.clear(); snoop = true; }
|
|
||||||
|
|
||||||
/** 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();
|
|
||||||
};
|
|
||||||
|
|
||||||
class FetchTranslation : public BaseTLB::Translation
|
class FetchTranslation : public BaseTLB::Translation
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -248,9 +206,6 @@ class DefaultFetch
|
||||||
/** Registers statistics. */
|
/** Registers statistics. */
|
||||||
void regStats();
|
void regStats();
|
||||||
|
|
||||||
/** Returns the icache port. */
|
|
||||||
Port *getIcachePort() { return icachePort; }
|
|
||||||
|
|
||||||
/** Sets the main backwards communication time buffer pointer. */
|
/** Sets the main backwards communication time buffer pointer. */
|
||||||
void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer);
|
void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer);
|
||||||
|
|
||||||
|
@ -266,6 +221,9 @@ class DefaultFetch
|
||||||
/** Tells the fetch stage that the Icache is set. */
|
/** Tells the fetch stage that the Icache is set. */
|
||||||
void setIcache();
|
void setIcache();
|
||||||
|
|
||||||
|
/** Handles retrying the fetch access. */
|
||||||
|
void recvRetry();
|
||||||
|
|
||||||
/** Processes cache completion event. */
|
/** Processes cache completion event. */
|
||||||
void processCacheCompletion(PacketPtr pkt);
|
void processCacheCompletion(PacketPtr pkt);
|
||||||
|
|
||||||
|
@ -389,9 +347,6 @@ class DefaultFetch
|
||||||
StaticInstPtr curMacroop, TheISA::PCState thisPC,
|
StaticInstPtr curMacroop, TheISA::PCState thisPC,
|
||||||
TheISA::PCState nextPC, bool trace);
|
TheISA::PCState nextPC, bool trace);
|
||||||
|
|
||||||
/** Handles retrying the fetch access. */
|
|
||||||
void recvRetry();
|
|
||||||
|
|
||||||
/** Returns the appropriate thread to fetch, given the fetch policy. */
|
/** Returns the appropriate thread to fetch, given the fetch policy. */
|
||||||
ThreadID getFetchingThread(FetchPriority &fetch_priority);
|
ThreadID getFetchingThread(FetchPriority &fetch_priority);
|
||||||
|
|
||||||
|
@ -440,9 +395,6 @@ class DefaultFetch
|
||||||
/** Wire used to write any information heading to decode. */
|
/** Wire used to write any information heading to decode. */
|
||||||
typename TimeBuffer<FetchStruct>::wire toDecode;
|
typename TimeBuffer<FetchStruct>::wire toDecode;
|
||||||
|
|
||||||
/** Icache interface. */
|
|
||||||
IcachePort *icachePort;
|
|
||||||
|
|
||||||
/** BPredUnit. */
|
/** BPredUnit. */
|
||||||
BPredUnit branchPred;
|
BPredUnit branchPred;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010 ARM Limited
|
* Copyright (c) 2010-2011 ARM Limited
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -70,68 +70,6 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
template<class Impl>
|
|
||||||
void
|
|
||||||
DefaultFetch<Impl>::IcachePort::setPeer(Port *port)
|
|
||||||
{
|
|
||||||
Port::setPeer(port);
|
|
||||||
|
|
||||||
fetch->setIcache();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Impl>
|
|
||||||
Tick
|
|
||||||
DefaultFetch<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
panic("DefaultFetch doesn't expect recvAtomic callback!");
|
|
||||||
return curTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Impl>
|
|
||||||
void
|
|
||||||
DefaultFetch<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
DPRINTF(Fetch, "DefaultFetch doesn't update its state from a "
|
|
||||||
"functional call.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Impl>
|
|
||||||
void
|
|
||||||
DefaultFetch<Impl>::IcachePort::recvStatusChange(Status status)
|
|
||||||
{
|
|
||||||
if (status == RangeChange) {
|
|
||||||
if (!snoopRangeSent) {
|
|
||||||
snoopRangeSent = true;
|
|
||||||
sendStatusChange(Port::RangeChange);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("DefaultFetch doesn't expect recvStatusChange callback!");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Impl>
|
|
||||||
bool
|
|
||||||
DefaultFetch<Impl>::IcachePort::recvTiming(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
DPRINTF(Fetch, "Received timing\n");
|
|
||||||
if (pkt->isResponse()) {
|
|
||||||
// We shouldn't ever get a block in ownership state
|
|
||||||
assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
|
|
||||||
|
|
||||||
fetch->processCacheCompletion(pkt);
|
|
||||||
}
|
|
||||||
//else Snooped a coherence request, just return
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Impl>
|
|
||||||
void
|
|
||||||
DefaultFetch<Impl>::IcachePort::recvRetry()
|
|
||||||
{
|
|
||||||
fetch->recvRetry();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
|
DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
|
||||||
: cpu(_cpu),
|
: cpu(_cpu),
|
||||||
|
@ -191,17 +129,6 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
|
||||||
|
|
||||||
// Get the size of an instruction.
|
// Get the size of an instruction.
|
||||||
instSize = sizeof(TheISA::MachInst);
|
instSize = sizeof(TheISA::MachInst);
|
||||||
|
|
||||||
// Name is finally available, so create the port.
|
|
||||||
icachePort = new IcachePort(this);
|
|
||||||
|
|
||||||
icachePort->snoopRangeSent = false;
|
|
||||||
|
|
||||||
#if USE_CHECKER
|
|
||||||
if (cpu->checker) {
|
|
||||||
cpu->checker->setIcachePort(icachePort);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
|
@ -404,8 +331,10 @@ template<class Impl>
|
||||||
void
|
void
|
||||||
DefaultFetch<Impl>::setIcache()
|
DefaultFetch<Impl>::setIcache()
|
||||||
{
|
{
|
||||||
|
assert(cpu->getIcachePort()->isConnected());
|
||||||
|
|
||||||
// Size of cache block.
|
// Size of cache block.
|
||||||
cacheBlkSize = icachePort->peerBlockSize();
|
cacheBlkSize = cpu->getIcachePort()->peerBlockSize();
|
||||||
|
|
||||||
// Create mask to get rid of offset bits.
|
// Create mask to get rid of offset bits.
|
||||||
cacheBlkMask = (cacheBlkSize - 1);
|
cacheBlkMask = (cacheBlkSize - 1);
|
||||||
|
@ -496,6 +425,10 @@ template <class Impl>
|
||||||
void
|
void
|
||||||
DefaultFetch<Impl>::takeOverFrom()
|
DefaultFetch<Impl>::takeOverFrom()
|
||||||
{
|
{
|
||||||
|
// the instruction port is now connected so we can get the block
|
||||||
|
// size
|
||||||
|
setIcache();
|
||||||
|
|
||||||
// Reset all state
|
// Reset all state
|
||||||
for (ThreadID i = 0; i < Impl::MaxThreads; ++i) {
|
for (ThreadID i = 0; i < Impl::MaxThreads; ++i) {
|
||||||
stalls[i].decode = 0;
|
stalls[i].decode = 0;
|
||||||
|
@ -686,7 +619,7 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
|
||||||
fetchedCacheLines++;
|
fetchedCacheLines++;
|
||||||
|
|
||||||
// Access the cache.
|
// Access the cache.
|
||||||
if (!icachePort->sendTiming(data_pkt)) {
|
if (!cpu->getIcachePort()->sendTiming(data_pkt)) {
|
||||||
assert(retryPkt == NULL);
|
assert(retryPkt == NULL);
|
||||||
assert(retryTid == InvalidThreadID);
|
assert(retryTid == InvalidThreadID);
|
||||||
DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
|
DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
|
||||||
|
@ -1405,7 +1338,7 @@ DefaultFetch<Impl>::recvRetry()
|
||||||
assert(retryTid != InvalidThreadID);
|
assert(retryTid != InvalidThreadID);
|
||||||
assert(fetchStatus[retryTid] == IcacheWaitRetry);
|
assert(fetchStatus[retryTid] == IcacheWaitRetry);
|
||||||
|
|
||||||
if (icachePort->sendTiming(retryPkt)) {
|
if (cpu->getIcachePort()->sendTiming(retryPkt)) {
|
||||||
fetchStatus[retryTid] = IcacheWaitResponse;
|
fetchStatus[retryTid] = IcacheWaitResponse;
|
||||||
retryPkt = NULL;
|
retryPkt = NULL;
|
||||||
retryTid = InvalidThreadID;
|
retryTid = InvalidThreadID;
|
||||||
|
|
|
@ -139,9 +139,6 @@ class DefaultIEW
|
||||||
/** Initializes stage; sends back the number of free IQ and LSQ entries. */
|
/** Initializes stage; sends back the number of free IQ and LSQ entries. */
|
||||||
void initStage();
|
void initStage();
|
||||||
|
|
||||||
/** Returns the dcache port. */
|
|
||||||
Port *getDcachePort() { return ldstQueue.getDcachePort(); }
|
|
||||||
|
|
||||||
/** Sets main time buffer used for backwards communication. */
|
/** Sets main time buffer used for backwards communication. */
|
||||||
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
|
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2004-2006 The Regents of The University of Michigan
|
* Copyright (c) 2004-2006 The Regents of The University of Michigan
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -66,13 +78,6 @@ class LSQ {
|
||||||
/** Registers statistics of each LSQ unit. */
|
/** Registers statistics of each LSQ unit. */
|
||||||
void regStats();
|
void regStats();
|
||||||
|
|
||||||
/** Returns dcache port.
|
|
||||||
* @todo: Dcache port needs to be moved up to this level for SMT
|
|
||||||
* to work. For now it just returns the port from one of the
|
|
||||||
* threads.
|
|
||||||
*/
|
|
||||||
Port *getDcachePort() { return &dcachePort; }
|
|
||||||
|
|
||||||
/** Sets the pointer to the list of active threads. */
|
/** Sets the pointer to the list of active threads. */
|
||||||
void setActiveThreads(std::list<ThreadID> *at_ptr);
|
void setActiveThreads(std::list<ThreadID> *at_ptr);
|
||||||
/** Switches out the LSQ. */
|
/** Switches out the LSQ. */
|
||||||
|
@ -282,56 +287,25 @@ class LSQ {
|
||||||
Fault write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
Fault write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
uint8_t *data, int store_idx);
|
uint8_t *data, int store_idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retry the previous send that failed.
|
||||||
|
*/
|
||||||
|
void recvRetry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles writing back and completing the load or store that has
|
||||||
|
* returned from memory.
|
||||||
|
*
|
||||||
|
* @param pkt Response packet from the memory sub-system
|
||||||
|
*/
|
||||||
|
bool recvTiming(PacketPtr pkt);
|
||||||
|
|
||||||
/** The CPU pointer. */
|
/** The CPU pointer. */
|
||||||
O3CPU *cpu;
|
O3CPU *cpu;
|
||||||
|
|
||||||
/** The IEW stage pointer. */
|
/** The IEW stage pointer. */
|
||||||
IEW *iewStage;
|
IEW *iewStage;
|
||||||
|
|
||||||
/** DcachePort class for this LSQ. Handles doing the
|
|
||||||
* communication with the cache/memory.
|
|
||||||
*/
|
|
||||||
class DcachePort : public Port
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/** Pointer to LSQ. */
|
|
||||||
LSQ *lsq;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Default constructor. */
|
|
||||||
DcachePort(LSQ *_lsq)
|
|
||||||
: Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
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,
|
|
||||||
bool &snoop)
|
|
||||||
{ resp.clear(); snoop = true; }
|
|
||||||
|
|
||||||
/** Timing version of receive. Handles writing back and
|
|
||||||
* completing the load or store that has returned from
|
|
||||||
* memory. */
|
|
||||||
virtual bool recvTiming(PacketPtr pkt);
|
|
||||||
|
|
||||||
/** Handles doing a retry of the previous send. */
|
|
||||||
virtual void recvRetry();
|
|
||||||
};
|
|
||||||
|
|
||||||
/** D-cache port. */
|
|
||||||
DcachePort dcachePort;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** The LSQ policy for SMT mode. */
|
/** The LSQ policy for SMT mode. */
|
||||||
LSQPolicy lsqPolicy;
|
LSQPolicy lsqPolicy;
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2005-2006 The Regents of The University of Michigan
|
* Copyright (c) 2005-2006 The Regents of The University of Michigan
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -40,85 +52,14 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
template <class Impl>
|
|
||||||
Tick
|
|
||||||
LSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
panic("O3CPU model does not work with atomic mode!");
|
|
||||||
return curTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Impl>
|
|
||||||
void
|
|
||||||
LSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
DPRINTF(LSQ, "LSQ doesn't update things on a recvFunctional.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Impl>
|
|
||||||
void
|
|
||||||
LSQ<Impl>::DcachePort::recvStatusChange(Status status)
|
|
||||||
{
|
|
||||||
if (status == RangeChange) {
|
|
||||||
if (!snoopRangeSent) {
|
|
||||||
snoopRangeSent = true;
|
|
||||||
sendStatusChange(Port::RangeChange);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
panic("O3CPU doesn't expect recvStatusChange callback!");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Impl>
|
|
||||||
bool
|
|
||||||
LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
if (pkt->isError())
|
|
||||||
DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr());
|
|
||||||
if (pkt->isResponse()) {
|
|
||||||
lsq->thread[pkt->req->threadId()].completeDataAccess(pkt);
|
|
||||||
} else {
|
|
||||||
DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
|
|
||||||
pkt->cmdString());
|
|
||||||
|
|
||||||
// must be a snoop
|
|
||||||
if (pkt->isInvalidate()) {
|
|
||||||
DPRINTF(LSQ, "received invalidation for addr:%#x\n", pkt->getAddr());
|
|
||||||
for (ThreadID tid = 0; tid < lsq->numThreads; tid++) {
|
|
||||||
lsq->thread[tid].checkSnoop(pkt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// to provide stronger consistency model
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Impl>
|
|
||||||
void
|
|
||||||
LSQ<Impl>::DcachePort::recvRetry()
|
|
||||||
{
|
|
||||||
if (lsq->retryTid == -1)
|
|
||||||
{
|
|
||||||
//Squashed, so drop it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int curr_retry_tid = lsq->retryTid;
|
|
||||||
// Speculatively clear the retry Tid. This will get set again if
|
|
||||||
// the LSQUnit was unable to complete its access.
|
|
||||||
lsq->retryTid = -1;
|
|
||||||
lsq->thread[curr_retry_tid].recvRetry();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
|
LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
|
||||||
: cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this),
|
: cpu(cpu_ptr), iewStage(iew_ptr),
|
||||||
LQEntries(params->LQEntries),
|
LQEntries(params->LQEntries),
|
||||||
SQEntries(params->SQEntries),
|
SQEntries(params->SQEntries),
|
||||||
numThreads(params->numThreads),
|
numThreads(params->numThreads),
|
||||||
retryTid(-1)
|
retryTid(-1)
|
||||||
{
|
{
|
||||||
dcachePort.snoopRangeSent = false;
|
|
||||||
|
|
||||||
//**********************************************/
|
//**********************************************/
|
||||||
//************ Handle SMT Parameters ***********/
|
//************ Handle SMT Parameters ***********/
|
||||||
//**********************************************/
|
//**********************************************/
|
||||||
|
@ -170,7 +111,7 @@ LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
|
||||||
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
thread[tid].init(cpu, iew_ptr, params, this,
|
thread[tid].init(cpu, iew_ptr, params, this,
|
||||||
maxLQEntries, maxSQEntries, tid);
|
maxLQEntries, maxSQEntries, tid);
|
||||||
thread[tid].setDcachePort(&dcachePort);
|
thread[tid].setDcachePort(cpu_ptr->getDcachePort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,6 +301,48 @@ LSQ<Impl>::violation()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Impl>
|
||||||
|
void
|
||||||
|
LSQ<Impl>::recvRetry()
|
||||||
|
{
|
||||||
|
if (retryTid == InvalidThreadID)
|
||||||
|
{
|
||||||
|
//Squashed, so drop it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int curr_retry_tid = retryTid;
|
||||||
|
// Speculatively clear the retry Tid. This will get set again if
|
||||||
|
// the LSQUnit was unable to complete its access.
|
||||||
|
retryTid = -1;
|
||||||
|
thread[curr_retry_tid].recvRetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Impl>
|
||||||
|
bool
|
||||||
|
LSQ<Impl>::recvTiming(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
if (pkt->isError())
|
||||||
|
DPRINTF(LSQ, "Got error packet back for address: %#X\n",
|
||||||
|
pkt->getAddr());
|
||||||
|
if (pkt->isResponse()) {
|
||||||
|
thread[pkt->req->threadId()].completeDataAccess(pkt);
|
||||||
|
} else {
|
||||||
|
DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
|
||||||
|
pkt->cmdString());
|
||||||
|
|
||||||
|
// must be a snoop
|
||||||
|
if (pkt->isInvalidate()) {
|
||||||
|
DPRINTF(LSQ, "received invalidation for addr:%#x\n",
|
||||||
|
pkt->getAddr());
|
||||||
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
|
thread[tid].checkSnoop(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// to provide stronger consistency model
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
int
|
int
|
||||||
LSQ<Impl>::getCount()
|
LSQ<Impl>::getCount()
|
||||||
|
|
|
@ -34,8 +34,4 @@ class AtomicSimpleCPU(BaseSimpleCPU):
|
||||||
width = Param.Int(1, "CPU width")
|
width = Param.Int(1, "CPU width")
|
||||||
simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles")
|
simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles")
|
||||||
simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles")
|
simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles")
|
||||||
icache_port = Port("Instruction Port")
|
|
||||||
dcache_port = Port("Data Port")
|
|
||||||
physmem_port = Port("Physical Memory Port")
|
physmem_port = Port("Physical Memory Port")
|
||||||
_cached_ports = BaseSimpleCPU._cached_ports + \
|
|
||||||
['icache_port', 'dcache_port']
|
|
||||||
|
|
|
@ -31,6 +31,3 @@ from BaseSimpleCPU import BaseSimpleCPU
|
||||||
|
|
||||||
class TimingSimpleCPU(BaseSimpleCPU):
|
class TimingSimpleCPU(BaseSimpleCPU):
|
||||||
type = 'TimingSimpleCPU'
|
type = 'TimingSimpleCPU'
|
||||||
icache_port = Port("Instruction Port")
|
|
||||||
dcache_port = Port("Data Port")
|
|
||||||
_cached_ports = BaseSimpleCPU._cached_ports + ['icache_port', 'dcache_port']
|
|
||||||
|
|
|
@ -107,47 +107,6 @@ AtomicSimpleCPU::init()
|
||||||
data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
|
data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
AtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tick
|
|
||||||
AtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
//Snooping a coherence request, just return
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
//No internal storage to update, just return
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
|
|
||||||
{
|
|
||||||
if (status == RangeChange) {
|
|
||||||
if (!snoopRangeSent) {
|
|
||||||
snoopRangeSent = true;
|
|
||||||
sendStatusChange(Port::RangeChange);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AtomicSimpleCPU::CpuPort::recvRetry()
|
|
||||||
{
|
|
||||||
panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
||||||
: BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
|
: BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
|
||||||
simulate_data_stalls(p->simulate_data_stalls),
|
simulate_data_stalls(p->simulate_data_stalls),
|
||||||
|
@ -156,10 +115,6 @@ AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
||||||
physmemPort(name() + "-iport", this), hasPhysMemPort(false)
|
physmemPort(name() + "-iport", this), hasPhysMemPort(false)
|
||||||
{
|
{
|
||||||
_status = Idle;
|
_status = Idle;
|
||||||
|
|
||||||
icachePort.snoopRangeSent = false;
|
|
||||||
dcachePort.snoopRangeSent = false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,38 +64,31 @@ class AtomicSimpleCPU : public BaseSimpleCPU
|
||||||
// main simulation loop (one cycle)
|
// main simulation loop (one cycle)
|
||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
class CpuPort : public Port
|
/**
|
||||||
|
* An AtomicCPUPort overrides the default behaviour of the
|
||||||
|
* recvAtomic and ignores the packet instead of panicking.
|
||||||
|
*/
|
||||||
|
class AtomicCPUPort : public CpuPort
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CpuPort(const std::string &_name, AtomicSimpleCPU *_cpu)
|
AtomicCPUPort(const std::string &_name, BaseCPU* _cpu)
|
||||||
: Port(_name, _cpu), cpu(_cpu)
|
: CpuPort(_name, _cpu)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool snoopRangeSent;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
AtomicSimpleCPU *cpu;
|
virtual Tick recvAtomic(PacketPtr pkt)
|
||||||
|
{
|
||||||
virtual bool recvTiming(PacketPtr pkt);
|
// Snooping a coherence request, just return
|
||||||
|
return 0;
|
||||||
virtual Tick recvAtomic(PacketPtr pkt);
|
}
|
||||||
|
|
||||||
virtual void recvFunctional(PacketPtr pkt);
|
|
||||||
|
|
||||||
virtual void recvStatusChange(Status status);
|
|
||||||
|
|
||||||
virtual void recvRetry();
|
|
||||||
|
|
||||||
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
|
||||||
bool &snoop)
|
|
||||||
{ resp.clear(); snoop = true; }
|
|
||||||
|
|
||||||
};
|
};
|
||||||
CpuPort icachePort;
|
|
||||||
|
|
||||||
CpuPort dcachePort;
|
AtomicCPUPort icachePort;
|
||||||
|
AtomicCPUPort dcachePort;
|
||||||
|
|
||||||
CpuPort physmemPort;
|
CpuPort physmemPort;
|
||||||
bool hasPhysMemPort;
|
bool hasPhysMemPort;
|
||||||
|
|
|
@ -87,51 +87,19 @@ TimingSimpleCPU::init()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Tick
|
|
||||||
TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
|
|
||||||
return curTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
|
TimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
|
||||||
{
|
|
||||||
//No internal storage to update, jusst return
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
|
|
||||||
{
|
|
||||||
if (status == RangeChange) {
|
|
||||||
if (!snoopRangeSent) {
|
|
||||||
snoopRangeSent = true;
|
|
||||||
sendStatusChange(Port::RangeChange);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
|
|
||||||
{
|
{
|
||||||
pkt = _pkt;
|
pkt = _pkt;
|
||||||
cpu->schedule(this, t);
|
cpu->schedule(this, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
|
TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
|
||||||
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
|
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this),
|
||||||
dcachePort(this, p->clock), fetchEvent(this)
|
dcachePort(this), fetchEvent(this)
|
||||||
{
|
{
|
||||||
_status = Idle;
|
_status = Idle;
|
||||||
|
|
||||||
icachePort.snoopRangeSent = false;
|
|
||||||
dcachePort.snoopRangeSent = false;
|
|
||||||
|
|
||||||
ifetch_pkt = dcache_pkt = NULL;
|
ifetch_pkt = dcache_pkt = NULL;
|
||||||
drainEvent = NULL;
|
drainEvent = NULL;
|
||||||
previousTick = 0;
|
previousTick = 0;
|
||||||
|
|
|
@ -137,31 +137,23 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||||
// This function always implicitly uses dcache_pkt.
|
// This function always implicitly uses dcache_pkt.
|
||||||
bool handleWritePacket();
|
bool handleWritePacket();
|
||||||
|
|
||||||
class CpuPort : public Port
|
/**
|
||||||
|
* A TimingCPUPort overrides the default behaviour of the
|
||||||
|
* recvTiming and recvRetry and implements events for the
|
||||||
|
* scheduling of handling of incoming packets in the following
|
||||||
|
* cycle.
|
||||||
|
*/
|
||||||
|
class TimingCPUPort : public CpuPort
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
TimingSimpleCPU *cpu;
|
|
||||||
Tick lat;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CpuPort(const std::string &_name, TimingSimpleCPU *_cpu, Tick _lat)
|
TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu)
|
||||||
: Port(_name, _cpu), cpu(_cpu), lat(_lat), retryEvent(this)
|
: CpuPort(_name, _cpu), cpu(_cpu), retryEvent(this)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool snoopRangeSent;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual Tick recvAtomic(PacketPtr pkt);
|
TimingSimpleCPU* cpu;
|
||||||
|
|
||||||
virtual void recvFunctional(PacketPtr pkt);
|
|
||||||
|
|
||||||
virtual void recvStatusChange(Status status);
|
|
||||||
|
|
||||||
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
|
||||||
bool &snoop)
|
|
||||||
{ resp.clear(); snoop = false; }
|
|
||||||
|
|
||||||
struct TickEvent : public Event
|
struct TickEvent : public Event
|
||||||
{
|
{
|
||||||
|
@ -169,7 +161,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||||
TimingSimpleCPU *cpu;
|
TimingSimpleCPU *cpu;
|
||||||
CpuPort *port;
|
CpuPort *port;
|
||||||
|
|
||||||
TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {}
|
TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {}
|
||||||
const char *description() const { return "Timing CPU tick"; }
|
const char *description() const { return "Timing CPU tick"; }
|
||||||
void schedule(PacketPtr _pkt, Tick t);
|
void schedule(PacketPtr _pkt, Tick t);
|
||||||
};
|
};
|
||||||
|
@ -177,12 +169,13 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||||
EventWrapper<Port, &Port::sendRetry> retryEvent;
|
EventWrapper<Port, &Port::sendRetry> retryEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IcachePort : public CpuPort
|
class IcachePort : public TimingCPUPort
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IcachePort(TimingSimpleCPU *_cpu, Tick _lat)
|
IcachePort(TimingSimpleCPU *_cpu)
|
||||||
: CpuPort(_cpu->name() + "-iport", _cpu, _lat), tickEvent(_cpu)
|
: TimingCPUPort(_cpu->name() + "-iport", _cpu),
|
||||||
|
tickEvent(_cpu)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -204,12 +197,12 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DcachePort : public CpuPort
|
class DcachePort : public TimingCPUPort
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DcachePort(TimingSimpleCPU *_cpu, Tick _lat)
|
DcachePort(TimingSimpleCPU *_cpu)
|
||||||
: CpuPort(_cpu->name() + "-dport", _cpu, _lat), tickEvent(_cpu)
|
: TimingCPUPort(_cpu->name() + "-dport", _cpu), tickEvent(_cpu)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in a new issue