MEM: Introduce the master/slave port sub-classes in C++

This patch introduces the notion of a master and slave port in the C++
code, thus bringing the previous classification from the Python
classes into the corresponding simulation objects and memory objects.

The patch enables us to classify behaviours into the two bins and add
assumptions and enfore compliance, also simplifying the two
interfaces. As a starting point, isSnooping is confined to a master
port, and getAddrRanges to slave ports. More of these specilisations
are to come in later patches.

The getPort function is not getMasterPort and getSlavePort, and
returns a port reference rather than a pointer as NULL would never be
a valid return value. The default implementation of these two
functions is placed in MemObject, and calls fatal.

The one drawback with this specific patch is that it requires some
code duplication, e.g. QueuedPort becomes QueuedMasterPort and
QueuedSlavePort, and BusPort becomes BusMasterPort and BusSlavePort
(avoiding multiple inheritance). With the later introduction of the
port interfaces, moving the functionality outside the port itself, a
lot of the duplicated code will disappear again.
This commit is contained in:
William Wang 2012-03-30 09:40:11 -04:00
parent a14013af3a
commit f9d403a7b9
75 changed files with 1036 additions and 658 deletions

View file

@ -91,13 +91,13 @@ TableWalker::resume()
}
}
Port*
TableWalker::getPort(const std::string &if_name, int idx)
MasterPort&
TableWalker::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "port") {
return &port;
return port;
}
return NULL;
return MemObject::getMasterPort(if_name, idx);
}
Fault

View file

@ -358,7 +358,8 @@ class TableWalker : public MemObject
virtual unsigned int drain(Event *de);
virtual void resume();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort& getMasterPort(const std::string &if_name,
int idx = -1);
Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
TLB::Translation *_trans, bool timing, bool functional = false);

View file

@ -722,10 +722,10 @@ TLB::translateTiming(RequestPtr req, ThreadContext *tc,
return fault;
}
Port*
TLB::getPort()
MasterPort*
TLB::getMasterPort()
{
return tableWalker->getPort("port");
return &tableWalker->getMasterPort("port");
}

View file

@ -214,8 +214,17 @@ class TLB : public BaseTLB
void regStats();
// Get the port from the table walker and return it
virtual Port *getPort();
/**
* Get the table walker master port. This is used for migrating
* port connections during a CPU takeOverFrom() call. For
* architectures that do not have a table walker, NULL is
* returned, hence the use of a pointer rather than a
* reference. For ARM this method will always return a valid port
* pointer.
*
* @return A pointer to the walker master port
*/
virtual MasterPort* getMasterPort();
// Caching misc register values here.
// Writing to misc registers needs to invalidate them.

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2008 The Hewlett-Packard Development Company
* All rights reserved.
*
@ -304,6 +316,9 @@ X86ISA::Interrupts::init()
//
BasicPioDevice::init();
IntDev::init();
// the slave port has a range so inform the connected master
intSlavePort.sendRangeChange();
}
@ -554,7 +569,7 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
break;
}
pendingIPIs += apics.size();
intPort.sendMessage(apics, message, timing);
intMasterPort.sendMessage(apics, message, timing);
newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
}
break;

View file

@ -189,7 +189,7 @@ class Interrupts : public BasicPioDevice, IntDev
int initialApicId;
// Port for receiving interrupts
IntPort intSlavePort;
IntSlavePort intSlavePort;
public:
@ -239,17 +239,20 @@ class Interrupts : public BasicPioDevice, IntDev
AddrRangeList getAddrRanges();
AddrRangeList getIntAddrRange();
Port *getPort(const std::string &if_name, int idx = -1)
MasterPort &getMasterPort(const std::string &if_name, int idx = -1)
{
// a bit of an odd one since there is now two ports in the
// Python class we also need two ports even if they are
// identical
if (if_name == "int_master") {
return &intPort;
} else if (if_name == "int_slave") {
return &intSlavePort;
return intMasterPort;
}
return BasicPioDevice::getPort(if_name, idx);
return BasicPioDevice::getMasterPort(if_name, idx);
}
SlavePort &getSlavePort(const std::string &if_name, int idx = -1)
{
if (if_name == "int_slave") {
return intSlavePort;
}
return BasicPioDevice::getSlavePort(if_name, idx);
}
/*

View file

@ -153,11 +153,6 @@ Walker::WalkerPort::recvFunctional(PacketPtr pkt)
return;
}
void
Walker::WalkerPort::recvRangeChange()
{
}
void
Walker::WalkerPort::recvRetry()
{
@ -182,13 +177,13 @@ bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt)
return port.sendTiming(pkt);
}
Port *
Walker::getPort(const std::string &if_name, int idx)
MasterPort &
Walker::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "port")
return &port;
return port;
else
panic("No page table walker port named %s!\n", if_name);
return MemObject::getMasterPort(if_name, idx);
}
void

View file

@ -60,11 +60,11 @@ namespace X86ISA
{
protected:
// Port for accessing memory
class WalkerPort : public Port
class WalkerPort : public MasterPort
{
public:
WalkerPort(const std::string &_name, Walker * _walker) :
Port(_name, _walker), walker(_walker)
MasterPort(_name, _walker), walker(_walker)
{}
protected:
@ -73,9 +73,8 @@ namespace X86ISA
bool recvTiming(PacketPtr pkt);
Tick recvAtomic(PacketPtr pkt);
void recvFunctional(PacketPtr pkt);
void recvRangeChange();
void recvRetry();
bool isSnooping() { return true; }
bool isSnooping() const { return true; }
};
friend class WalkerPort;
@ -166,7 +165,7 @@ namespace X86ISA
RequestPtr req, BaseTLB::Mode mode);
Fault startFunctional(ThreadContext * _tc, Addr &addr,
Addr &pageSize, BaseTLB::Mode mode);
Port *getPort(const std::string &if_name, int idx = -1);
MasterPort &getMasterPort(const std::string &if_name, int idx = -1);
protected:
// The TLB we're supposed to load.

View file

@ -428,10 +428,10 @@ TLB::unserialize(Checkpoint *cp, const std::string &section)
{
}
Port *
TLB::getPort()
MasterPort *
TLB::getMasterPort()
{
return walker->getPort("port");
return &walker->getMasterPort("port");
}
} // namespace X86ISA

View file

@ -125,7 +125,17 @@ namespace X86ISA
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual Port * getPort();
/**
* Get the table walker master port. This is used for
* migrating port connections during a CPU takeOverFrom()
* call. For architectures that do not have a table walker,
* NULL is returned, hence the use of a pointer rather than a
* reference. For X86 this method will always return a valid
* port pointer.
*
* @return A pointer to the walker master port
*/
virtual MasterPort *getMasterPort();
};
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 ARM Limited
* Copyright (c) 2011-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@ -299,19 +299,19 @@ BaseCPU::regStats()
threadContexts[0]->regStats(name());
}
Port *
BaseCPU::getPort(const string &if_name, int idx)
MasterPort &
BaseCPU::getMasterPort(const string &if_name, int idx)
{
// Get the right port based on name. This applies to all the
// subclasses of the base CPU and relies on their implementation
// of getDataPort and getInstPort. In all cases there methods
// return a CpuPort pointer.
if (if_name == "dcache_port")
return &getDataPort();
return getDataPort();
else if (if_name == "icache_port")
return &getInstPort();
return getInstPort();
else
panic("CPU %s has no port named %s\n", name(), if_name);
return MemObject::getMasterPort(if_name, idx);
}
Tick
@ -381,8 +381,6 @@ BaseCPU::switchOut()
void
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
{
CpuPort &ic = getInstPort();
CpuPort &dc = getDataPort();
assert(threadContexts.size() == oldCPU->threadContexts.size());
_cpuId = oldCPU->cpuId();
@ -407,24 +405,21 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
ThreadContext::compare(oldTC, newTC);
*/
Port *old_itb_port, *old_dtb_port, *new_itb_port, *new_dtb_port;
old_itb_port = oldTC->getITBPtr()->getPort();
old_dtb_port = oldTC->getDTBPtr()->getPort();
new_itb_port = newTC->getITBPtr()->getPort();
new_dtb_port = newTC->getDTBPtr()->getPort();
MasterPort *old_itb_port = oldTC->getITBPtr()->getMasterPort();
MasterPort *old_dtb_port = oldTC->getDTBPtr()->getMasterPort();
MasterPort *new_itb_port = newTC->getITBPtr()->getMasterPort();
MasterPort *new_dtb_port = newTC->getDTBPtr()->getMasterPort();
// Move over any table walker ports if they exist
if (new_itb_port && !new_itb_port->isConnected()) {
assert(old_itb_port);
Port *peer = old_itb_port->getPeer();;
new_itb_port->setPeer(peer);
peer->setPeer(new_itb_port);
SlavePort &slavePort = old_itb_port->getSlavePort();
new_itb_port->bind(slavePort);
}
if (new_dtb_port && !new_dtb_port->isConnected()) {
assert(old_dtb_port);
Port *peer = old_dtb_port->getPeer();;
new_dtb_port->setPeer(peer);
peer->setPeer(new_dtb_port);
SlavePort &slavePort = old_dtb_port->getSlavePort();
new_dtb_port->bind(slavePort);
}
// Checker whether or not we have to transfer CheckerCPU
@ -432,26 +427,25 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr();
CheckerCPU *newChecker = newTC->getCheckerCpuPtr();
if (oldChecker && newChecker) {
Port *old_checker_itb_port, *old_checker_dtb_port;
Port *new_checker_itb_port, *new_checker_dtb_port;
old_checker_itb_port = oldChecker->getITBPtr()->getPort();
old_checker_dtb_port = oldChecker->getDTBPtr()->getPort();
new_checker_itb_port = newChecker->getITBPtr()->getPort();
new_checker_dtb_port = newChecker->getDTBPtr()->getPort();
MasterPort *old_checker_itb_port =
oldChecker->getITBPtr()->getMasterPort();
MasterPort *old_checker_dtb_port =
oldChecker->getDTBPtr()->getMasterPort();
MasterPort *new_checker_itb_port =
newChecker->getITBPtr()->getMasterPort();
MasterPort *new_checker_dtb_port =
newChecker->getDTBPtr()->getMasterPort();
// Move over any table walker ports if they exist for checker
if (new_checker_itb_port && !new_checker_itb_port->isConnected()) {
assert(old_checker_itb_port);
Port *peer = old_checker_itb_port->getPeer();;
new_checker_itb_port->setPeer(peer);
peer->setPeer(new_checker_itb_port);
SlavePort &slavePort = old_checker_itb_port->getSlavePort();;
new_checker_itb_port->bind(slavePort);
}
if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) {
assert(old_checker_dtb_port);
Port *peer = old_checker_dtb_port->getPeer();;
new_checker_dtb_port->setPeer(peer);
peer->setPeer(new_checker_dtb_port);
SlavePort &slavePort = old_checker_dtb_port->getSlavePort();;
new_checker_dtb_port->bind(slavePort);
}
}
}
@ -470,16 +464,12 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
// Connect new CPU to old CPU's memory only if new CPU isn't
// connected to anything. Also connect old CPU's memory to new
// CPU.
if (!ic.isConnected()) {
Port *peer = oldCPU->getInstPort().getPeer();
ic.setPeer(peer);
peer->setPeer(&ic);
if (!getInstPort().isConnected()) {
getInstPort().bind(oldCPU->getInstPort().getSlavePort());
}
if (!dc.isConnected()) {
Port *peer = oldCPU->getDataPort().getPeer();
dc.setPeer(peer);
peer->setPeer(&dc);
if (!getDataPort().isConnected()) {
getDataPort().bind(oldCPU->getDataPort().getSlavePort());
}
}
@ -568,8 +558,3 @@ BaseCPU::CpuPort::recvFunctional(PacketPtr pkt)
// long term this should never be called, but that assumed a split
// into master/slave and request/response.
}
void
BaseCPU::CpuPort::recvRangeChange()
{
}

View file

@ -117,7 +117,7 @@ class BaseCPU : public MemObject
* both atomic and timing access is to panic and the corresponding
* subclasses have to override these methods.
*/
class CpuPort : public Port
class CpuPort : public MasterPort
{
public:
@ -128,7 +128,7 @@ class BaseCPU : public MemObject
* @param _name structural owner of this port
*/
CpuPort(const std::string& _name, MemObject* _owner) :
Port(_name, _owner)
MasterPort(_name, _owner)
{ }
protected:
@ -141,8 +141,6 @@ class BaseCPU : public MemObject
void recvFunctional(PacketPtr pkt);
void recvRangeChange();
};
public:
@ -172,11 +170,11 @@ class BaseCPU : public MemObject
MasterID instMasterId() { return _instMasterId; }
/**
* Get a port on this MemObject. This method is virtual to allow
* Get a master port on this MemObject. This method is virtual to allow
* the subclasses of the BaseCPU to override it. All CPUs have a
* data and instruction port, but the Atomic CPU (in its current
* form) adds a port directly connected to the memory and has to
* override getPort.
* override getMasterPort.
*
* This method uses getDataPort and getInstPort to resolve the two
* ports.
@ -184,9 +182,10 @@ class BaseCPU : public MemObject
* @param if_name the port name
* @param idx ignored index
*
* @return a pointer to the port with the given name
* @return a reference to the port with the given name
*/
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
// Tick currentTick;
inline Tick frequency() const { return SimClock::Frequency / clock; }

View file

@ -132,12 +132,6 @@ class CheckerCPU : public BaseCPU
return *icachePort;
}
virtual Port *getPort(const std::string &name, int idx)
{
panic("Not supported on checker!");
return NULL;
}
public:
// Primary thread being run.
SimpleThread *thread;

View file

@ -139,7 +139,7 @@ class CacheUnit : public Resource
protected:
/** Cache interface. */
Port *cachePort;
MasterPort *cachePort;
bool cachePortBlocked;

View file

@ -186,8 +186,7 @@ class FullO3CPU : public BaseO3CPU
*
* @return true since we have to snoop
*/
virtual bool isSnooping()
{ return true; }
virtual bool isSnooping() const { return true; }
};
class TickEvent : public Event

View file

@ -90,7 +90,7 @@ class LSQUnit {
void regStats();
/** Sets the pointer to the dcache port. */
void setDcachePort(Port *dcache_port);
void setDcachePort(MasterPort *dcache_port);
/** Switches out LSQ unit. */
void switchOut();
@ -268,7 +268,7 @@ class LSQUnit {
LSQ *lsq;
/** Pointer to the dcache port. Used only for sending. */
Port *dcachePort;
MasterPort *dcachePort;
/** Derived class to hold any sender state the LSQ needs. */
class LSQSenderState : public Packet::SenderState, public FastAlloc

View file

@ -239,7 +239,7 @@ LSQUnit<Impl>::regStats()
template<class Impl>
void
LSQUnit<Impl>::setDcachePort(Port *dcache_port)
LSQUnit<Impl>::setDcachePort(MasterPort *dcache_port)
{
dcachePort = dcache_port;
}

View file

@ -36,9 +36,6 @@ class DerivOzoneCPU(BaseCPU):
numThreads = Param.Unsigned("number of HW thread contexts")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
width = Param.Unsigned("Width")
frontEndWidth = Param.Unsigned("Front end width")
frontEndLatency = Param.Unsigned("Front end latency")

View file

@ -316,8 +316,6 @@ class OzoneCPU : public BaseCPU
System *system;
PhysicalMemory *physmem;
virtual Port *getPort(const std::string &name, int idx);
FrontEnd *frontEnd;
BackEnd *backEnd;

View file

@ -390,18 +390,6 @@ OzoneCPU<Impl>::init()
thread.inSyscall = false;
}
template <class Impl>
Port *
OzoneCPU<Impl>::getPort(const std::string &if_name, int idx)
{
if (if_name == "dcache_port")
return backEnd->getDcachePort();
else if (if_name == "icache_port")
return frontEnd->getIcachePort();
else
panic("No Such Port\n");
}
template <class Impl>
void
OzoneCPU<Impl>::serialize(std::ostream &os)

View file

@ -68,7 +68,7 @@ class FrontEnd
/** IcachePort class. Handles doing the communication with the
* cache/memory.
*/
class IcachePort : public Port
class IcachePort : public MasterPort
{
protected:
/** Pointer to FE. */
@ -87,9 +87,6 @@ class FrontEnd
/** Functional version of receive. Panics. */
virtual void recvFunctional(PacketPtr pkt);
/** Receives range change. */
virtual void recvRangeChange();
/** Timing version of receive. Handles setting fetch to the
* proper status to start fetching. */
virtual bool recvTiming(PacketPtr pkt);

View file

@ -58,12 +58,6 @@ FrontEnd<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
warn("FrontEnd doesn't update state from functional calls");
}
template<class Impl>
void
FrontEnd<Impl>::IcachePort::recvRangeChange()
{
}
template<class Impl>
bool
FrontEnd<Impl>::IcachePort::recvTiming(PacketPtr pkt)

View file

@ -240,7 +240,7 @@ class OzoneLWLSQ {
/** Pointer to the back-end stage. */
BackEnd *be;
class DcachePort : public Port
class DcachePort : public MasterPort
{
protected:
OzoneLWLSQ *lsq;
@ -255,13 +255,10 @@ class OzoneLWLSQ {
virtual void recvFunctional(PacketPtr pkt);
virtual void recvRangeChange();
/**
* Is a snooper due to LSQ maintenance
*/
virtual bool isSnooping()
{ return true; }
virtual bool isSnooping() const { return true; }
virtual bool recvTiming(PacketPtr pkt);

View file

@ -74,12 +74,6 @@ OzoneLWLSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
warn("O3CPU doesn't update things on a recvFunctional");
}
template <class Impl>
void
OzoneLWLSQ<Impl>::DcachePort::recvRangeChange()
{
}
template <class Impl>
bool
OzoneLWLSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)

View file

@ -65,14 +65,14 @@ AtomicSimpleCPU::TickEvent::description() const
return "AtomicSimpleCPU tick";
}
Port *
AtomicSimpleCPU::getPort(const string &if_name, int idx)
MasterPort &
AtomicSimpleCPU::getMasterPort(const string &if_name, int idx)
{
if (if_name == "physmem_port") {
hasPhysMemPort = true;
return &physmemPort;
return physmemPort;
} else {
return BaseCPU::getPort(if_name, idx);
return BaseCPU::getMasterPort(if_name, idx);
}
}
@ -94,7 +94,7 @@ AtomicSimpleCPU::init()
}
if (hasPhysMemPort) {
AddrRangeList pmAddrList = physmemPort.getPeer()->getAddrRanges();
AddrRangeList pmAddrList = physmemPort.getSlavePort().getAddrRanges();
physMemAddr = *pmAddrList.begin();
}
// Atomic doesn't do MT right now, so contextId == threadId

View file

@ -112,10 +112,11 @@ class AtomicSimpleCPU : public BaseSimpleCPU
public:
/**
* Override the getPort of the BaseCPU so that we can provide a pointer
* to the physmemPort, unique to the Atomic CPU.
* Override the getMasterPort of the BaseCPU so that we can
* provide the physmemPort, unique to the Atomic CPU.
*/
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);

View file

@ -75,19 +75,19 @@ RubyDirectedTester::init()
generator->setDirectedTester(this);
}
Port *
RubyDirectedTester::getPort(const std::string &if_name, int idx)
MasterPort &
RubyDirectedTester::getMasterPort(const std::string &if_name, int idx)
{
if (if_name != "cpuPort") {
panic("RubyDirectedTester::getPort: unknown port %s requested",
if_name);
}
// pass it along to our super class
return MemObject::getMasterPort(if_name, idx);
} else {
if (idx >= static_cast<int>(ports.size())) {
panic("RubyDirectedTester::getMasterPort: unknown index %d\n", idx);
}
if (idx >= static_cast<int>(ports.size())) {
panic("RubyDirectedTester::getPort: unknown index %d requested\n", idx);
return *ports[idx];
}
return ports[idx];
}
Tick
@ -110,7 +110,7 @@ RubyDirectedTester::CpuPort::recvTiming(PacketPtr pkt)
return true;
}
Port*
MasterPort*
RubyDirectedTester::getCpuPort(int idx)
{
assert(idx >= 0 && idx < ports.size());

View file

@ -47,7 +47,7 @@ class DirectedGenerator;
class RubyDirectedTester : public MemObject
{
public:
class CpuPort : public Port
class CpuPort : public MasterPort
{
private:
RubyDirectedTester *tester;
@ -55,25 +55,27 @@ class RubyDirectedTester : public MemObject
public:
CpuPort(const std::string &_name, RubyDirectedTester *_tester,
uint32_t _idx)
: Port(_name, _tester), tester(_tester), idx(_idx)
: MasterPort(_name, _tester), tester(_tester), idx(_idx)
{}
uint32_t idx;
protected:
virtual bool recvTiming(PacketPtr pkt);
virtual void recvRetry()
{ panic("%s does not expect a retry\n", name()); }
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt) { }
virtual void recvRangeChange() { }
};
typedef RubyDirectedTesterParams Params;
RubyDirectedTester(const Params *p);
~RubyDirectedTester();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
Port* getCpuPort(int idx);
MasterPort* getCpuPort(int idx);
virtual void init();

View file

@ -84,11 +84,6 @@ MemTest::CpuPort::recvFunctional(PacketPtr pkt)
return;
}
void
MemTest::CpuPort::recvRangeChange()
{
}
void
MemTest::CpuPort::recvRetry()
{
@ -161,15 +156,15 @@ MemTest::MemTest(const Params *p)
dmaOutstanding = false;
}
Port *
MemTest::getPort(const std::string &if_name, int idx)
MasterPort &
MemTest::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "functional")
return &funcPort;
return funcPort;
else if (if_name == "test")
return &cachePort;
return cachePort;
else
panic("No Such Port\n");
return MemObject::getMasterPort(if_name, idx);
}
void

View file

