mem: Fix guest corruption when caches handle uncacheable accesses
[gem5.git] / src / mem / port.cc
index 3305541c72b5e2b00698f6b859e6c917dd768d68..45045f40eaadbe9af022e10ece24c2ddcad90804 100644 (file)
@@ -50,8 +50,8 @@
 #include "mem/mem_object.hh"
 #include "mem/port.hh"
 
-Port::Port(const std::string &_name, MemObject& _owner)
-    : portName(_name), peer(NULL), owner(_owner)
+Port::Port(const std::string &_name, MemObject& _owner, PortID _id)
+    : portName(_name), id(_id), owner(_owner)
 {
 }
 
@@ -59,11 +59,63 @@ Port::~Port()
 {
 }
 
+BaseMasterPort::BaseMasterPort(const std::string& name, MemObject* owner,
+                               PortID _id)
+    : Port(name, *owner, _id), _baseSlavePort(NULL)
+{
+}
+
+BaseMasterPort::~BaseMasterPort()
+{
+}
+
+BaseSlavePort&
+BaseMasterPort::getSlavePort() const
+{
+    if(_baseSlavePort == NULL)
+        panic("Cannot getSlavePort on master port %s that is not connected\n",
+              name());
+
+    return *_baseSlavePort;
+}
+
+bool
+BaseMasterPort::isConnected() const
+{
+    return _baseSlavePort != NULL;
+}
+
+BaseSlavePort::BaseSlavePort(const std::string& name, MemObject* owner,
+                             PortID _id)
+    : Port(name, *owner, _id), _baseMasterPort(NULL)
+{
+}
+
+BaseSlavePort::~BaseSlavePort()
+{
+}
+
+BaseMasterPort&
+BaseSlavePort::getMasterPort() const
+{
+    if(_baseMasterPort == NULL)
+        panic("Cannot getMasterPort on slave port %s that is not connected\n",
+              name());
+
+    return *_baseMasterPort;
+}
+
+bool
+BaseSlavePort::isConnected() const
+{
+    return _baseMasterPort != NULL;
+}
+
 /**
  * Master port
  */
-MasterPort::MasterPort(const std::string& name, MemObject* owner)
-    : Port(name, *owner), _slavePort(NULL)
+MasterPort::MasterPort(const std::string& name, MemObject* owner, PortID _id)
+    : BaseMasterPort(name, owner, _id), _slavePort(NULL)
 {
 }
 
@@ -71,44 +123,89 @@ MasterPort::~MasterPort()
 {
 }
 
-SlavePort&
-MasterPort::getSlavePort() const
+void
+MasterPort::bind(BaseSlavePort& slave_port)
 {
-    if(_slavePort == NULL)
-        panic("Cannot getSlavePort on master port %s that is not connected\n",
+    // bind on the level of the base ports
+    _baseSlavePort = &slave_port;
+
+    // also attempt to base the slave to the appropriate type
+    SlavePort* cast_slave_port = dynamic_cast<SlavePort*>(&slave_port);
+
+    // if this port is compatible, then proceed with the binding
+    if (cast_slave_port != NULL) {
+        // master port keeps track of the slave port
+        _slavePort = cast_slave_port;
+        // slave port also keeps track of master port
+        _slavePort->bind(*this);
+    } else {
+        fatal("Master port %s cannot bind to %s\n", name(),
+              slave_port.name());
+    }
+}
+
+void
+MasterPort::unbind()
+{
+    if (_slavePort == NULL)
+        panic("Attempting to unbind master port %s that is not connected\n",
               name());
+    _slavePort->unbind();
+    _slavePort = NULL;
+    _baseSlavePort = NULL;
+}
 
-    return *_slavePort;
+unsigned
+MasterPort::peerBlockSize() const
+{
+    return _slavePort->deviceBlockSize();
+}
+
+AddrRangeList
+MasterPort::getAddrRanges() const
+{
+    return _slavePort->getAddrRanges();
+}
+
+Tick
+MasterPort::sendAtomic(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    return _slavePort->recvAtomic(pkt);
 }
 
 void
-MasterPort::bind(SlavePort& slave_port)
+MasterPort::sendFunctional(PacketPtr pkt)
 {
-    // master port keeps track of the slave port
-    _slavePort = &slave_port;
-    peer = &slave_port;
+    assert(pkt->isRequest());
+    return _slavePort->recvFunctional(pkt);
+}
 
-    // slave port also keeps track of master port
-    _slavePort->bind(*this);
+bool
+MasterPort::sendTimingReq(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    return _slavePort->recvTimingReq(pkt);
 }
 
 bool
-MasterPort::isConnected() const
+MasterPort::sendTimingSnoopResp(PacketPtr pkt)
 {
-    return _slavePort != NULL;
+    assert(pkt->isResponse());
+    return _slavePort->recvTimingSnoopResp(pkt);
 }
 
-unsigned
-MasterPort::peerBlockSize() const
+void
+MasterPort::sendRetry()
 {
-    return _slavePort->deviceBlockSize();
+    _slavePort->recvRetry();
 }
 
- void
+void
 MasterPort::printAddr(Addr a)
 {
     Request req(a, 1, 0, Request::funcMasterId);
-    Packet pkt(&req, MemCmd::PrintReq, Packet::Broadcast);
+    Packet pkt(&req, MemCmd::PrintReq);
     Packet::PrintReqState prs(std::cerr);
     pkt.senderState = &prs;
 
@@ -118,8 +215,8 @@ MasterPort::printAddr(Addr a)
 /**
  * Slave port
  */
-SlavePort::SlavePort(const std::string& name, MemObject* owner)
-    : Port(name, *owner), _masterPort(NULL)
+SlavePort::SlavePort(const std::string& name, MemObject* owner, PortID id)
+    : BaseSlavePort(name, owner, id), _masterPort(NULL)
 {
 }
 
@@ -128,20 +225,17 @@ SlavePort::~SlavePort()
 }
 
 void
-SlavePort::bind(MasterPort& master_port)
+SlavePort::unbind()
 {
-    _masterPort = &master_port;
-    peer = &master_port;
+    _baseMasterPort = NULL;
+    _masterPort = NULL;
 }
 
-MasterPort&
-SlavePort::getMasterPort() const
+void
+SlavePort::bind(MasterPort& master_port)
 {
-    if (_masterPort == NULL)
-        panic("Cannot getMasterPort on slave port %s that is not connected\n",
-              name());
-
-    return *_masterPort;
+    _baseMasterPort = &master_port;
+    _masterPort = &master_port;
 }
 
 unsigned
@@ -150,8 +244,36 @@ SlavePort::peerBlockSize() const
     return _masterPort->deviceBlockSize();
 }
 
+Tick
+SlavePort::sendAtomicSnoop(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    return _masterPort->recvAtomicSnoop(pkt);
+}
+
+void
+SlavePort::sendFunctionalSnoop(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    return _masterPort->recvFunctionalSnoop(pkt);
+}
+
 bool
-SlavePort::isConnected() const
+SlavePort::sendTimingResp(PacketPtr pkt)
+{
+    assert(pkt->isResponse());
+    return _masterPort->recvTimingResp(pkt);
+}
+
+void
+SlavePort::sendTimingSnoopReq(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    _masterPort->recvTimingSnoopReq(pkt);
+}
+
+void
+SlavePort::sendRetry()
 {
-    return _masterPort != NULL;
+    _masterPort->recvRetry();
 }