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:
Andreas Hansson 2012-01-17 12:55:08 -06:00
parent f85286b3de
commit b3f930c884
18 changed files with 409 additions and 402 deletions

View file

@ -152,9 +152,12 @@ class BaseCPU(MemObject):
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']:
_cached_ports = ["itb.walker.port", "dtb.walker.port"]
_cached_ports += ["itb.walker.port", "dtb.walker.port"]
_uncached_ports = []
if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']:

View file

@ -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) 2011 Regents of the University of California
* All rights reserved.
@ -485,3 +497,53 @@ BaseCPU::traceFunctionsInternal(Addr pc)
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;
}

View file

@ -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) 2011 Regents of the University of California
* All rights reserved.
@ -95,6 +107,57 @@ class BaseCPU : public MemObject
// therefore no setCpuId() method is provided
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:
/** Reads this CPU's ID. */
int cpuId() { return _cpuId; }

View file

@ -44,9 +44,6 @@ class InOrderCPU(BaseCPU):
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")
_cached_ports = ['icache_port', 'dcache_port']
fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)")
memBlockSize = Param.Unsigned(64, "Memory Block Size")

View file

@ -53,9 +53,6 @@ class DerivO3CPU(BaseCPU):
checker.dtb = Parent.dtb
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")
renameToFetchDelay = Param.Unsigned(1 ,"Rename to fetch delay")

View file

