/*
+ * Copyright (c) 2012,2015,2017 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
*/
/**
* @file
* Port object definitions.
*/
-#include <cstring>
+#include "mem/port.hh"
-#include "base/chunk_generator.hh"
#include "base/trace.hh"
#include "mem/mem_object.hh"
-#include "mem/port.hh"
-/**
- * Special class for port objects that are used as peers for
- * unconnected ports. Assigning instances of this class to newly
- * allocated ports allows us to guarantee that every port has a peer
- * object (so there's no need to check for null peer pointers), while
- * catching uses of unconnected ports.
- */
-class DefaultPeerPort : public Port
+BaseMasterPort::BaseMasterPort(const std::string &name, PortID _id)
+ : Port(name, _id), _baseSlavePort(NULL)
{
- protected:
- void blowUp()
- {
- Port *peer = getPeer();
- fatal("unconnected port: %s", peer ? peer->name() : "<unknown>");
- }
+}
- public:
- DefaultPeerPort(Port *_peer)
- : Port("default_port", NULL, _peer)
- { }
+BaseMasterPort::~BaseMasterPort()
+{
+}
- bool recvTiming(PacketPtr)
- {
- blowUp();
- return false;
- }
+BaseSlavePort&
+BaseMasterPort::getSlavePort() const
+{
+ if (_baseSlavePort == NULL)
+ panic("Cannot getSlavePort on master port %s that is not connected\n",
+ name());
- Tick recvAtomic(PacketPtr)
- {
- blowUp();
- return 0;
- }
+ return *_baseSlavePort;
+}
- void recvFunctional(PacketPtr)
- {
- blowUp();
- }
+BaseSlavePort::BaseSlavePort(const std::string &name, PortID _id)
+ : Port(name, _id), _baseMasterPort(NULL)
+{
+}
- void recvStatusChange(Status)
- {
- blowUp();
- }
+BaseSlavePort::~BaseSlavePort()
+{
+}
- int deviceBlockSize()
- {
- blowUp();
- return 0;
- }
+BaseMasterPort&
+BaseSlavePort::getMasterPort() const
+{
+ if (_baseMasterPort == NULL)
+ panic("Cannot getMasterPort on slave port %s that is not connected\n",
+ name());
+
+ return *_baseMasterPort;
+}
+
+/**
+ * Master port
+ */
+MasterPort::MasterPort(const std::string& name, MemObject* _owner, PortID _id)
+ : BaseMasterPort(name, _id), _slavePort(NULL), owner(*_owner)
+{
+}
+
+MasterPort::~MasterPort()
+{
+}
- void getDeviceAddressRanges(AddrRangeList &, bool &)
- {
- blowUp();
+void
+MasterPort::bind(Port &peer)
+{
+ auto *slave_port = dynamic_cast<SlavePort *>(&peer);
+ if (!slave_port) {
+ fatal("Attempt to bind port %s to non-slave port %s.",
+ name(), peer.name());
}
+ // bind on the level of the base ports
+ _baseSlavePort = slave_port;
+
+ // master port keeps track of the slave port
+ _slavePort = slave_port;
+ _connected = true;
+ // slave port also keeps track of master port
+ _slavePort->slaveBind(*this);
+}
- bool isDefaultPort() const { return true; }
-};
+void
+MasterPort::unbind()
+{
+ if (_slavePort == NULL)
+ panic("Attempting to unbind master port %s that is not connected\n",
+ name());
+ _slavePort->slaveUnbind();
+ _slavePort = NULL;
+ _connected = false;
+ _baseSlavePort = NULL;
+}
+AddrRangeList
+MasterPort::getAddrRanges() const
+{
+ return _slavePort->getAddrRanges();
+}
-Port::Port(const std::string &_name, MemObject *_owner, Port *_peer) :
- portName(_name),
- peer(_peer ? _peer : new DefaultPeerPort(this)),
- owner(_owner)
+Tick
+MasterPort::sendAtomic(PacketPtr pkt)
{
+ assert(pkt->isRequest());
+ return _slavePort->recvAtomic(pkt);
}
-Port::~Port()
+Tick
+MasterPort::sendAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor)
{
- disconnectFromPeer();
+ assert(pkt->isRequest());
+ return _slavePort->recvAtomicBackdoor(pkt, backdoor);
}
void
-Port::disconnectFromPeer()
+MasterPort::sendFunctional(PacketPtr pkt)
{
- if (peer) {
- assert(peer->getPeer() == this);
- peer->disconnect();
- }
+ assert(pkt->isRequest());
+ return _slavePort->recvFunctional(pkt);
+}
+
+bool
+MasterPort::sendTimingReq(PacketPtr pkt)
+{
+ assert(pkt->isRequest());
+ return _slavePort->recvTimingReq(pkt);
+}
+
+bool
+MasterPort::tryTiming(PacketPtr pkt) const
+{
+ assert(pkt->isRequest());
+ return _slavePort->tryTiming(pkt);
+}
+
+bool
+MasterPort::sendTimingSnoopResp(PacketPtr pkt)
+{
+ assert(pkt->isResponse());
+ return _slavePort->recvTimingSnoopResp(pkt);
}
void
-Port::disconnect()
-{
- // This notification should come only from our peer, so we must
- // have one,
- assert(peer != NULL);
- // We must clear 'peer' here, else if owner->deletePort() calls
- // delete on us then we'll recurse infinitely through the Port
- // destructor.
- peer = NULL;
- // If owner->deletePort() returns true, then we've been deleted,
- // so don't do anything but get out of here. If not, reset peer
- // pointer to a DefaultPeerPort.
- if (!(owner && owner->deletePort(this)))
- peer = new DefaultPeerPort(this);
+MasterPort::sendRetryResp()
+{
+ _slavePort->recvRespRetry();
}
void
-Port::setPeer(Port *port)
+MasterPort::printAddr(Addr a)
{
- DPRINTF(Config, "setting peer to %s, old peer %s\n",
- port->name(), peer ? peer->name() : "<null>");
-
- // You'd think we'd want to disconnect from the previous peer
- // here, but it turns out that with some functional ports the old
- // peer keeps using the connection, and it works because
- // functional ports are unidirectional.
- //
- // disconnectFromPeer();
+ auto req = std::make_shared<Request>(
+ a, 1, 0, Request::funcMasterId);
- peer = port;
+ Packet pkt(req, MemCmd::PrintReq);
+ Packet::PrintReqState prs(std::cerr);
+ pkt.senderState = &prs;
+
+ sendFunctional(&pkt);
}
-void
-Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd)
+/**
+ * Slave port
+ */
+SlavePort::SlavePort(const std::string& name, MemObject* _owner, PortID id)
+ : BaseSlavePort(name, id), _masterPort(NULL), defaultBackdoorWarned(false),
+ owner(*_owner)
{
- Request req;
+}
- for (ChunkGenerator gen(addr, size, peerBlockSize());
- !gen.done(); gen.next()) {
- req.setPhys(gen.addr(), gen.size(), 0);
- Packet pkt(&req, cmd, Packet::Broadcast);
- pkt.dataStatic(p);
- sendFunctional(&pkt);
- p += gen.size();
- }
+SlavePort::~SlavePort()
+{
}
void
-Port::writeBlob(Addr addr, uint8_t *p, int size)
+SlavePort::slaveUnbind()
{
- blobHelper(addr, p, size, MemCmd::WriteReq);
+ _baseMasterPort = NULL;
+ _masterPort = NULL;
+ _connected = false;
}
void
-Port::readBlob(Addr addr, uint8_t *p, int size)
+SlavePort::slaveBind(MasterPort& master_port)
{
- blobHelper(addr, p, size, MemCmd::ReadReq);
+ _baseMasterPort = &master_port;
+ _masterPort = &master_port;
+ _connected = true;
}
-void
-Port::memsetBlob(Addr addr, uint8_t val, int size)
+Tick
+SlavePort::recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor)
+{
+ if (!defaultBackdoorWarned) {
+ warn("Port %s doesn't support requesting a back door.", name());
+ defaultBackdoorWarned = true;
+ }
+ return recvAtomic(pkt);
+}
+
+Tick
+SlavePort::sendAtomicSnoop(PacketPtr pkt)
{
- // quick and dirty...
- uint8_t *buf = new uint8_t[size];
+ assert(pkt->isRequest());
+ return _masterPort->recvAtomicSnoop(pkt);
+}
- std::memset(buf, val, size);
- blobHelper(addr, buf, size, MemCmd::WriteReq);
+void
+SlavePort::sendFunctionalSnoop(PacketPtr pkt)
+{
+ assert(pkt->isRequest());
+ return _masterPort->recvFunctionalSnoop(pkt);
+}
- delete [] buf;
+bool
+SlavePort::sendTimingResp(PacketPtr pkt)
+{
+ assert(pkt->isResponse());
+ return _masterPort->recvTimingResp(pkt);
}
+void
+SlavePort::sendTimingSnoopReq(PacketPtr pkt)
+{
+ assert(pkt->isRequest());
+ _masterPort->recvTimingSnoopReq(pkt);
+}
void
-Port::printAddr(Addr a)
+SlavePort::sendRetryReq()
{
- Request req(a, 1, 0);
- Packet pkt(&req, MemCmd::PrintReq, Packet::Broadcast);
- Packet::PrintReqState prs(std::cerr);
- pkt.senderState = &prs;
+ _masterPort->recvReqRetry();
+}
- sendFunctional(&pkt);
+void
+SlavePort::sendRetrySnoopResp()
+{
+ _masterPort->recvRetrySnoopResp();
}