/*
+ * 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.
*
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Steve Reinhardt
*/
/**
* @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"
+#include "sim/sim_object.hh"
-void
-Port::setPeer(Port *port)
+namespace
+{
+
+class DefaultRequestPort : public RequestPort
+{
+ protected:
+ [[noreturn]] void
+ blowUp() const
+ {
+ throw UnboundPortException();
+ }
+
+ public:
+ DefaultRequestPort() : RequestPort("default_request_port", nullptr) {}
+
+ // Atomic protocol.
+ Tick recvAtomicSnoop(PacketPtr) override { blowUp(); }
+
+ // Timing protocol.
+ bool recvTimingResp(PacketPtr) override { blowUp(); }
+ void recvTimingSnoopReq(PacketPtr) override { blowUp(); }
+ void recvReqRetry() override { blowUp(); }
+ void recvRetrySnoopResp() override { blowUp(); }
+
+ // Functional protocol.
+ void recvFunctionalSnoop(PacketPtr) override { blowUp(); }
+};
+
+class DefaultResponsePort : public ResponsePort
+{
+ protected:
+ [[noreturn]] void
+ blowUp() const
+ {
+ throw UnboundPortException();
+ }
+
+ public:
+ DefaultResponsePort() : ResponsePort("default_response_port", nullptr) {}
+
+ // Atomic protocol.
+ Tick recvAtomic(PacketPtr) override { blowUp(); }
+
+ // Timing protocol.
+ bool recvTimingReq(PacketPtr) override { blowUp(); }
+ bool tryTiming(PacketPtr) override { blowUp(); }
+ bool recvTimingSnoopResp(PacketPtr) override { blowUp(); }
+ void recvRespRetry() override { blowUp(); }
+
+ // Functional protocol.
+ void recvFunctional(PacketPtr) override { blowUp(); }
+
+ // General.
+ AddrRangeList getAddrRanges() const override { return AddrRangeList(); }
+};
+
+DefaultRequestPort defaultRequestPort;
+DefaultResponsePort defaultResponsePort;
+
+} // anonymous namespace
+
+/**
+ * Request port
+ */
+RequestPort::RequestPort(const std::string& name, SimObject* _owner,
+ PortID _id) : Port(name, _id), _responsePort(&defaultResponsePort),
+ owner(*_owner)
{
- DPRINTF(Config, "setting peer to %s\n", port->name());
- peer = port;
}
-void
-Port::removeConn()
+RequestPort::~RequestPort()
{
- if (peer->getOwner())
- peer->getOwner()->deletePortRefs(peer);
- peer = NULL;
}
void
-Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd)
+RequestPort::bind(Port &peer)
{
- 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();
- }
+ auto *response_port = dynamic_cast<ResponsePort *>(&peer);
+ fatal_if(!response_port, "Can't bind port %s to non-response port %s.",
+ name(), peer.name());
+ // request port keeps track of the response port
+ _responsePort = response_port;
+ Port::bind(peer);
+ // response port also keeps track of request port
+ _responsePort->responderBind(*this);
}
void
-Port::writeBlob(Addr addr, uint8_t *p, int size)
+RequestPort::unbind()
+{
+ panic_if(!isConnected(), "Can't unbind request port %s which is "
+ "not bound.", name());
+ _responsePort->responderUnbind();
+ _responsePort = &defaultResponsePort;
+ Port::unbind();
+}
+
+AddrRangeList
+RequestPort::getAddrRanges() const
{
- blobHelper(addr, p, size, MemCmd::WriteReq);
+ return _responsePort->getAddrRanges();
}
void
-Port::readBlob(Addr addr, uint8_t *p, int size)
+RequestPort::printAddr(Addr a)
+{
+ auto req = std::make_shared<Request>(
+ a, 1, 0, Request::funcRequestorId);
+
+ Packet pkt(req, MemCmd::PrintReq);
+ Packet::PrintReqState prs(std::cerr);
+ pkt.senderState = &prs;
+
+ sendFunctional(&pkt);
+}
+
+/**
+ * Response port
+ */
+ResponsePort::ResponsePort(const std::string& name, SimObject* _owner,
+ PortID id) : Port(name, id), _requestPort(&defaultRequestPort),
+ defaultBackdoorWarned(false), owner(*_owner)
+{
+}
+
+ResponsePort::~ResponsePort()
{
- blobHelper(addr, p, size, MemCmd::ReadReq);
}
void
-Port::memsetBlob(Addr addr, uint8_t val, int size)
+ResponsePort::responderUnbind()
{
- // quick and dirty...
- uint8_t *buf = new uint8_t[size];
+ _requestPort = &defaultRequestPort;
+ Port::unbind();
+}
- std::memset(buf, val, size);
- blobHelper(addr, buf, size, MemCmd::WriteReq);
+void
+ResponsePort::responderBind(RequestPort& request_port)
+{
+ _requestPort = &request_port;
+ Port::bind(request_port);
+}
- delete [] buf;
+Tick
+ResponsePort::recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor)
+{
+ if (!defaultBackdoorWarned) {
+ warn("Port %s doesn't support requesting a back door.", name());
+ defaultBackdoorWarned = true;
+ }
+ return recvAtomic(pkt);
}