@ -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) 2011 Regents of the University of California
* All rights reserved.
@ -79,6 +91,42 @@ BaseO3CPU::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>
FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
: Event(CPU_Tick_Pri), cpu(c)
@ -194,6 +242,9 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
TheISA::NumMiscRegs * numThreads,
TheISA::ZeroReg),
icachePort(&fetch, this),
dcachePort(&iew.ldstQueue, this),
timeBuffer(params->backComSize, params->forwardComSize),
fetchQueue(params->backComSize, params->forwardComSize),
decodeQueue(params->backComSize, params->forwardComSize),
@ -218,6 +269,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
if (params->checker) {
BaseCPU *temp_checker = params->checker;
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
checker->setIcachePort(&icachePort);
#if FULL_SYSTEM
checker->setSystem(params->system);
#endif
@ -528,9 +580,9 @@ Port *
FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
{
if (if_name == "dcache_port")
return iew.getDcachePort();
return &dcachePort;
else if (if_name == "icache_port")
return fetch.getIcachePort();
return &icachePort;
else
panic("No Such Port\n");
}
@ -606,6 +658,13 @@ FullO3CPU<Impl>::init()
for (ThreadID tid = 0; tid < numThreads; ++tid)
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
for (ThreadID tid = 0; tid < numThreads; tid++) {
ThreadContext *src_tc = threadContexts[tid];
@ -1170,7 +1229,7 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
activityRec.reset();
BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort());
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
fetch.takeOverFrom();
decode.takeOverFrom();

View file

@ -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) 2011 Regents of the University of California
* All rights reserved.
@ -118,6 +130,70 @@ class FullO3CPU : public BaseO3CPU
Status _threadStatus[Impl::MaxThreads];
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
{
private:
@ -566,6 +642,12 @@ class FullO3CPU : public BaseO3CPU
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:
/** Enum to give each stage a specific index, so when calling
* activateStage() or deactivateStage(), they can specify which stage
@ -704,8 +786,11 @@ class FullO3CPU : public BaseO3CPU
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). */
Port *getDcachePort() { return this->iew.ldstQueue.getDcachePort(); }
Port* getDcachePort() { return &dcachePort; }
Addr lockAddr;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010 ARM Limited
* Copyright (c) 2010-2011 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@ -85,48 +85,6 @@ class DefaultFetch
typedef TheISA::MachInst MachInst;
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
{
protected:
@ -248,9 +206,6 @@ class DefaultFetch
/** Registers statistics. */
void regStats();
/** Returns the icache port. */
Port *getIcachePort() { return icachePort; }
/** Sets the main backwards communication time buffer pointer. */
void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer);
@ -266,6 +221,9 @@ class DefaultFetch
/** Tells the fetch stage that the Icache is set. */
void setIcache();
/** Handles retrying the fetch access. */
void recvRetry();
/** Processes cache completion event. */
void processCacheCompletion(PacketPtr pkt);
@ -389,9 +347,6 @@ class DefaultFetch
StaticInstPtr curMacroop, TheISA::PCState thisPC,
TheISA::PCState nextPC, bool trace);
/** Handles retrying the fetch access. */
void recvRetry();
/** Returns the appropriate thread to fetch, given the fetch policy. */
ThreadID getFetchingThread(FetchPriority &fetch_priority);
@ -440,9 +395,6 @@ class DefaultFetch
/** Wire used to write any information heading to decode. */
typename TimeBuffer<FetchStruct>::wire toDecode;
/** Icache interface. */
IcachePort *icachePort;
/** BPredUnit. */
BPredUnit branchPred;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010 ARM Limited
* Copyright (c) 2010-2011 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@ -70,68 +70,6 @@
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>
DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
@ -191,17 +129,6 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
// Get the size of an instruction.
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>
@ -404,8 +331,10 @@ template<class Impl>
void
DefaultFetch<Impl>::setIcache()
{
assert(cpu->getIcachePort()->isConnected());
// Size of cache block.
cacheBlkSize = icachePort->peerBlockSize();
cacheBlkSize = cpu->getIcachePort()->peerBlockSize();
// Create mask to get rid of offset bits.
cacheBlkMask = (cacheBlkSize - 1);
@ -496,6 +425,10 @@ template <class Impl>
void
DefaultFetch<Impl>::takeOverFrom()
{
// the instruction port is now connected so we can get the block
// size
setIcache();
// Reset all state
for (ThreadID i = 0; i < Impl::MaxThreads; ++i) {
stalls[i].decode = 0;
@ -686,7 +619,7 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
fetchedCacheLines++;
// Access the cache.
if (!icachePort->sendTiming(data_pkt)) {
if (!cpu->getIcachePort()->sendTiming(data_pkt)) {
assert(retryPkt == NULL);
assert(retryTid == InvalidThreadID);
DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
@ -1405,7 +1338,7 @@ DefaultFetch<Impl>::recvRetry()
assert(retryTid != InvalidThreadID);
assert(fetchStatus[retryTid] == IcacheWaitRetry);
if (icachePort->sendTiming(retryPkt)) {
if (cpu->getIcachePort()->sendTiming(retryPkt)) {
fetchStatus[retryTid] = IcacheWaitResponse;
retryPkt = NULL;
retryTid = InvalidThreadID;

View file

@ -139,9 +139,6 @@ class DefaultIEW
/** Initializes stage; sends back the number of free IQ and LSQ entries. */
void initStage();
/** Returns the dcache port. */
Port *getDcachePort() { return ldstQueue.getDcachePort(); }
/** Sets main time buffer used for backwards communication. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);

View file

@ -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
* All rights reserved.
*
@ -66,13 +78,6 @@ class LSQ {
/** Registers statistics of each LSQ unit. */
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. */
void setActiveThreads(std::list<ThreadID> *at_ptr);
/** Switches out the LSQ. */
@ -282,56 +287,25 @@ class LSQ {
Fault write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
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. */
O3CPU *cpu;
/** The IEW stage pointer. */
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:
/** The LSQ policy for SMT mode. */
LSQPolicy lsqPolicy;

View file

@ -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
* All rights reserved.
*
@ -40,85 +52,14 @@
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>
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),
SQEntries(params->SQEntries),
numThreads(params->numThreads),
retryTid(-1)
{
dcachePort.snoopRangeSent = false;
//**********************************************/
//************ 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++) {
thread[tid].init(cpu, iew_ptr, params, this,
maxLQEntries, maxSQEntries, tid);
thread[tid].setDcachePort(&dcachePort);
thread[tid].setDcachePort(cpu_ptr->getDcachePort());
}
}
@ -360,6 +301,48 @@ LSQ<Impl>::violation()
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>
int
LSQ<Impl>::getCount()

View file

@ -34,8 +34,4 @@ class AtomicSimpleCPU(BaseSimpleCPU):
width = Param.Int(1, "CPU width")
simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles")
simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
physmem_port = Port("Physical Memory Port")
_cached_ports = BaseSimpleCPU._cached_ports + \
['icache_port', 'dcache_port']

View file

@ -31,6 +31,3 @@ from BaseSimpleCPU import BaseSimpleCPU
class TimingSimpleCPU(BaseSimpleCPU):
type = 'TimingSimpleCPU'
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
_cached_ports = BaseSimpleCPU._cached_ports + ['icache_port', 'dcache_port']

View file

@ -107,47 +107,6 @@ AtomicSimpleCPU::init()
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)
: BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
simulate_data_stalls(p->simulate_data_stalls),
@ -156,10 +115,6 @@ AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
physmemPort(name() + "-iport", this), hasPhysMemPort(false)
{
_status = Idle;
icachePort.snoopRangeSent = false;
dcachePort.snoopRangeSent = false;
}

View file

@ -64,38 +64,31 @@ class AtomicSimpleCPU : public BaseSimpleCPU
// main simulation loop (one cycle)
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:
CpuPort(const std::string &_name, AtomicSimpleCPU *_cpu)
: Port(_name, _cpu), cpu(_cpu)
AtomicCPUPort(const std::string &_name, BaseCPU* _cpu)
: CpuPort(_name, _cpu)
{ }
bool snoopRangeSent;
protected:
AtomicSimpleCPU *cpu;
virtual bool recvTiming(PacketPtr pkt);
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; }
virtual Tick recvAtomic(PacketPtr pkt)
{
// Snooping a coherence request, just return
return 0;
}
};
CpuPort icachePort;
CpuPort dcachePort;
AtomicCPUPort icachePort;
AtomicCPUPort dcachePort;
CpuPort physmemPort;
bool hasPhysMemPort;

View file

@ -87,51 +87,19 @@ TimingSimpleCPU::init()
#endif
}
Tick
TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
{
panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
return curTick();
}
void
TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
{
//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)
TimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
{
pkt = _pkt;
cpu->schedule(this, t);
}
TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
dcachePort(this, p->clock), fetchEvent(this)
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this),
dcachePort(this), fetchEvent(this)
{
_status = Idle;
icachePort.snoopRangeSent = false;
dcachePort.snoopRangeSent = false;
ifetch_pkt = dcache_pkt = NULL;
drainEvent = NULL;
previousTick = 0;

View file

@ -137,31 +137,23 @@ class TimingSimpleCPU : public BaseSimpleCPU
// This function always implicitly uses dcache_pkt.
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:
CpuPort(const std::string &_name, TimingSimpleCPU *_cpu, Tick _lat)
: Port(_name, _cpu), cpu(_cpu), lat(_lat), retryEvent(this)
TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu)
: CpuPort(_name, _cpu), cpu(_cpu), retryEvent(this)
{ }
bool snoopRangeSent;
protected:
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
virtual void recvStatusChange(Status status);
virtual void getDeviceAddressRanges(AddrRangeList &resp,
bool &snoop)
{ resp.clear(); snoop = false; }
TimingSimpleCPU* cpu;
struct TickEvent : public Event
{
@ -169,7 +161,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
TimingSimpleCPU *cpu;
CpuPort *port;
TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {}
TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {}
const char *description() const { return "Timing CPU tick"; }
void schedule(PacketPtr _pkt, Tick t);
};
@ -177,12 +169,13 @@ class TimingSimpleCPU : public BaseSimpleCPU
EventWrapper<Port, &Port::sendRetry> retryEvent;
};
class IcachePort : public CpuPort
class IcachePort : public TimingCPUPort
{
public:
IcachePort(TimingSimpleCPU *_cpu, Tick _lat)
: CpuPort(_cpu->name() + "-iport", _cpu, _lat), tickEvent(_cpu)
IcachePort(TimingSimpleCPU *_cpu)
: TimingCPUPort(_cpu->name() + "-iport", _cpu),
tickEvent(_cpu)
{ }
protected:
@ -204,12 +197,12 @@ class TimingSimpleCPU : public BaseSimpleCPU
};
class DcachePort : public CpuPort
class DcachePort : public TimingCPUPort
{
public:
DcachePort(TimingSimpleCPU *_cpu, Tick _lat)
: CpuPort(_cpu->name() + "-dport", _cpu, _lat), tickEvent(_cpu)
DcachePort(TimingSimpleCPU *_cpu)
: TimingCPUPort(_cpu->name() + "-dport", _cpu), tickEvent(_cpu)
{ }
protected: