}
}
-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
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);
return fault;
}
-Port*
-TLB::getPort()
+MasterPort*
+TLB::getMasterPort()
{
- return tableWalker->getPort("port");
+ return &tableWalker->getMasterPort("port");
}
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.
/*
+ * 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.
*
//
BasicPioDevice::init();
IntDev::init();
+
+ // the slave port has a range so inform the connected master
+ intSlavePort.sendRangeChange();
}
break;
}
pendingIPIs += apics.size();
- intPort.sendMessage(apics, message, timing);
+ intMasterPort.sendMessage(apics, message, timing);
newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
}
break;
int initialApicId;
// Port for receiving interrupts
- IntPort intSlavePort;
+ IntSlavePort intSlavePort;
public:
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);
}
/*
return;
}
-void
-Walker::WalkerPort::recvRangeChange()
-{
-}
-
void
Walker::WalkerPort::recvRetry()
{
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
{
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:
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;
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.
{
}
-Port *
-TLB::getPort()
+MasterPort *
+TLB::getMasterPort()
{
- return walker->getPort("port");
+ return &walker->getMasterPort("port");
}
} // namespace X86ISA
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string §ion);
- 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();
};
}
/*
- * 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
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
void
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
{
- CpuPort &ic = getInstPort();
- CpuPort &dc = getDataPort();
assert(threadContexts.size() == oldCPU->threadContexts.size());
_cpuId = oldCPU->cpuId();
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
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);
}
}
}
// 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());
}
}
// long term this should never be called, but that assumed a split
// into master/slave and request/response.
}
-
-void
-BaseCPU::CpuPort::recvRangeChange()
-{
-}
* 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:
* @param _name structural owner of this port
*/
CpuPort(const std::string& _name, MemObject* _owner) :
- Port(_name, _owner)
+ MasterPort(_name, _owner)
{ }
protected:
void recvFunctional(PacketPtr pkt);
- void recvRangeChange();
-
};
public:
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.
* @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; }
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;
protected:
/** Cache interface. */
- Port *cachePort;
+ MasterPort *cachePort;
bool cachePortBlocked;
*
* @return true since we have to snoop
*/
- virtual bool isSnooping()
- { return true; }
+ virtual bool isSnooping() const { return true; }
};
class TickEvent : public Event
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();
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
template<class Impl>
void
-LSQUnit<Impl>::setDcachePort(Port *dcache_port)
+LSQUnit<Impl>::setDcachePort(MasterPort *dcache_port)
{
dcachePort = dcache_port;
}
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")
System *system;
PhysicalMemory *physmem;
- virtual Port *getPort(const std::string &name, int idx);
-
FrontEnd *frontEnd;
BackEnd *backEnd;
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)
/** IcachePort class. Handles doing the communication with the
* cache/memory.
*/
- class IcachePort : public Port
+ class IcachePort : public MasterPort
{
protected:
/** Pointer to FE. */
/** 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);
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)
/** Pointer to the back-end stage. */
BackEnd *be;
- class DcachePort : public Port
+ class DcachePort : public MasterPort
{
protected:
OzoneLWLSQ *lsq;
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);
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)
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);
}
}
}
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
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 §ion);
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
return true;
}
-Port*
+MasterPort*
RubyDirectedTester::getCpuPort(int idx)
{
assert(idx >= 0 && idx < ports.size());
class RubyDirectedTester : public MemObject
{
public:
- class CpuPort : public Port
+ class CpuPort : public MasterPort
{
private:
RubyDirectedTester *tester;
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();
return;
}
-void
-MemTest::CpuPort::recvRangeChange()
-{
-}
-
void
MemTest::CpuPort::recvRetry()
{
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
// 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
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:
virtual void recvFunctional(PacketPtr pkt);
- virtual void recvRangeChange();
-
virtual void recvRetry();
};
return;
}
-void
-NetworkTest::CpuPort::recvRangeChange()
-{
-}
-
void
NetworkTest::CpuPort::recvRetry()
{
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
// 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
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:
virtual void recvFunctional(PacketPtr pkt);
- virtual void recvRangeChange();
-
virtual void recvRetry();
};
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
return true;
}
-Port*
+MasterPort*
RubyTester::getCpuPort(int idx)
{
assert(idx >= 0 && idx < ports.size());
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
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();
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
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)
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);
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
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),
}
-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);
}
};
-class DmaPort : public Port
+class DmaPort : public MasterPort
{
protected:
struct DmaReqState : public Packet::SenderState, public FastAlloc
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();
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;
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;
};
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);
}
};
apics.push_back(selected);
}
}
- intPort.sendMessage(apics, message,
- sys->getMemoryMode() == Enums::timing);
+ intMasterPort.sendMessage(apics, message,
+ sys->getMemoryMode() == Enums::timing);
}
}
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);
#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++) {
void
X86ISA::IntDev::init()
{
- if (!intPort.isConnected()) {
+ if (!intMasterPort.isConnected()) {
panic("Int port not connected to anything!");
}
- intPort.sendRangeChange();
}
X86ISA::IntSourcePin *
/*
+ * 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.
*
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)
{
}
{
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)
{
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)
{
}
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;
/*
- * 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
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),
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)
{
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()
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()
{
/*
- * 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
* 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:
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();
* responses. The master port has a buffer for the requests not
* yet sent.
*/
- class BridgeMasterPort : public Port
+ class BridgeMasterPort : public MasterPort
{
private:
/** 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. */
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();
*
* Authors: Ali Saidi
* Andreas Hansson
+ * William Wang
*/
/**
// 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;
}
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;
// 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);
+ }
}
}
}
// 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.
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
// 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
// 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
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
// 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
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
// 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);
}
}
}
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",
}
} 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();
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",
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());
}
}
}
// 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);
}
bool
-Bus::isSnooping(int id)
+Bus::isSnooping(int id) const
{
// in essence, answer the question if there are snooping ports
return !snoopPorts.empty();
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;
}
* Authors: Ron Dreslinski
* Ali Saidi
* Andreas Hansson
+ * William Wang
*/
/**
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 interface ID of this port. */
+ int id;
+
+ public:
+
+ /** 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 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 BusMasterPort.*/
+ BusMasterPort(const std::string &_name, Bus *_bus, int _id)
+ : MasterPort(_name, _bus), bus(_bus), id(_id)
{ }
int getId() const { return id; }
*
* @return a boolean that is true if this port is snooping
*/
- virtual bool isSnooping()
+ virtual bool isSnooping() const
{ return bus->isSnooping(id); }
protected:
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.
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.*/
*
* @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.
// 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.*/
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();
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)
{
}
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);
}
}
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()
* 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:
CacheMasterPort(const std::string &_name, BaseCache *_cache,
PacketQueue &_queue) :
- QueuedPort(_name, _cache, _queue)
+ QueuedMasterPort(_name, _cache, _queue)
{ }
/**
*
* @return always true
*/
- virtual bool isSnooping() { return true; }
+ virtual bool isSnooping() const { return true; }
};
/**
* incoming requests. If blocked, the port will issue a retry once
* unblocked.
*/
- class CacheSlavePort : public QueuedPort
+ class CacheSlavePort : public QueuedSlavePort
{
public:
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
#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
/** Instantiates a basic cache object. */
Cache(const Params *p, TagStore *tags);
- virtual Port *getPort(const std::string &if_name, int idx = -1);
-
void 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)
// 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);
{
}
-FSTranslatingPortProxy::FSTranslatingPortProxy(Port &port)
+FSTranslatingPortProxy::FSTranslatingPortProxy(MasterPort &port)
: PortProxy(port), _tc(NULL)
{
}
FSTranslatingPortProxy(ThreadContext* tc);
- FSTranslatingPortProxy(Port &port);
+ FSTranslatingPortProxy(MasterPort &port);
virtual ~FSTranslatingPortProxy();
/*
+ * 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.
*
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Steve Reinhardt
+ * Andreas Hansson
*/
#include "mem/mem_object.hh"
: 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);
+}
/*
+ * 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.
*
* 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__
#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
{
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__
#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());
}
}
/*
+ * 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.
*
* 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:
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)
}
-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,
: 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()
{
virtual void recvFunctional(PacketPtr pkt);
- virtual void recvRangeChange();
-
virtual AddrRangeList getAddrRanges();
virtual unsigned deviceBlockSize() const;
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);
/*
+ * 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.
*
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Steve Reinhardt
+ * Andreas Hansson
+ * William Wang
*/
/**
* 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)
{
}
{
}
-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()
+{
}
-void
-Port::setOwner(MemObject *_owner)
+SlavePort&
+MasterPort::getSlavePort() const
{
- owner = _owner;
+ if(_slavePort == NULL)
+ panic("Cannot getSlavePort on master port %s that is not connected\n",
+ name());
+
+ return *_slavePort;
}
void
-Port::printAddr(Addr a)
+MasterPort::bind(SlavePort& slave_port)
+{
+ // 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);
+}
+
+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);
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;
+}
*
* 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__
#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.
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; }
-
- /** 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; }
+ public:
- bool isConnected() { return peer != NULL; }
+ /** Return port name (for DPRINTF). */
+ const std::string name() const { return portName; }
protected:
/** 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 sendTiming was unsuccesful, and had to
+ * wait.
+ */
+ virtual void recvRetry() = 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("??"); }
+ public:
- /** 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.
+ /**
+ * 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.
+ *
+ * @param pkt Packet to send.
+ *
+ * @return If the send was succesful or not.
*/
- virtual unsigned deviceBlockSize() const { return 0; }
+ bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); }
- public:
+ /**
+ * Send a retry to a peer port that previously attempted a sendTiming
+ * which was unsuccessful.
+ */
+ void sendRetry() { return peer->recvRetry(); }
/**
- * 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.
+ * Send an atomic packet, where the data is moved and the state
+ * is updated in zero time, without interleaving with other
+ * memory accesses.
*
- * @return a list of ranges responded to
+ * @param pkt Packet to send.
+ *
+ * @return Estimated latency of access.
*/
- virtual AddrRangeList getAddrRanges()
- { AddrRangeList ranges; return ranges; }
+ Tick sendAtomic(PacketPtr pkt) { return peer->recvAtomic(pkt); }
/**
- * 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.
+ * 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.
*
- * @return true if the port should be considered a snooper
+ * @param pkt Packet to send.
*/
- 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.
- */
- bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); }
+ void sendFunctional(PacketPtr pkt) { return peer->recvFunctional(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.
- */
- 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); }
+/** 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 by the associated device to send a status range to the
- * peer interface.
+ * 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.
*/
- void sendRangeChange() const { peer->recvRangeChange(); }
+ virtual void recvRangeChange() { }
- /** When a timing access doesn't return a success, some time later the
- Retry will be sent.
- */
- void sendRetry() { return peer->recvRetry(); }
+ /**
+ * 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.
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__
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() { }
/**
* queue is a parameter to allow tailoring of the queue implementation
* (used in the cache).
*/
-class QueuedPort : public Port
+class QueuedSlavePort : public SlavePort
{
protected:
* 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:
* 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. */
/*
+ * 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.
#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;
-
- 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;
+ // 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));
+ }
- 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
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);
+ }
- if (if_name == "physMemPort") {
- return &physMemPort;
+ return *slave_ports[idx];
}
-
- 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
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);
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++) {
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);
+ }
}
}
/*
+ * 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.
class RubyPort : public MemObject
{
public:
- class M5Port : public QueuedPort
+ class M5Port : public QueuedSlavePort
{
private:
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
+ virtual AddrRangeList getAddrRanges();
private:
bool isPhysMemAddress(Addr addr);
friend class M5Port;
- class PioPort : public QueuedPort
+ class PioPort : public QueuedMasterPort
{
private:
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;
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;
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)
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;
SimpleTimingPort::SimpleTimingPort(const std::string& _name,
MemObject* _owner) :
- QueuedPort(_name, _owner, queue), queue(*_owner, *this)
+ QueuedSlavePort(_name, _owner, queue), queue(*_owner, *this)
{
}
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
* recvFunctional and recvTiming through recvAtomic. It is always a
* slave port.
*/
-class SimpleTimingPort : public QueuedPort
+class SimpleTimingPort : public QueuedSlavePort
{
protected:
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)
{
/**
* 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,
}
}
}
- 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;
}
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
* 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:
* 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;
*
* @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];
#include "sim/sim_object.hh"
class ThreadContext;
-class Packet;
-class Port;
+class MasterPort;
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
{