@ -62,7 +62,8 @@ class MemTest : public MemObject
// main simulation loop (one cycle)
void tick();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
/**
* Print state of address in memory system via PrintReq (for
@ -84,14 +85,14 @@ class MemTest : public MemObject
TickEvent tickEvent;
class CpuPort : public Port
class CpuPort : public MasterPort
{
MemTest *memtest;
public:
CpuPort(const std::string &_name, MemTest *_memtest)
: Port(_name, _memtest), memtest(_memtest)
: MasterPort(_name, _memtest), memtest(_memtest)
{ }
protected:
@ -102,8 +103,6 @@ class MemTest : public MemObject
virtual void recvFunctional(PacketPtr pkt);
virtual void recvRangeChange();
virtual void recvRetry();
};

View file

@ -81,11 +81,6 @@ NetworkTest::CpuPort::recvFunctional(PacketPtr pkt)
return;
}
void
NetworkTest::CpuPort::recvRangeChange()
{
}
void
NetworkTest::CpuPort::recvRetry()
{
@ -126,13 +121,13 @@ NetworkTest::NetworkTest(const Params *p)
name(), id);
}
Port *
NetworkTest::getPort(const std::string &if_name, int idx)
MasterPort &
NetworkTest::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "test")
return &cachePort;
return cachePort;
else
panic("No Such Port\n");
return MemObject::getMasterPort(if_name, idx);
}
void

View file

@ -57,7 +57,8 @@ class NetworkTest : public MemObject
// main simulation loop (one cycle)
void tick();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
/**
* Print state of address in memory system via PrintReq (for
@ -79,14 +80,14 @@ class NetworkTest : public MemObject
TickEvent tickEvent;
class CpuPort : public Port
class CpuPort : public MasterPort
{
NetworkTest *networktest;
public:
CpuPort(const std::string &_name, NetworkTest *_networktest)
: Port(_name, _networktest), networktest(_networktest)
: MasterPort(_name, _networktest), networktest(_networktest)
{ }
protected:
@ -97,8 +98,6 @@ class NetworkTest : public MemObject
virtual void recvFunctional(PacketPtr pkt);
virtual void recvRangeChange();
virtual void recvRetry();
};

View file

@ -92,18 +92,19 @@ RubyTester::init()
m_checkTable_ptr = new CheckTable(m_num_cpu_sequencers, this);
}
Port *
RubyTester::getPort(const std::string &if_name, int idx)
MasterPort &
RubyTester::getMasterPort(const std::string &if_name, int idx)
{
if (if_name != "cpuPort") {
panic("RubyTester::getPort: unknown port %s requested\n", if_name);
}
// pass it along to our super class
return MemObject::getMasterPort(if_name, idx);
} else {
if (idx >= static_cast<int>(ports.size())) {
panic("RubyTester::getMasterPort: unknown index %d\n", idx);
}
if (idx >= static_cast<int>(ports.size())) {
panic("RubyTester::getPort: unknown index %d requested\n", idx);
return *ports[idx];
}
return ports[idx];
}
Tick
@ -135,7 +136,7 @@ RubyTester::CpuPort::recvTiming(PacketPtr pkt)
return true;
}
Port*
MasterPort*
RubyTester::getCpuPort(int idx)
{
assert(idx >= 0 && idx < ports.size());

View file

@ -45,23 +45,24 @@
class RubyTester : public MemObject
{
public:
class CpuPort : public Port
class CpuPort : public MasterPort
{
private:
RubyTester *tester;
public:
CpuPort(const std::string &_name, RubyTester *_tester, int _idx)
: Port(_name, _tester), tester(_tester), idx(_idx)
: MasterPort(_name, _tester), tester(_tester), idx(_idx)
{}
int idx;
protected:
virtual bool recvTiming(PacketPtr pkt);
virtual void recvRetry()
{ panic("%s does not expect a retry\n", name()); }
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt) { }
virtual void recvRangeChange() { }
};
struct SenderState : public Packet::SenderState
@ -86,9 +87,10 @@ class RubyTester : public MemObject
RubyTester(const Params *p);
~RubyTester();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
Port* getCpuPort(int idx);
MasterPort* getCpuPort(int idx);
virtual void init();

View file

@ -110,21 +110,26 @@ CopyEngine::CopyEngineChannel::~CopyEngineChannel()
delete [] copyBuffer;
}
Port *
CopyEngine::getPort(const std::string &if_name, int idx)
MasterPort &
CopyEngine::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "dma") {
if (idx < chan.size())
return chan[idx]->getPort();
if (if_name != "dma") {
// pass it along to our super class
return PciDev::getMasterPort(if_name, idx);
} else {
if (idx >= static_cast<int>(chan.size())) {
panic("CopyEngine::getMasterPort: unknown index %d\n", idx);
}
return chan[idx]->getMasterPort();
}
return PciDev::getPort(if_name, idx);
}
Port *
CopyEngine::CopyEngineChannel::getPort()
MasterPort &
CopyEngine::CopyEngineChannel::getMasterPort()
{
return &cePort;
return cePort;
}
void

View file

@ -94,7 +94,7 @@ class CopyEngine : public PciDev
public:
CopyEngineChannel(CopyEngine *_ce, int cid);
virtual ~CopyEngineChannel();
Port *getPort();
MasterPort &getMasterPort();
std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); }
virtual Tick read(PacketPtr pkt)
@ -196,7 +196,8 @@ class CopyEngine : public PciDev
void regStats();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);

View file

@ -71,14 +71,13 @@ PioDevice::init()
pioPort.sendRangeChange();
}
Port *
PioDevice::getPort(const std::string &if_name, int idx)
SlavePort &
PioDevice::getSlavePort(const std::string &if_name, int idx)
{
if (if_name == "pio") {
return &pioPort;
return pioPort;
}
panic("PioDevice %s has no port named %s\n", name(), if_name);
return NULL;
return MemObject::getSlavePort(if_name, idx);
}
unsigned int
@ -111,7 +110,7 @@ BasicPioDevice::getAddrRanges()
DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff,
bool recv_snoops)
: Port(dev->name() + "-dmaport", dev), device(dev), sys(s),
: MasterPort(dev->name() + "-dmaport", dev), device(dev), sys(s),
masterId(s->getMasterId(dev->name())),
pendingCount(0), actionInProgress(0), drainEvent(NULL),
backoffTime(0), minBackoffDelay(min_backoff),
@ -370,12 +369,12 @@ DmaDevice::~DmaDevice()
}
Port *
DmaDevice::getPort(const std::string &if_name, int idx)
MasterPort &
DmaDevice::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "dma") {
return &dmaPort;
return dmaPort;
}
return PioDevice::getPort(if_name, idx);
return PioDevice::getMasterPort(if_name, idx);
}

View file

@ -69,7 +69,7 @@ class PioPort : public SimpleTimingPort
};
class DmaPort : public Port
class DmaPort : public MasterPort
{
protected:
struct DmaReqState : public Packet::SenderState, public FastAlloc
@ -148,16 +148,9 @@ class DmaPort : public Port
panic("dma port shouldn't be used for pio access.");
}
virtual void recvRangeChange()
{
// DMA port is a master with a single slave so there is no choice and
// thus no need to worry about any address changes
}
virtual void recvRetry() ;
virtual bool isSnooping()
{ return recvSnoops; }
virtual bool isSnooping() const { return recvSnoops; }
void queueDma(PacketPtr pkt, bool front = false);
void sendDma();
@ -231,7 +224,7 @@ class PioDevice : public MemObject
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
friend class PioPort;
@ -304,7 +297,8 @@ class DmaDevice : public PioDevice
unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); }
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
friend class DmaPort;
};

View file

@ -218,12 +218,12 @@ class PciDev : public DmaDevice
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1)
virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1)
{
if (if_name == "config") {
return &configPort;
return configPort;
}
return DmaDevice::getPort(if_name, idx);
return DmaDevice::getSlavePort(if_name, idx);
}
};

View file

@ -222,8 +222,8 @@ X86ISA::I82094AA::signalInterrupt(int line)
apics.push_back(selected);
}
}
intPort.sendMessage(apics, message,
sys->getMemoryMode() == Enums::timing);
intMasterPort.sendMessage(apics, message,
sys->getMemoryMode() == Enums::timing);
}
}

View file

@ -121,11 +121,11 @@ class I82094AA : public PioDevice, public IntDev
void writeReg(uint8_t offset, uint32_t value);
uint32_t readReg(uint8_t offset);
Port *getPort(const std::string &if_name, int idx = -1)
MasterPort &getMasterPort(const std::string &if_name, int idx = -1)
{
if (if_name == "int_master")
return &intPort;
return PioDevice::getPort(if_name, idx);
return intMasterPort;
return PioDevice::getMasterPort(if_name, idx);
}
void signalInterrupt(int line);

View file

@ -43,8 +43,9 @@
#include "dev/x86/intdev.hh"
void
X86ISA::IntDev::IntPort::sendMessage(ApicList apics, TriggerIntMessage message,
bool timing)
X86ISA::IntDev::IntMasterPort::sendMessage(ApicList apics,
TriggerIntMessage message,
bool timing)
{
ApicList::iterator apicIt;
for (apicIt = apics.begin(); apicIt != apics.end(); apicIt++) {
@ -67,10 +68,9 @@ X86ISA::IntDev::IntPort::sendMessage(ApicList apics, TriggerIntMessage message,
void
X86ISA::IntDev::init()
{
if (!intPort.isConnected()) {
if (!intMasterPort.isConnected()) {
panic("Int port not connected to anything!");
}
intPort.sendRangeChange();
}
X86ISA::IntSourcePin *

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
@ -51,15 +63,14 @@ typedef std::list<int> ApicList;
class IntDev
{
protected:
class IntPort : public MessagePort
class IntSlavePort : public MessageSlavePort
{
IntDev * device;
Tick latency;
Addr intAddr;
public:
IntPort(const std::string &_name, MemObject * _parent,
IntDev *dev, Tick _latency) :
MessagePort(_name, _parent), device(dev), latency(_latency)
IntSlavePort(const std::string& _name, MemObject* _parent,
IntDev* dev, Tick _latency) :
MessageSlavePort(_name, _parent), device(dev), latency(_latency)
{
}
@ -72,6 +83,18 @@ class IntDev
{
return device->recvMessage(pkt);
}
};
class IntMasterPort : public MessageMasterPort
{
IntDev* device;
Tick latency;
public:
IntMasterPort(const std::string& _name, MemObject* _parent,
IntDev* dev, Tick _latency) :
MessageMasterPort(_name, _parent), device(dev), latency(_latency)
{
}
Tick recvResponse(PacketPtr pkt)
{
@ -84,11 +107,11 @@ class IntDev
TriggerIntMessage message, bool timing);
};
IntPort intPort;
IntMasterPort intMasterPort;
public:
IntDev(MemObject * parent, Tick latency = 0) :
intPort(parent->name() + ".int_master", parent, this, latency)
intMasterPort(parent->name() + ".int_master", parent, this, latency)
{
}

View file

@ -60,9 +60,9 @@ BadAddrEvent::process(ThreadContext *tc)
AddrRangeIter iter;
bool found = false;
Port &dataPort = tc->getCpuPtr()->getDataPort();
MasterPort &dataPort = tc->getCpuPtr()->getDataPort();
AddrRangeList resp = dataPort.getPeer()->getAddrRanges();
AddrRangeList resp = dataPort.getSlavePort().getAddrRanges();
for (iter = resp.begin(); iter != resp.end(); iter++) {
if (*iter == (K0Seg2Phys(a0) & PAddrImplMask))
found = true;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 ARM Limited
* Copyright (c) 2011-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@ -59,7 +59,7 @@ Bridge::BridgeSlavePort::BridgeSlavePort(const std::string &_name,
int _delay, int _nack_delay,
int _resp_limit,
std::vector<Range<Addr> > _ranges)
: Port(_name, _bridge), bridge(_bridge), masterPort(_masterPort),
: SlavePort(_name, _bridge), bridge(_bridge), masterPort(_masterPort),
delay(_delay), nackDelay(_nack_delay),
ranges(_ranges.begin(), _ranges.end()),
outstandingResponses(0), inRetry(false),
@ -71,7 +71,7 @@ Bridge::BridgeMasterPort::BridgeMasterPort(const std::string &_name,
Bridge* _bridge,
BridgeSlavePort& _slavePort,
int _delay, int _req_limit)
: Port(_name, _bridge), bridge(_bridge), slavePort(_slavePort),
: MasterPort(_name, _bridge), bridge(_bridge), slavePort(_slavePort),
delay(_delay), inRetry(false), reqQueueLimit(_req_limit),
sendEvent(*this)
{
@ -88,19 +88,25 @@ Bridge::Bridge(Params *p)
panic("No support for acknowledging writes\n");
}
Port*
Bridge::getPort(const std::string &if_name, int idx)
MasterPort&
Bridge::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "slave")
return &slavePort;
else if (if_name == "master")
return &masterPort;
else {
panic("Bridge %s has no port named %s\n", name(), if_name);
return NULL;
}
if (if_name == "master")
return masterPort;
else
// pass it along to our super class
return MemObject::getMasterPort(if_name, idx);
}
SlavePort&
Bridge::getSlavePort(const std::string &if_name, int idx)
{
if (if_name == "slave")
return slavePort;
else
// pass it along to our super class
return MemObject::getSlavePort(if_name, idx);
}
void
Bridge::init()
@ -473,19 +479,6 @@ Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt)
return found;
}
/** Function called by the port when the bridge is receiving a range change.*/
void
Bridge::BridgeMasterPort::recvRangeChange()
{
// no need to forward as the bridge has a fixed set of ranges
}
void
Bridge::BridgeSlavePort::recvRangeChange()
{
// is a slave port so do nothing
}
AddrRangeList
Bridge::BridgeSlavePort::getAddrRanges()
{

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 ARM Limited
* Copyright (c) 2011-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@ -122,7 +122,7 @@ class Bridge : public MemObject
* is responsible for. The slave port also has a buffer for the
* responses not yet sent.
*/
class BridgeSlavePort : public Port
class BridgeSlavePort : public SlavePort
{
private:
@ -244,11 +244,6 @@ class Bridge : public MemObject
pass it to the bridge. */
virtual void recvFunctional(PacketPtr pkt);
/**
* When receiving a range change on the slave side do nothing.
*/
virtual void recvRangeChange();
/** When receiving a address range request the peer port,
pass it to the bridge. */
virtual AddrRangeList getAddrRanges();
@ -260,7 +255,7 @@ class Bridge : public MemObject
* responses. The master port has a buffer for the requests not
* yet sent.
*/
class BridgeMasterPort : public Port
class BridgeMasterPort : public MasterPort
{
private:
@ -371,11 +366,6 @@ class Bridge : public MemObject
/** When receiving a Functional request from the peer port,
pass it to the bridge. */
virtual void recvFunctional(PacketPtr pkt);
/**
* When receiving a range change, pass it through the bridge.
*/
virtual void recvRangeChange();
};
/** Slave port of the bridge. */
@ -396,8 +386,9 @@ class Bridge : public MemObject
public:
const Params *params() const { return _params; }
/** A function used to return the port associated with this bus object. */
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort& getMasterPort(const std::string& if_name,
int idx = -1);
virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
virtual void init();

View file

@ -39,6 +39,7 @@
*
* Authors: Ali Saidi
* Andreas Hansson
* William Wang
*/
/**
@ -72,12 +73,14 @@ Bus::Bus(const BusParams *p)
// create the ports based on the size of the master and slave
// vector ports, and the presence of the default master
// id used to index into interfaces which is a flat vector of all
// ports
// id used to index into master and slave ports, that currently
// has holes to be able to use the id to index into either
int id = 0;
for (int i = 0; i < p->port_master_connection_count; ++i) {
std::string portName = csprintf("%s-p%d", name(), id);
interfaces.push_back(new BusPort(portName, this, id));
BusMasterPort* bp = new BusMasterPort(portName, this, id);
masterPorts.push_back(bp);
slavePorts.push_back(NULL);
++id;
}
@ -86,7 +89,9 @@ Bus::Bus(const BusParams *p)
if (p->port_default_connection_count) {
defaultPortId = id;
std::string portName = csprintf("%s-default", name());
interfaces.push_back(new BusPort(portName, this, id));
BusMasterPort* bp = new BusMasterPort(portName, this, id);
masterPorts.push_back(bp);
slavePorts.push_back(NULL);
++id;
// this is an additional master port
++nbrMasterPorts;
@ -96,44 +101,55 @@ Bus::Bus(const BusParams *p)
// nbrMasterPorts in the vector
for (int i = 0; i < p->port_slave_connection_count; ++i) {
std::string portName = csprintf("%s-p%d", name(), id);
interfaces.push_back(new BusPort(portName, this, id));
BusSlavePort* bp = new BusSlavePort(portName, this, id);
masterPorts.push_back(NULL);
slavePorts.push_back(bp);
++id;
}
clearPortCache();
}
Port *
Bus::getPort(const std::string &if_name, int idx)
MasterPort &
Bus::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "master") {
// the master index translates directly to the interfaces
// vector as they are stored first
return interfaces[idx];
} else if (if_name == "slave") {
// the slaves are stored after the masters and we must thus
// offset the slave index with the number of master ports
return interfaces[nbrMasterPorts + idx];
return *masterPorts[idx];
} else if (if_name == "default") {
return interfaces[defaultPortId];
return *masterPorts[defaultPortId];
} else {
panic("No port %s %d on bus %s\n", if_name, idx, name());
return MemObject::getMasterPort(if_name, idx);
}
}
SlavePort &
Bus::getSlavePort(const std::string &if_name, int idx)
{
if (if_name == "slave") {
return *slavePorts[nbrMasterPorts + idx];
} else {
return MemObject::getSlavePort(if_name, idx);
}
}
void
Bus::init()
{
std::vector<BusPort*>::iterator intIter;
std::vector<BusSlavePort*>::iterator intIter;
// iterate over our interfaces and determine which of our neighbours
// are snooping and add them as snoopers
for (intIter = interfaces.begin(); intIter != interfaces.end();
for (intIter = slavePorts.begin(); intIter != slavePorts.end();
intIter++) {
if ((*intIter)->getPeer()->isSnooping()) {
DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
(*intIter)->getPeer()->name());
snoopPorts.push_back(*intIter);
// since there are holes in the vector, check for NULL
if (*intIter != NULL) {
if ((*intIter)->getMasterPort().isSnooping()) {
DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
(*intIter)->getMasterPort().name());
snoopPorts.push_back(*intIter);
}
}
}
}
@ -194,7 +210,9 @@ Bus::recvTiming(PacketPtr pkt)
// get the source id and port
Packet::NodeID src_id = pkt->getSrc();
BusPort *src_port = interfaces[src_id];
// determine the source port based on the id
Port *src_port = slavePorts[src_id] ?
(Port*) slavePorts[src_id] : (Port*) masterPorts[src_id];
// If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list.
@ -218,14 +236,14 @@ Bus::recvTiming(PacketPtr pkt)
int dest_id;
Port *dest_port;
if (dest == Packet::Broadcast) {
if (pkt->isRequest()) {
// the packet is a memory-mapped request and should be broadcasted to
// our snoopers
assert(pkt->isRequest());
assert(dest == Packet::Broadcast);
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
BusPort *p = *s_iter;
BusSlavePort *p = *s_iter;
// we got this request from a snooping master
// (corresponding to our own slave port that is also in
// snoopPorts) and should not send it back to where it
@ -241,16 +259,28 @@ Bus::recvTiming(PacketPtr pkt)
// determine the destination based on the address and forward
// through the corresponding master port
dest_id = findPort(pkt->getAddr());
dest_port = interfaces[dest_id];
dest_port = masterPorts[dest_id];
} else {
// the packet is a response, and it should always go back to
// the port determined by the destination field
dest_id = dest;
assert(dest_id != src_id); // catch infinite loops
assert(dest_id < interfaces.size());
dest_port = interfaces[dest_id];
dest_port = slavePorts[dest_id] ?
(Port*) slavePorts[dest_id] : (Port*) masterPorts[dest_id];
// a normal response from the memory system (i.e. from a
// connected slave) should always go back to the master
// that issued it through one of our slave ports, however
// if this is a snoop response it could go either way, for
// example, it could be coming from a slave port
// connecting an L1 with a coherent master and another L1
// coherent master (one of our slave ports), or coming
// from the L1 and going to the L2 slave port (through one
// of our master ports)
}
assert(dest_port != NULL);
// if this is a snoop from a slave (corresponding to our own
// master), i.e. the memory side of the bus, then do not send it
// back to where it came from
@ -318,8 +348,6 @@ Bus::retryWaiting()
// send a retry to the port at the head of the retry list
inRetry = true;
DPRINTF(Bus, "Sending a retry to %s\n",
retryList.front()->getPeer()->name());
// note that we might have blocked on the receiving port being
// busy (rather than the bus itself) and now call retry before the
@ -427,7 +455,7 @@ Bus::recvAtomic(PacketPtr pkt)
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
BusPort *p = *s_iter;
BusSlavePort *p = *s_iter;
// we could have gotten this request from a snooping master
// (corresponding to our own slave port that is also in
// snoopPorts) and should not send it back to where it came
@ -464,7 +492,7 @@ Bus::recvAtomic(PacketPtr pkt)
// master), i.e. the memory side of the bus, then do not send it
// back to where it came from
if (dest_id != src_id) {
response_latency = interfaces[dest_id]->sendAtomic(pkt);
response_latency = masterPorts[dest_id]->sendAtomic(pkt);
}
// if we got a response from a snooper, restore it here
@ -504,7 +532,7 @@ Bus::recvFunctional(PacketPtr pkt)
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
BusPort *p = *s_iter;
BusSlavePort *p = *s_iter;
// we could have gotten this request from a snooping master
// (corresponding to our own slave port that is also in
// snoopPorts) and should not send it back to where it came
@ -528,7 +556,7 @@ Bus::recvFunctional(PacketPtr pkt)
// master), i.e. the memory side of the bus, then do not send
// it back to where it came from,
if (dest_id != src_id) {
interfaces[dest_id]->sendFunctional(pkt);
masterPorts[dest_id]->sendFunctional(pkt);
}
}
}
@ -551,7 +579,8 @@ Bus::recvRangeChange(int id)
defaultRange.clear();
// Only try to update these ranges if the user set a default responder.
if (useDefaultRange) {
AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges();
AddrRangeList ranges =
masterPorts[id]->getSlavePort().getAddrRanges();
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
defaultRange.push_back(*iter);
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
@ -560,8 +589,8 @@ Bus::recvRangeChange(int id)
}
} else {
assert(id < interfaces.size() && id >= 0);
BusPort *port = interfaces[id];
assert(id < masterPorts.size() && id >= 0);
BusMasterPort *port = masterPorts[id];
// Clean out any previously existent ids
for (PortIter portIter = portMap.begin();
@ -572,7 +601,7 @@ Bus::recvRangeChange(int id)
portIter++;
}
ranges = port->getPeer()->getAddrRanges();
ranges = port->getSlavePort().getAddrRanges();
for (iter = ranges.begin(); iter != ranges.end(); iter++) {
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
@ -580,8 +609,8 @@ Bus::recvRangeChange(int id)
if (portMap.insert(*iter, id) == portMap.end()) {
int conflict_id = portMap.find(*iter)->second;
fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
name(), interfaces[id]->getPeer()->name(),
interfaces[conflict_id]->getPeer()->name());
name(), masterPorts[id]->getSlavePort().name(),
masterPorts[conflict_id]->getSlavePort().name());
}
}
}
@ -589,10 +618,10 @@ Bus::recvRangeChange(int id)
// tell all our peers that our address range has changed.
// Don't tell the device that caused this change, it already knows
std::vector<BusPort*>::const_iterator intIter;
std::vector<BusSlavePort*>::const_iterator intIter;
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
if ((*intIter)->getId() != id)
for (intIter = slavePorts.begin(); intIter != slavePorts.end(); intIter++)
if (*intIter != NULL && (*intIter)->getId() != id)
(*intIter)->sendRangeChange();
inRecvRangeChange.erase(id);
@ -640,7 +669,7 @@ Bus::getAddrRanges(int id)
}
bool
Bus::isSnooping(int id)
Bus::isSnooping(int id) const
{
// in essence, answer the question if there are snooping ports
return !snoopPorts.empty();
@ -656,7 +685,7 @@ Bus::findBlockSize(int id)
PortIter p_end = portMap.end();
for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
unsigned tmp_bs = masterPorts[p_iter->second]->peerBlockSize();
if (tmp_bs > max_bs)
max_bs = tmp_bs;
}

View file

@ -40,6 +40,7 @@
* Authors: Ron Dreslinski
* Ali Saidi
* Andreas Hansson
* William Wang
*/
/**
@ -65,21 +66,85 @@
class Bus : public MemObject
{
/** Declaration of the buses port type, one will be instantiated for each
of the interfaces connecting to the bus. */
class BusPort : public Port
/**
* Declaration of the bus slave port type, one will be
* instantiated for each of the master interfaces connecting to
* the bus.
*/
class BusSlavePort : public SlavePort
{
private:
/** A pointer to the bus to which this port belongs. */
Bus *bus;
/** A id to keep track of the intercafe ID this port is connected to. */
/** A id to keep track of the interface ID of this port. */
int id;
public:
/** Constructor for the BusPort.*/
BusPort(const std::string &_name, Bus *_bus, int _id)
: Port(_name, _bus), bus(_bus), id(_id)
/** Constructor for the BusSlavePort.*/
BusSlavePort(const std::string &_name, Bus *_bus, int _id)
: SlavePort(_name, _bus), bus(_bus), id(_id)
{ }
int getId() const { return id; }
protected:
/** When reciving a timing request from the peer port (at id),
pass it to the bus. */
virtual bool recvTiming(PacketPtr pkt)
{ pkt->setSrc(id); return bus->recvTiming(pkt); }
/** When reciving a Atomic requestfrom the peer port (at id),
pass it to the bus. */
virtual Tick recvAtomic(PacketPtr pkt)
{ pkt->setSrc(id); return bus->recvAtomic(pkt); }
/** When reciving a Functional requestfrom the peer port (at id),
pass it to the bus. */
virtual void recvFunctional(PacketPtr pkt)
{ pkt->setSrc(id); bus->recvFunctional(pkt); }
/** When reciving a retry from the peer port (at id),
pass it to the bus. */
virtual void recvRetry()
{ bus->recvRetry(id); }
// This should return all the 'owned' addresses that are
// downstream from this bus, yes? That is, the union of all
// the 'owned' address ranges of all the other interfaces on
// this bus...
virtual AddrRangeList getAddrRanges()
{ return bus->getAddrRanges(id); }
// Ask the bus to ask everyone on the bus what their block size is and
// take the max of it. This might need to be changed a bit if we ever
// support multiple block sizes.
virtual unsigned deviceBlockSize() const
{ return bus->findBlockSize(id); }
};
/**
* Declaration of the bus master port type, one will be
* instantiated for each of the slave interfaces connecting to the
* bus.
*/
class BusMasterPort : public MasterPort
{
private:
/** A pointer to the bus to which this port belongs. */
Bus *bus;
/** A id to keep track of the interface ID of this port. */
int id;
public:
/** Constructor for the BusMasterPort.*/
BusMasterPort(const std::string &_name, Bus *_bus, int _id)
: MasterPort(_name, _bus), bus(_bus), id(_id)
{ }
int getId() const { return id; }
@ -90,7 +155,7 @@ class Bus : public MemObject
*
* @return a boolean that is true if this port is snooping
*/
virtual bool isSnooping()
virtual bool isSnooping() const
{ return bus->isSnooping(id); }
protected:
@ -120,13 +185,6 @@ class Bus : public MemObject
virtual void recvRetry()
{ bus->recvRetry(id); }
// This should return all the 'owned' addresses that are
// downstream from this bus, yes? That is, the union of all
// the 'owned' address ranges of all the other interfaces on
// this bus...
virtual AddrRangeList getAddrRanges()
{ return bus->getAddrRanges(id); }
// Ask the bus to ask everyone on the bus what their block size is and
// take the max of it. This might need to be changed a bit if we ever
// support multiple block sizes.
@ -151,8 +209,8 @@ class Bus : public MemObject
AddrRangeList defaultRange;
typedef std::vector<BusPort*>::iterator SnoopIter;
std::vector<BusPort*> snoopPorts;
typedef std::vector<BusSlavePort*>::iterator SnoopIter;
std::vector<BusSlavePort*> snoopPorts;
/** Function called by the port when the bus is recieving a Timing
transaction.*/
@ -250,7 +308,7 @@ class Bus : public MemObject
*
* @return a boolean indicating if this port is snooping or not
*/
bool isSnooping(int id);
bool isSnooping(int id) const;
/** Calculate the timing parameters for the packet. Updates the
* firstWordTime and finishTime fields of the packet object.
@ -292,9 +350,9 @@ class Bus : public MemObject
// interfaces vector
unsigned int nbrMasterPorts;
/** An ordered vector of pointers to the peer port interfaces
connected to this bus.*/
std::vector<BusPort*> interfaces;
/** The master and slave ports of the bus */
std::vector<BusSlavePort*> slavePorts;
std::vector<BusMasterPort*> masterPorts;
/** An array of pointers to ports that retry should be called on because the
* original send failed for whatever reason.*/
@ -338,7 +396,8 @@ class Bus : public MemObject
public:
/** A function used to return the port associated with this bus object. */
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
virtual void init();
virtual void startup();

25
src/mem/cache/base.cc vendored
View file

@ -57,7 +57,7 @@ using namespace std;
BaseCache::CacheSlavePort::CacheSlavePort(const std::string &_name,
BaseCache *_cache,
const std::string &_label)
: QueuedPort(_name, _cache, queue), queue(*_cache, *this, _label),
: QueuedSlavePort(_name, _cache, queue), queue(*_cache, *this, _label),
blocked(false), mustSendRetry(false), sendRetryEvent(this)
{
}
@ -99,7 +99,7 @@ BaseCache::CacheSlavePort::clearBlocked()
DPRINTF(CachePort, "Cache port %s sending retry\n", name());
mustSendRetry = false;
// @TODO: need to find a better time (next bus cycle?)
owner->schedule(sendRetryEvent, curTick() + 1);
owner.schedule(sendRetryEvent, curTick() + 1);
}
}
@ -108,10 +108,29 @@ void
BaseCache::init()
{
if (!cpuSidePort->isConnected() || !memSidePort->isConnected())
panic("Cache %s not hooked up on both sides\n", name());
fatal("Cache ports on %s are not connected\n", name());
cpuSidePort->sendRangeChange();
}
MasterPort &
BaseCache::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "mem_side") {
return *memSidePort;
} else {
return MemObject::getMasterPort(if_name, idx);
}
}
SlavePort &
BaseCache::getSlavePort(const std::string &if_name, int idx)
{
if (if_name == "cpu_side") {
return *cpuSidePort;
} else {
return MemObject::getSlavePort(if_name, idx);
}
}
void
BaseCache::regStats()

