Generate more useful error messages for unconnected ports.
Force all non-default ports to provide a name and an owner in the constructor.
This commit is contained in:
parent
c1584e4227
commit
6b45238316
17 changed files with 87 additions and 57 deletions
|
@ -80,8 +80,8 @@ class DefaultFetch
|
|||
|
||||
public:
|
||||
/** Default constructor. */
|
||||
IcachePort(DefaultFetch<Impl> *_fetch)
|
||||
: Port(_fetch->name() + "-iport"), fetch(_fetch)
|
||||
IcachePort(DefaultFetch<Impl> *_fetch, O3CPU *_cpu)
|
||||
: Port(_fetch->name() + "-iport", _cpu), fetch(_fetch)
|
||||
{ }
|
||||
|
||||
bool snoopRangeSent;
|
||||
|
|
|
@ -167,7 +167,7 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
|
|||
instSize = sizeof(TheISA::MachInst);
|
||||
|
||||
// Name is finally available, so create the port.
|
||||
icachePort = new IcachePort(this);
|
||||
icachePort = new IcachePort(this, cpu);
|
||||
|
||||
icachePort->snoopRangeSent = false;
|
||||
|
||||
|
|
|
@ -296,8 +296,8 @@ class LSQ {
|
|||
|
||||
public:
|
||||
/** Default constructor. */
|
||||
DcachePort(LSQ *_lsq)
|
||||
: Port(_lsq->name() + "-dport"), lsq(_lsq)
|
||||
DcachePort(LSQ *_lsq, O3CPU *_cpu)
|
||||
: Port(_lsq->name() + "-dport", _cpu), lsq(_lsq)
|
||||
{ }
|
||||
|
||||
bool snoopRangeSent;
|
||||
|
|
|
@ -112,7 +112,7 @@ LSQ<Impl>::DcachePort::recvRetry()
|
|||
|
||||
template <class Impl>
|
||||
LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params)
|
||||
: cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this),
|
||||
: cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this, cpu_ptr),
|
||||
LQEntries(params->LQEntries),
|
||||
SQEntries(params->SQEntries),
|
||||
numThreads(params->numberOfThreads),
|
||||
|
|
|
@ -103,7 +103,6 @@ void
|
|||
O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp)
|
||||
{
|
||||
if (vp != thread->getVirtPort()) {
|
||||
vp->removeConn();
|
||||
delete vp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -747,7 +747,6 @@ template <class Impl>
|
|||
void
|
||||
OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp)
|
||||
{
|
||||
vp->removeConn();
|
||||
delete vp;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -302,7 +302,6 @@ void
|
|||
SimpleThread::delVirtPort(VirtualPort *vp)
|
||||
{
|
||||
if (vp != virtPort) {
|
||||
vp->removeConn();
|
||||
delete vp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ ThreadState::connectPhysPort()
|
|||
// already existed. Fix this memory leak once the bus port IDs
|
||||
// for functional ports is resolved.
|
||||
if (physPort)
|
||||
physPort->removeConn();
|
||||
physPort->disconnectFromPeer();
|
||||
else
|
||||
physPort = new FunctionalPort(csprintf("%s-%d-funcport",
|
||||
baseCpu->name(), tid));
|
||||
|
@ -140,7 +140,7 @@ ThreadState::connectVirtPort()
|
|||
// already existed. Fix this memory leak once the bus port IDs
|
||||
// for functional ports is resolved.
|
||||
if (virtPort)
|
||||
virtPort->removeConn();
|
||||
virtPort->disconnectFromPeer();
|
||||
else
|
||||
virtPort = new VirtualPort(csprintf("%s-%d-vport",
|
||||
baseCpu->name(), tid));
|
||||
|
|
|
@ -47,7 +47,7 @@ Bridge::BridgePort::BridgePort(const std::string &_name,
|
|||
int _delay, int _nack_delay, int _req_limit,
|
||||
int _resp_limit,
|
||||
std::vector<Range<Addr> > filter_ranges)
|
||||
: Port(_name), bridge(_bridge), otherPort(_otherPort),
|
||||
: Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort),
|
||||
delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
|
||||
outstandingResponses(0), queuedRequests(0), inRetry(false),
|
||||
reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
|
||||
|
|
|
@ -72,8 +72,8 @@ Bus::getPort(const std::string &if_name, int idx)
|
|||
return bp;
|
||||
}
|
||||
|
||||
void
|
||||
Bus::deletePortRefs(Port *p)
|
||||
bool
|
||||
Bus::deletePort(Port *p)
|
||||
{
|
||||
|
||||
BusPort *bp = dynamic_cast<BusPort*>(p);
|
||||
|
@ -81,10 +81,11 @@ Bus::deletePortRefs(Port *p)
|
|||
panic("Couldn't convert Port* to BusPort*\n");
|
||||
// If this is our one functional port
|
||||
if (funcPort == bp)
|
||||
return;
|
||||
return false;
|
||||
interfaces.erase(bp->getId());
|
||||
clearBusCache();
|
||||
delete bp;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get the ranges of anyone other buses that we are connected to. */
|
||||
|
|
|
@ -364,7 +364,7 @@ class Bus : public MemObject
|
|||
|
||||
/** A function used to return the port associated with this bus object. */
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
virtual void deletePortRefs(Port *p);
|
||||
virtual bool deletePort(Port *p);
|
||||
|
||||
virtual void init();
|
||||
virtual void startup();
|
||||
|
|
2
src/mem/cache/cache.hh
vendored
2
src/mem/cache/cache.hh
vendored
|
@ -217,7 +217,7 @@ class Cache : public BaseCache
|
|||
Cache(const Params *p, TagStore *tags, BasePrefetcher *prefetcher);
|
||||
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
virtual void deletePortRefs(Port *p);
|
||||
virtual bool deletePort(Port *p);
|
||||
|
||||
void regStats();
|
||||
|
||||
|
|
5
src/mem/cache/cache_impl.hh
vendored
5
src/mem/cache/cache_impl.hh
vendored
|
@ -105,13 +105,14 @@ Cache<TagStore>::getPort(const std::string &if_name, int idx)
|
|||
}
|
||||
|
||||
template<class TagStore>
|
||||
void
|
||||
Cache<TagStore>::deletePortRefs(Port *p)
|
||||
bool
|
||||
Cache<TagStore>::deletePort(Port *p)
|
||||
{
|
||||
if (cpuSidePort == p || memSidePort == p)
|
||||
panic("Can only delete functional ports\n");
|
||||
|
||||
delete p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ MemObject::makeParams(const std::string &name)
|
|||
return params;
|
||||
}
|
||||
|
||||
void
|
||||
MemObject::deletePortRefs(Port *p)
|
||||
bool
|
||||
MemObject::deletePort(Port *p)
|
||||
{
|
||||
panic("This object does not support port deletion\n");
|
||||
}
|
||||
|
|
|
@ -64,9 +64,13 @@ class MemObject : public SimObject
|
|||
/** Additional function to return the Port of a memory object. */
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1) = 0;
|
||||
|
||||
/** Tell object that this port is about to disappear, so it should remove it
|
||||
* from any structures that it's keeping it in. */
|
||||
virtual void deletePortRefs(Port *p) ;
|
||||
/** Tell MemObject that this port is no longer in use, so it
|
||||
* should remove it from any structures that it's keeping it in.
|
||||
* If the port was allocated dynamically for this connection, it
|
||||
* should be deleted here.
|
||||
* @return True if the port was deleted, false if it still exists.
|
||||
*/
|
||||
virtual bool deletePort(Port *p);
|
||||
};
|
||||
|
||||
#endif //__MEM_MEM_OBJECT_HH__
|
||||
|
|
|
@ -39,17 +39,25 @@
|
|||
#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
|
||||
{
|
||||
protected:
|
||||
void blowUp()
|
||||
{
|
||||
fatal("%s: Unconnected port!", peer->name());
|
||||
Port *peer = getPeer();
|
||||
fatal("unconnected port: %s", peer ? peer->name() : "<unknown>");
|
||||
}
|
||||
|
||||
public:
|
||||
DefaultPeerPort()
|
||||
: Port("default_port")
|
||||
DefaultPeerPort(Port *_peer)
|
||||
: Port("default_port", NULL, _peer)
|
||||
{ }
|
||||
|
||||
bool recvTiming(PacketPtr)
|
||||
|
@ -88,38 +96,61 @@ class DefaultPeerPort : public Port
|
|||
bool isDefaultPort() const { return true; }
|
||||
};
|
||||
|
||||
DefaultPeerPort defaultPeerPort;
|
||||
|
||||
Port::Port()
|
||||
: peer(&defaultPeerPort), owner(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Port::Port(const std::string &_name, MemObject *_owner)
|
||||
: portName(_name), peer(&defaultPeerPort), owner(_owner)
|
||||
Port::Port(const std::string &_name, MemObject *_owner, Port *_peer) :
|
||||
portName(_name),
|
||||
peer(_peer ? _peer : new DefaultPeerPort(this)),
|
||||
owner(_owner)
|
||||
{
|
||||
}
|
||||
|
||||
Port::~Port()
|
||||
{
|
||||
disconnectFromPeer();
|
||||
}
|
||||
|
||||
void
|
||||
Port::disconnectFromPeer()
|
||||
{
|
||||
if (peer) {
|
||||
assert(peer->getPeer() == this);
|
||||
peer->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
Port::setPeer(Port *port)
|
||||
{
|
||||
DPRINTF(Config, "setting peer to %s\n", port->name());
|
||||
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();
|
||||
|
||||
peer = port;
|
||||
}
|
||||
|
||||
void
|
||||
Port::removeConn()
|
||||
{
|
||||
if (peer->getOwner())
|
||||
peer->getOwner()->deletePortRefs(peer);
|
||||
peer = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd)
|
||||
{
|
||||
|
|
|
@ -87,17 +87,14 @@ class Port
|
|||
|
||||
public:
|
||||
|
||||
Port();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
Port(const std::string &_name, MemObject *_owner = NULL);
|
||||
Port(const std::string &_name, MemObject *_owner, Port *_peer = NULL);
|
||||
|
||||
/** Return port name (for DPRINTF). */
|
||||
const std::string &name() const { return portName; }
|
||||
|
@ -111,24 +108,18 @@ class Port
|
|||
RangeChange
|
||||
};
|
||||
|
||||
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) { owner = _owner; }
|
||||
|
||||
/** Function to return the owner of this port. */
|
||||
MemObject *getOwner() { return owner; }
|
||||
|
||||
/** Inform the peer port to delete itself and notify it's owner about it's
|
||||
* demise. */
|
||||
void removeConn();
|
||||
/** Notify my peer port that I'm disconnecting (by calling its
|
||||
* disconnect() method) so it can clean up. */
|
||||
void disconnectFromPeer();
|
||||
|
||||
virtual bool isDefaultPort() const { return false; }
|
||||
|
||||
|
@ -254,6 +245,11 @@ class Port
|
|||
/** Internal helper function for read/writeBlob().
|
||||
*/
|
||||
void blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd);
|
||||
|
||||
/** Receive notification that my peer is disconnecting and clean
|
||||
* up (potentially deleting myself in the process). Should be
|
||||
* called only from peer's disconnectFromPeer(). */
|
||||
void disconnect();
|
||||
};
|
||||
|
||||
/** A simple functional port that is only meant for one way communication to
|
||||
|
|
Loading…
Reference in a new issue