11
src/mem/cache/base.hh vendored
View file

@ -118,7 +118,7 @@ class BaseCache : public MemObject
* and the sendDeferredPacket of the timing port is modified to
* consider both the transmit list and the requests from the MSHR.
*/
class CacheMasterPort : public QueuedPort
class CacheMasterPort : public QueuedMasterPort
{
public:
@ -149,7 +149,7 @@ class BaseCache : public MemObject
CacheMasterPort(const std::string &_name, BaseCache *_cache,
PacketQueue &_queue) :
QueuedPort(_name, _cache, _queue)
QueuedMasterPort(_name, _cache, _queue)
{ }
/**
@ -157,7 +157,7 @@ class BaseCache : public MemObject
*
* @return always true
*/
virtual bool isSnooping() { return true; }
virtual bool isSnooping() const { return true; }
};
/**
@ -168,7 +168,7 @@ class BaseCache : public MemObject
* incoming requests. If blocked, the port will issue a retry once
* unblocked.
*/
class CacheSlavePort : public QueuedPort
class CacheSlavePort : public QueuedSlavePort
{
public:
@ -444,6 +444,9 @@ class BaseCache : public MemObject
virtual void init();
virtual MasterPort &getMasterPort(const std::string &if_name, int idx = -1);
virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
/**
* Query block size of a cache.
* @return The block size

View file

@ -40,7 +40,6 @@
#include "mem/cache/base.hh"
#include "mem/cache/cache.hh"
#include "mem/config/cache.hh"
#include "mem/bus.hh"
#include "params/BaseCache.hh"
// Tag Templates

View file

@ -249,8 +249,6 @@ class Cache : public BaseCache
/** Instantiates a basic cache object. */
Cache(const Params *p, TagStore *tags);
virtual Port *getPort(const std::string &if_name, int idx = -1);
void regStats();
/**

View file

@ -91,19 +91,6 @@ Cache<TagStore>::regStats()
tags->regStats(name());
}
template<class TagStore>
Port *
Cache<TagStore>::getPort(const std::string &if_name, int idx)
{
if (if_name == "cpu_side") {
return cpuSidePort;
} else if (if_name == "mem_side") {
return memSidePort;
} else {
panic("Port name %s unrecognized\n", if_name);
}
}
template<class TagStore>
void
Cache<TagStore>::cmpAndSwap(BlkType *blk, PacketPtr pkt)
@ -795,7 +782,7 @@ Cache<TagStore>::functionalAccess(PacketPtr pkt, bool fromCpuSide)
// continues towards the memory side
if (fromCpuSide) {
memSidePort->sendFunctional(pkt);
} else if (forwardSnoops) {
} else if (forwardSnoops && cpuSidePort->getMasterPort().isSnooping()) {
// if it came from the memory side, it must be a snoop request
// and we should only forward it if we are forwarding snoops
cpuSidePort->sendFunctional(pkt);

View file

@ -58,7 +58,7 @@ FSTranslatingPortProxy::FSTranslatingPortProxy(ThreadContext *tc)
{
}
FSTranslatingPortProxy::FSTranslatingPortProxy(Port &port)
FSTranslatingPortProxy::FSTranslatingPortProxy(MasterPort &port)
: PortProxy(port), _tc(NULL)
{
}

View file

@ -78,7 +78,7 @@ class FSTranslatingPortProxy : public PortProxy
FSTranslatingPortProxy(ThreadContext* tc);
FSTranslatingPortProxy(Port &port);
FSTranslatingPortProxy(MasterPort &port);
virtual ~FSTranslatingPortProxy();

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@ -26,6 +38,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Steve Reinhardt
* Andreas Hansson
*/
#include "mem/mem_object.hh"
@ -34,3 +47,15 @@ MemObject::MemObject(const Params *params)
: SimObject(params)
{
}
MasterPort&
MemObject::getMasterPort(const std::string& if_name, int idx)
{
fatal("%s does not have any master port named %s\n", name(), if_name);
}
SlavePort&
MemObject::getSlavePort(const std::string& if_name, int idx)
{
fatal("%s does not have any slave port named %s\n", name(), if_name);
}

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@ -26,11 +38,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ron Dreslinski
* Andreas Hansson
*/
/**
* @file
* Base Memory Object declaration.
* MemObject declaration.
*/
#ifndef __MEM_MEM_OBJECT_HH__
@ -41,8 +54,8 @@
#include "sim/sim_object.hh"
/**
* The base MemoryObject class, allows for an accesor function to a
* simobj that returns the Port.
* The MemObject class extends the SimObject with accessor functions
* to get its master and slave ports.
*/
class MemObject : public SimObject
{
@ -53,9 +66,27 @@ class MemObject : public SimObject
MemObject(const Params *params);
public:
/** Additional function to return the Port of a memory object. */
virtual Port *getPort(const std::string &if_name, int idx = -1) = 0;
/**
* Get a master port with a given name and index.
*
* @param if_name Port name
* @param idx Index in the case of a VectorPort
*
* @return A reference to the given port
*/
virtual MasterPort& getMasterPort(const std::string& if_name,
int idx = -1);
/**
* Get a slave port with a given name and index.
*
* @param if_name Port name
* @param idx Index in the case of a VectorPort
*
* @return A reference to the given port
*/
virtual SlavePort& getSlavePort(const std::string& if_name,
int idx = -1);
};
#endif //__MEM_MEM_OBJECT_HH__

View file

@ -43,17 +43,26 @@
#include "mem/mport.hh"
Tick
MessagePort::recvAtomic(PacketPtr pkt)
MessageSlavePort::recvAtomic(PacketPtr pkt)
{
if (pkt->cmd == MemCmd::MessageReq) {
return recvMessage(pkt);
} else if (pkt->cmd == MemCmd::MessageResp) {
} else {
panic("%s received unexpected atomic command %s from %s.\n",
name(), pkt->cmd.toString(), getMasterPort().name());
}
}
Tick
MessageMasterPort::recvAtomic(PacketPtr pkt)
{
if (pkt->cmd == MemCmd::MessageResp) {
// normally we would never see responses in recvAtomic, but
// since the timing port uses recvAtomic to implement
// recvTiming we have to deal with both cases
// recvTiming we have to deal with them here
return recvResponse(pkt);
} else {
panic("%s received unexpected atomic command %s from %s.\n",
name(), pkt->cmd.toString(), getPeer()->name());
name(), pkt->cmd.toString(), getSlavePort().name());
}
}

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
@ -41,15 +53,15 @@
* the underpinnings of SimpleTimingPort, but it tweaks some of the external
* functions.
*/
class MessagePort : public SimpleTimingPort
class MessageSlavePort : public SimpleTimingPort
{
public:
MessagePort(const std::string &name, MemObject *owner) :
MessageSlavePort(const std::string &name, MemObject *owner) :
SimpleTimingPort(name, owner)
{}
virtual ~MessagePort()
virtual ~MessageSlavePort()
{}
protected:
@ -57,6 +69,29 @@ class MessagePort : public SimpleTimingPort
Tick recvAtomic(PacketPtr pkt);
virtual Tick recvMessage(PacketPtr pkt) = 0;
};
class MessageMasterPort : public QueuedMasterPort
{
public:
MessageMasterPort(const std::string &name, MemObject *owner) :
QueuedMasterPort(name, owner, queue), queue(*owner, *this)
{}
virtual ~MessageMasterPort()
{}
void recvFunctional(PacketPtr pkt) { assert(false); }
Tick recvAtomic(PacketPtr pkt);
bool recvTiming(PacketPtr pkt) { recvAtomic(pkt); return true; }
protected:
/** A packet queue for outgoing packets. */
PacketQueue queue;
// Accept and ignore responses.
virtual Tick recvResponse(PacketPtr pkt)

View file

@ -439,18 +439,18 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
}
Port *
PhysicalMemory::getPort(const std::string &if_name, int idx)
SlavePort &
PhysicalMemory::getSlavePort(const std::string &if_name, int idx)
{
if (if_name != "port") {
panic("PhysicalMemory::getPort: unknown port %s requested\n", if_name);
}
return MemObject::getSlavePort(if_name, idx);
} else {
if (idx >= static_cast<int>(ports.size())) {
fatal("PhysicalMemory::getSlavePort: unknown index %d\n", idx);
}
if (idx >= static_cast<int>(ports.size())) {
panic("PhysicalMemory::getPort: unknown index %d requested\n", idx);
return *ports[idx];
}
return ports[idx];
}
PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
@ -458,13 +458,6 @@ PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
: SimpleTimingPort(_name, _memory), memory(_memory)
{ }
void
PhysicalMemory::MemoryPort::recvRangeChange()
{
// memory is a slave and thus should never have to worry about its
// neighbours address ranges
}
AddrRangeList
PhysicalMemory::MemoryPort::getAddrRanges()
{

View file

@ -67,8 +67,6 @@ class PhysicalMemory : public MemObject
virtual void recvFunctional(PacketPtr pkt);
virtual void recvRangeChange();
virtual AddrRangeList getAddrRanges();
virtual unsigned deviceBlockSize() const;
@ -196,7 +194,7 @@ class PhysicalMemory : public MemObject
public:
unsigned deviceBlockSize() const;
AddrRangeList getAddrRanges();
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
void virtual init();
unsigned int drain(Event *de);

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@ -26,6 +38,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Steve Reinhardt
* Andreas Hansson
* William Wang
*/
/**
@ -33,11 +47,10 @@
* Port object definitions.
*/
#include "base/trace.hh"
#include "debug/Config.hh"
#include "mem/mem_object.hh"
#include "mem/port.hh"
Port::Port(const std::string &_name, MemObject *_owner)
Port::Port(const std::string &_name, MemObject& _owner)
: portName(_name), peer(NULL), owner(_owner)
{
}
@ -46,22 +59,53 @@ Port::~Port()
{
}
void
Port::setPeer(Port *port)
/**
* Master port
*/
MasterPort::MasterPort(const std::string& name, MemObject* owner)
: Port(name, *owner), _slavePort(NULL)
{
DPRINTF(Config, "setting peer to %s\n", port->name());
}
peer = port;
MasterPort::~MasterPort()
{
}
SlavePort&
MasterPort::getSlavePort() const
{
if(_slavePort == NULL)
panic("Cannot getSlavePort on master port %s that is not connected\n",
name());
return *_slavePort;
}
void
Port::setOwner(MemObject *_owner)
MasterPort::bind(SlavePort& slave_port)
{
owner = _owner;
// master port keeps track of the slave port
_slavePort = &slave_port;
peer = &slave_port;
// slave port also keeps track of master port
_slavePort->bind(*this);
}
void
Port::printAddr(Addr a)
bool
MasterPort::isConnected() const
{
return _slavePort != NULL;
}
unsigned
MasterPort::peerBlockSize() const
{
return _slavePort->deviceBlockSize();
}
void
MasterPort::printAddr(Addr a)
{
Request req(a, 1, 0, Request::funcMasterId);
Packet pkt(&req, MemCmd::PrintReq, Packet::Broadcast);
@ -70,3 +114,44 @@ Port::printAddr(Addr a)
sendFunctional(&pkt);
}
/**
* Slave port
*/
SlavePort::SlavePort(const std::string& name, MemObject* owner)
: Port(name, *owner), _masterPort(NULL)
{
}
SlavePort::~SlavePort()
{
}
void
SlavePort::bind(MasterPort& master_port)
{
_masterPort = &master_port;
peer = &master_port;
}
MasterPort&
SlavePort::getMasterPort() const
{
if (_masterPort == NULL)
panic("Cannot getMasterPort on slave port %s that is not connected\n",
name());
return *_masterPort;
}
unsigned
SlavePort::peerBlockSize() const
{
return _masterPort->deviceBlockSize();
}
bool
SlavePort::isConnected() const
{
return _masterPort != NULL;
}

View file

@ -39,15 +39,12 @@
*
* Authors: Ron Dreslinski
* Andreas Hansson
* William Wang
*/
/**
* @file
* Port Object Declaration. Ports are used to interface memory objects to
* each other. They will always come in pairs, and we refer to the other
* port object as the peer. These are used to make the design more
* modular so that a specific interface between every type of objcet doesn't
* have to be created.
* Port Object Declaration.
*/
#ifndef __MEM_PORT_HH__
@ -58,7 +55,8 @@
#include "base/range.hh"
#include "mem/packet.hh"
/** This typedef is used to clean up getAddrRanges(). It's declared
/**
* This typedef is used to clean up getAddrRanges(). It's declared
* outside the Port object since it's also used by some mem objects.
* Eventually we should move this typedef to wherever Addr is
* defined.
@ -70,62 +68,47 @@ typedef std::list<Range<Addr> >::iterator AddrRangeIter;
class MemObject;
/**
* Ports are used to interface memory objects to
* each other. They will always come in pairs, and we refer to the other
* port object as the peer. These are used to make the design more
* modular so that a specific interface between every type of objcet doesn't
* have to be created.
* Ports are used to interface memory objects to each other. A port is
* either a master or a slave and the connected peer is always of the
* opposite role.
*
* Recv accesor functions are being called from the peer interface.
* Send accessor functions are being called from the device the port is
* associated with, and it will call the peer recv. accessor function.
* Each port has a name and an owner, and enables three basic types of
* accesses to the peer port: sendFunctional, sendAtomic and
* sendTiming.
*/
class Port
{
protected:
private:
/** Descriptive name (for DPRINTF output) */
mutable std::string portName;
std::string portName;
/** A pointer to the peer port. Ports always come in pairs, that way they
can use a standardized interface to communicate between different
memory objects. */
Port *peer;
protected:
/** A pointer to the MemObject that owns this port. This may not be set. */
MemObject *owner;
/** A pointer to the peer port. */
Port* peer;
/** A reference to the MemObject that owns this port. */
MemObject& owner;
public:
/**
* Constructor.
* Abstract base class for ports
*
* @param _name Port name for DPRINTF output. Should include name
* of memory system object to which the port belongs.
* @param _owner Pointer to the MemObject that owns this port.
* Will not necessarily be set.
* @param _name Port name including the owners name
* @param _owner The MemObject that is the structural owner of this port
*/
Port(const std::string &_name, MemObject *_owner);
/** Return port name (for DPRINTF). */
const std::string &name() const { return portName; }
Port(const std::string& _name, MemObject& _owner);
/**
* Virtual destructor due to inheritance.
*/
virtual ~Port();
void setName(const std::string &name)
{ portName = name; }
public:
/** Function to set the pointer for the peer port. */
virtual void setPeer(Port *port);
/** Function to get the pointer to the peer port. */
Port *getPeer() { return peer; }
/** Function to set the owner of this port. */
void setOwner(MemObject *_owner);
/** Function to return the owner of this port. */
MemObject *getOwner() { return owner; }
bool isConnected() { return peer != NULL; }
/** Return port name (for DPRINTF). */
const std::string name() const { return portName; }
protected:
@ -141,89 +124,109 @@ class Port
/** Called to recive a functional call from the peer port. */
virtual void recvFunctional(PacketPtr pkt) = 0;
/** Called to recieve an address range change from the peer port. */
virtual void recvRangeChange() = 0;
/** Called by a peer port if the send was unsuccesful, and had to
wait. This shouldn't be valid for response paths (IO Devices).
so it is set to panic if it isn't already defined.
*/
virtual void recvRetry() { panic("??"); }
/** Called by a peer port in order to determine the block size of the
device connected to this port. It sometimes doesn't make sense for
this function to be called, so it just returns 0. Anytthing that is
concerned with the size should just ignore that.
*/
virtual unsigned deviceBlockSize() const { return 0; }
/**
* Called by a peer port if sendTiming was unsuccesful, and had to
* wait.
*/
virtual void recvRetry() = 0;
public:
/**
* Get a list of the non-overlapping address ranges we are
* responsible for. The default implementation returns an empty
* list and thus no address ranges. Any slave port must override
* this function and return a populated list with at least one
* item.
* Attempt to send a timing packet to the peer port by calling its
* receive function. If the send does not succeed, as indicated by
* the return value, then the sender must wait for a recvRetry at
* which point it can re-issue a sendTiming.
*
* @return a list of ranges responded to
*/
virtual AddrRangeList getAddrRanges()
{ AddrRangeList ranges; return ranges; }
/**
* Determine if this port is snooping or not. The default
* implementation returns false and thus tells the neighbour we
* are not snooping. Any port that is to snoop (e.g. a cache
* connected to a bus) has to override this function.
* @param pkt Packet to send.
*
* @return true if the port should be considered a snooper
*/
virtual bool isSnooping()
{ return false; }
/** Function called by associated memory device (cache, memory, iodevice)
in order to send a timing request to the port. Simply calls the peer
port receive function.
@return This function returns if the send was succesful in it's
recieve. If it was a failure, then the port will wait for a recvRetry
at which point it can possibly issue a successful sendTiming. This is used in
case a cache has a higher priority request come in while waiting for
the bus to arbitrate.
* @return If the send was succesful or not.
*/
bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); }
/** Function called by the associated device to send an atomic
* access, an access in which the data is moved and the state is
* updated in one cycle, without interleaving with other memory
* accesses. Returns estimated latency of access.
/**
* Send a retry to a peer port that previously attempted a sendTiming
* which was unsuccessful.
*/
Tick sendAtomic(PacketPtr pkt)
{ return peer->recvAtomic(pkt); }
/** Function called by the associated device to send a functional access,
an access in which the data is instantly updated everywhere in the
memory system, without affecting the current state of any block or
moving the block.
*/
void sendFunctional(PacketPtr pkt)
{ return peer->recvFunctional(pkt); }
void sendRetry() { return peer->recvRetry(); }
/**
* Called by the associated device to send a status range to the
* peer interface.
* Send an atomic packet, where the data is moved and the state
* is updated in zero time, without interleaving with other
* memory accesses.
*
* @param pkt Packet to send.
*
* @return Estimated latency of access.
*/
void sendRangeChange() const { peer->recvRangeChange(); }
Tick sendAtomic(PacketPtr pkt) { return peer->recvAtomic(pkt); }
/** When a timing access doesn't return a success, some time later the
Retry will be sent.
*/
void sendRetry() { return peer->recvRetry(); }
/**
* Send a functional packet, where the data is instantly updated
* everywhere in the memory system, without affecting the current
* state of any block or moving the block.
*
* @param pkt Packet to send.
*/
void sendFunctional(PacketPtr pkt) { return peer->recvFunctional(pkt); }
};
/** Forward declaration */
class SlavePort;
/**
* A MasterPort is a specialisation of a port. In addition to the
* basic functionality of sending packets to its slave peer, it also
* has functions specific to a master, e.g. to receive range changes
* or determine if the port is snooping or not.
*/
class MasterPort : public Port
{
private:
SlavePort* _slavePort;
public:
MasterPort(const std::string& name, MemObject* owner);
virtual ~MasterPort();
void bind(SlavePort& slave_port);
SlavePort& getSlavePort() const;
bool isConnected() const;
/**
* Called to receive an address range change from the peer slave
* port. the default implementation ignored the change and does
* nothing. Override this function in a derived class if the owner
* needs to be aware of he laesddress ranges, e.g. in an
* interconnect component like a bus.
*/
virtual void recvRangeChange() { }
/**
* Determine if this master port is snooping or not. The default
* implementation returns false and thus tells the neighbour we
* are not snooping. Any master port that wants to receive snoop
* requests (e.g. a cache connected to a bus) has to override this
* function.
*
* @return true if the port should be considered a snooper
*/
virtual bool isSnooping() const { return false; }
/**
* Called by a peer port in order to determine the block size of
* the owner of this port.
*/
virtual unsigned deviceBlockSize() const { return 0; }
/** Called by the associated device if it wishes to find out the blocksize
of the device on attached to the peer port.
*/
unsigned peerBlockSize() const { return peer->deviceBlockSize(); }
unsigned peerBlockSize() const;
/** Inject a PrintReq for the given address to print the state of
* that address throughout the memory system. For debugging.
@ -231,4 +234,52 @@ class Port
void printAddr(Addr a);
};
/**
* A SlavePort is a specialisation of a port. In addition to the
* basic functionality of sending packets to its master peer, it also
* has functions specific to a slave, e.g. to send range changes
* and get the address ranges that the port responds to.
*/
class SlavePort : public Port
{
private:
MasterPort* _masterPort;
public:
SlavePort(const std::string& name, MemObject* owner);
virtual ~SlavePort();
void bind(MasterPort& master_port);
MasterPort& getMasterPort() const;
bool isConnected() const;
/**
* Called by a peer port in order to determine the block size of
* the owner of this port.
*/
virtual unsigned deviceBlockSize() const { return 0; }
/** Called by the associated device if it wishes to find out the blocksize
of the device on attached to the peer port.
*/
unsigned peerBlockSize() const;
/**
* Called by the owner to send a range change
*/
void sendRangeChange() const { _masterPort->recvRangeChange(); }
/**
* Get a list of the non-overlapping address ranges the owner is
* responsible for. All slave ports must override this function
* and return a populated list with at least one item.
*
* @return a list of ranges responded to
*/
virtual AddrRangeList getAddrRanges() = 0;
};
#endif //__MEM_PORT_HH__

View file

@ -86,12 +86,12 @@ class PortProxy
private:
/** The actual physical port used by this proxy. */
Port &_port;
MasterPort &_port;
void blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd) const;
public:
PortProxy(Port &port) : _port(port) { }
PortProxy(MasterPort &port) : _port(port) { }
virtual ~PortProxy() { }
/**

View file

@ -56,7 +56,7 @@
* queue is a parameter to allow tailoring of the queue implementation
* (used in the cache).
*/
class QueuedPort : public Port
class QueuedSlavePort : public SlavePort
{
protected:
@ -68,7 +68,46 @@ class QueuedPort : public Port
* packet again. */
virtual void recvRetry() { queue.retry(); }
virtual void recvRangeChange() { }
public:
/**
* Create a QueuedPort with a given name, owner, and a supplied
* implementation of a packet queue. The external definition of
* the queue enables e.g. the cache to implement a specific queue
* behaviuor in a subclass, and provide the latter to the
* QueuePort constructor.
*/
QueuedSlavePort(const std::string& name, MemObject* owner,
PacketQueue &queue) :
SlavePort(name, owner), queue(queue)
{ }
virtual ~QueuedSlavePort() { }
/** Check the list of buffered packets against the supplied
* functional request. */
bool checkFunctional(PacketPtr pkt) { return queue.checkFunctional(pkt); }
/**
* Hook for draining the queued port.
*
* @param de an event which is used to signal back to the caller
* @returns a number indicating how many times process will be called
*/
unsigned int drain(Event *de) { return queue.drain(de); }
};
class QueuedMasterPort : public MasterPort
{
protected:
/** Packet queue used to store outgoing requests and responses. */
PacketQueue &queue;
/** This function is notification that the device should attempt to send a
* packet again. */
virtual void recvRetry() { queue.retry(); }
public:
@ -79,11 +118,12 @@ class QueuedPort : public Port
* behaviuor in a subclass, and provide the latter to the
* QueuePort constructor.
*/
QueuedPort(const std::string& name, MemObject* owner, PacketQueue &queue) :
Port(name, owner), queue(queue)
QueuedMasterPort(const std::string& name, MemObject* owner,
PacketQueue &queue) :
MasterPort(name, owner), queue(queue)
{ }
virtual ~QueuedPort() { }
virtual ~QueuedMasterPort() { }
/** Check the list of buffered packets against the supplied
* functional request. */

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2009 Advanced Micro Devices, Inc.
* Copyright (c) 2011 Mark D. Hill and David A. Wood
* All rights reserved.
@ -35,26 +47,27 @@
#include "mem/ruby/system/RubyPort.hh"
RubyPort::RubyPort(const Params *p)
: MemObject(p), pio_port(csprintf("%s-pio-port", name()), this),
physMemPort(csprintf("%s-physMemPort", name()), this)
: MemObject(p), m_version(p->version), m_controller(NULL),
m_mandatory_q_ptr(NULL),
pio_port(csprintf("%s-pio-port", name()), this),
m_usingRubyTester(p->using_ruby_tester), m_request_cnt(0),
physMemPort(csprintf("%s-physMemPort", name()), this),
drainEvent(NULL), physmem(p->physmem), ruby_system(p->ruby_system),
waitingOnSequencer(false), access_phys_mem(p->access_phys_mem)
{
m_version = p->version;
assert(m_version != -1);
physmem = p->physmem;
// create the slave ports based on the number of connected ports
for (size_t i = 0; i < p->port_slave_connection_count; ++i) {
slave_ports.push_back(new M5Port(csprintf("%s-slave%d", name(), i),
this, ruby_system, access_phys_mem));
}
m_controller = NULL;
m_mandatory_q_ptr = NULL;
m_request_cnt = 0;
m_usingRubyTester = p->using_ruby_tester;
access_phys_mem = p->access_phys_mem;
drainEvent = NULL;
ruby_system = p->ruby_system;
waitingOnSequencer = false;
// create the master ports based on the number of connected ports
for (size_t i = 0; i < p->port_master_connection_count; ++i) {
master_ports.push_back(new PioPort(csprintf("%s-master%d", name(), i),
this));
}
}
void
@ -64,52 +77,63 @@ RubyPort::init()
m_mandatory_q_ptr = m_controller->getMandatoryQueue();
}
Port *
RubyPort::getPort(const std::string &if_name, int idx)
MasterPort &
RubyPort::getMasterPort(const std::string &if_name, int idx)
{
// used by the CPUs to connect the caches to the interconnect, and
// for the x86 case also the interrupt master
if (if_name == "slave") {
M5Port* cpuPort = new M5Port(csprintf("%s-slave%d", name(), idx),
this, ruby_system, access_phys_mem);
cpu_ports.push_back(cpuPort);
return cpuPort;
if (if_name == "pio_port") {
return pio_port;
}
if (if_name == "physMemPort") {
return physMemPort;
}
// used by the x86 CPUs to connect the interrupt PIO and interrupt slave
// port
if (if_name == "master") {
PioPort* masterPort = new PioPort(csprintf("%s-master%d", name(), idx),
this);
if (if_name != "master") {
// pass it along to our super class
return MemObject::getMasterPort(if_name, idx);
} else {
if (idx >= static_cast<int>(master_ports.size())) {
panic("RubyPort::getMasterPort: unknown index %d\n", idx);
}
return masterPort;
return *master_ports[idx];
}
}
if (if_name == "pio_port") {
return &pio_port;
SlavePort &
RubyPort::getSlavePort(const std::string &if_name, int idx)
{
// used by the CPUs to connect the caches to the interconnect, and
// for the x86 case also the interrupt master
if (if_name != "slave") {
// pass it along to our super class
return MemObject::getSlavePort(if_name, idx);
} else {
if (idx >= static_cast<int>(slave_ports.size())) {
panic("RubyPort::getSlavePort: unknown index %d\n", idx);
}
return *slave_ports[idx];
}
if (if_name == "physMemPort") {
return &physMemPort;
}
return NULL;
}
RubyPort::PioPort::PioPort(const std::string &_name,
RubyPort *_port)
: QueuedPort(_name, _port, queue), queue(*_port, *this), ruby_port(_port)
: QueuedMasterPort(_name, _port, queue), queue(*_port, *this),
ruby_port(_port)
{
DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name);
DPRINTF(RubyPort, "creating master port on ruby sequencer %s\n", _name);
}
RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
RubySystem *_system, bool _access_phys_mem)
: QueuedPort(_name, _port, queue), queue(*_port, *this),
: QueuedSlavePort(_name, _port, queue), queue(*_port, *this),
ruby_port(_port), ruby_system(_system),
_onRetryList(false), access_phys_mem(_access_phys_mem)
{
DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name);
}
Tick
@ -549,11 +573,15 @@ RubyPort::getDrainCount(Event *de)
DPRINTF(Config, "count after physmem check %d\n", count);
}
for (CpuPortIter p_iter = cpu_ports.begin(); p_iter != cpu_ports.end();
p_iter++) {
M5Port* cpu_port = *p_iter;
count += cpu_port->drain(de);
DPRINTF(Config, "count after cpu port check %d\n", count);
for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
count += (*p)->drain(de);
DPRINTF(Config, "count after slave port check %d\n", count);
}
for (std::vector<PioPort*>::iterator p = master_ports.begin();
p != master_ports.end(); ++p) {
count += (*p)->drain(de);
DPRINTF(Config, "count after master port check %d\n", count);
}
DPRINTF(Config, "final count %d\n", count);
@ -657,11 +685,19 @@ RubyPort::PioPort::sendNextCycle(PacketPtr pkt)
return true;
}
AddrRangeList
RubyPort::M5Port::getAddrRanges()
{
// at the moment the assumption is that the master does not care
AddrRangeList ranges;
return ranges;
}
bool
RubyPort::M5Port::isPhysMemAddress(Addr addr)
{
AddrRangeList physMemAddrList =
ruby_port->physMemPort.getPeer()->getAddrRanges();
ruby_port->physMemPort.getSlavePort().getAddrRanges();
for (AddrRangeIter iter = physMemAddrList.begin();
iter != physMemAddrList.end();
iter++) {
@ -684,9 +720,12 @@ void
RubyPort::ruby_eviction_callback(const Address& address)
{
DPRINTF(RubyPort, "Sending invalidations.\n");
// should this really be using funcMasterId?
Request req(address.getAddress(), 0, 0, Request::funcMasterId);
for (CpuPortIter it = cpu_ports.begin(); it != cpu_ports.end(); it++) {
Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1);
(*it)->sendNextCycle(pkt);
for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
if ((*p)->getMasterPort().isSnooping()) {
Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1);
(*p)->sendNextCycle(pkt);
}
}
}

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2009 Advanced Micro Devices, Inc.
* Copyright (c) 2011 Mark D. Hill and David A. Wood
* All rights reserved.
@ -46,7 +58,7 @@ class AbstractController;
class RubyPort : public MemObject
{
public:
class M5Port : public QueuedPort
class M5Port : public QueuedSlavePort
{
private:
@ -74,6 +86,7 @@ class RubyPort : public MemObject
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
virtual AddrRangeList getAddrRanges();
private:
bool isPhysMemAddress(Addr addr);
@ -83,7 +96,7 @@ class RubyPort : public MemObject
friend class M5Port;
class PioPort : public QueuedPort
class PioPort : public QueuedMasterPort
{
private:
@ -119,7 +132,8 @@ class RubyPort : public MemObject
void init();
Port *getPort(const std::string &if_name, int idx);
MasterPort &getMasterPort(const std::string &if_name, int idx);
SlavePort &getSlavePort(const std::string &if_name, int idx);
virtual RequestStatus makeRequest(PacketPtr pkt) = 0;
virtual int outstandingCount() const = 0;
@ -163,9 +177,10 @@ class RubyPort : public MemObject
PioPort physMemPort;
/*! Vector of CPU Port attached to this Ruby port. */
/** Vector of M5 Ports attached to this Ruby port. */
typedef std::vector<M5Port*>::iterator CpuPortIter;
std::vector<M5Port*> cpu_ports;
std::vector<M5Port*> slave_ports;
std::vector<PioPort*> master_ports;
Event *drainEvent;

View file

@ -53,7 +53,7 @@
using namespace TheISA;
SETranslatingPortProxy::SETranslatingPortProxy(Port& port, Process *p,
SETranslatingPortProxy::SETranslatingPortProxy(MasterPort& port, Process *p,
AllocType alloc)
: PortProxy(port), pTable(p->pTable), process(p),
allocating(alloc)

View file

@ -80,7 +80,7 @@ class SETranslatingPortProxy : public PortProxy
AllocType allocating;
public:
SETranslatingPortProxy(Port& port, Process* p, AllocType alloc);
SETranslatingPortProxy(MasterPort& port, Process* p, AllocType alloc);
virtual ~SETranslatingPortProxy();
bool tryReadBlob(Addr addr, uint8_t *p, int size) const;

View file

@ -46,7 +46,7 @@
SimpleTimingPort::SimpleTimingPort(const std::string& _name,
MemObject* _owner) :
QueuedPort(_name, _owner, queue), queue(*_owner, *this)
QueuedSlavePort(_name, _owner, queue), queue(*_owner, *this)
{
}
@ -63,6 +63,9 @@ SimpleTimingPort::recvFunctional(PacketPtr pkt)
bool
SimpleTimingPort::recvTiming(PacketPtr pkt)
{
// the port is a slave and should hence only get timing requests
assert(pkt->isRequest());
if (pkt->memInhibitAsserted()) {
// snooper will supply based on copy of packet
// still target's responsibility to delete packet

View file

@ -57,7 +57,7 @@
* recvFunctional and recvTiming through recvAtomic. It is always a
* slave port.
*/
class SimpleTimingPort : public QueuedPort
class SimpleTimingPort : public QueuedSlavePort
{
protected:

View file

@ -44,24 +44,6 @@
using namespace std;
/**
* Look up a MemObject port. Helper function for connectPorts().
*/
Port *
lookupPort(SimObject *so, const std::string &name, int i)
{
MemObject *mo = dynamic_cast<MemObject *>(so);
if (mo == NULL) {
warn("error casting SimObject %s to MemObject", so->name());
return NULL;
}
Port *p = mo->getPort(name, i);
if (p == NULL)
warn("error looking up port %s on object %s", name, so->name());
return p;
}
EtherInt *
lookupEthPort(SimObject *so, const std::string &name, int i)
{
@ -83,6 +65,7 @@ lookupEthPort(SimObject *so, const std::string &name, int i)
/**
* Connect the described MemObject ports. Called from Python via SWIG.
* The indices i1 & i2 will be -1 for regular ports, >= 0 for vector ports.
* SimObject1 is the master, and SimObject2 is the slave
*/
int
connectPorts(SimObject *o1, const std::string &name1, int i1,
@ -109,16 +92,20 @@ connectPorts(SimObject *o1, const std::string &name1, int i1,
}
}
}
Port *p1 = lookupPort(o1, name1, i1);
Port *p2 = lookupPort(o2, name2, i2);
MemObject *mo1, *mo2;
mo1 = dynamic_cast<MemObject*>(o1);
mo2 = dynamic_cast<MemObject*>(o2);
if (p1 == NULL || p2 == NULL) {
warn("connectPorts: port lookup error");
return 0;
if(mo1 == NULL || mo2 == NULL) {
panic ("Error casting SimObjects %s and %s to MemObject", o1->name(),
o2->name());
}
p1->setPeer(p2);
p2->setPeer(p1);
// generic master/slave port connection
MasterPort& masterPort = mo1->getMasterPort(name1, i1);
SlavePort& slavePort = mo2->getSlavePort(name2, i2);
masterPort.bind(slavePort);
return 1;
}

View file

@ -174,11 +174,11 @@ System::init()
panic("System port on %s is not connected.\n", name());
}
Port*
System::getPort(const std::string &if_name, int idx)
MasterPort&
System::getMasterPort(const std::string &if_name, int idx)
{
// no need to distinguish at the moment (besides checking)
return &_systemPort;
return _systemPort;
}
void

View file

@ -78,7 +78,7 @@ class System : public MemObject
* master for debug access and for non-structural entities that do
* not have a port of their own.
*/
class SystemPort : public Port
class SystemPort : public MasterPort
{
public:
@ -86,22 +86,16 @@ class System : public MemObject
* Create a system port with a name and an owner.
*/
SystemPort(const std::string &_name, MemObject *_owner)
: Port(_name, _owner)
: MasterPort(_name, _owner)
{ }
bool recvTiming(PacketPtr pkt)
{ panic("SystemPort does not receive timing!\n"); return false; }
void recvRetry()
{ panic("SystemPort does not expect retry!\n"); }
Tick recvAtomic(PacketPtr pkt)
{ panic("SystemPort does not receive atomic!\n"); return 0; }
void recvFunctional(PacketPtr pkt)
{ panic("SystemPort does not receive functional!\n"); }
/**
* The system port is a master port connected to a single
* slave and thus do not care about what ranges the slave
* covers (as there is nothing to choose from).
*/
void recvRangeChange() { }
};
SystemPort _systemPort;
@ -122,12 +116,12 @@ class System : public MemObject
*
* @return a reference to the system port we own
*/
Port& getSystemPort() { return _systemPort; }
MasterPort& getSystemPort() { return _systemPort; }
/**
* Additional function to return the Port of a memory object.
*/
Port *getPort(const std::string &if_name, int idx = -1);
MasterPort& getMasterPort(const std::string &if_name, int idx = -1);
static const char *MemoryModeStrings[3];

View file

@ -49,8 +49,7 @@
#include "sim/sim_object.hh"
class ThreadContext;
class Packet;
class Port;
class MasterPort;
class BaseTLB : public SimObject
{
@ -65,10 +64,16 @@ class BaseTLB : public SimObject
public:
virtual void demapPage(Addr vaddr, uint64_t asn) = 0;
/** Get any port that the TLB or hardware table walker needs.
* This is used for migrating port connections during a takeOverFrom()
* call. */
virtual Port* getPort() { return NULL; }
/**
* Get the table walker master port if present. This is used for
* migrating port connections during a CPU takeOverFrom()
* call. For architectures that do not have a table walker, NULL
* is returned, hence the use of a pointer rather than a
* reference.
*
* @return A pointer to the walker master port or NULL if not present
*/
virtual MasterPort* getMasterPort() { return NULL; }
class Translation
{