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:
Steve Reinhardt 2008-06-21 01:04:43 -04:00
parent c1584e4227
commit 6b45238316
17 changed files with 87 additions and 57 deletions

View file

@ -80,8 +80,8 @@ class DefaultFetch
public: public:
/** Default constructor. */ /** Default constructor. */
IcachePort(DefaultFetch<Impl> *_fetch) IcachePort(DefaultFetch<Impl> *_fetch, O3CPU *_cpu)
: Port(_fetch->name() + "-iport"), fetch(_fetch) : Port(_fetch->name() + "-iport", _cpu), fetch(_fetch)
{ } { }
bool snoopRangeSent; bool snoopRangeSent;

View file

@ -167,7 +167,7 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
instSize = sizeof(TheISA::MachInst); instSize = sizeof(TheISA::MachInst);
// Name is finally available, so create the port. // Name is finally available, so create the port.
icachePort = new IcachePort(this); icachePort = new IcachePort(this, cpu);
icachePort->snoopRangeSent = false; icachePort->snoopRangeSent = false;

View file

@ -296,8 +296,8 @@ class LSQ {
public: public:
/** Default constructor. */ /** Default constructor. */
DcachePort(LSQ *_lsq) DcachePort(LSQ *_lsq, O3CPU *_cpu)
: Port(_lsq->name() + "-dport"), lsq(_lsq) : Port(_lsq->name() + "-dport", _cpu), lsq(_lsq)
{ } { }
bool snoopRangeSent; bool snoopRangeSent;

View file

@ -112,7 +112,7 @@ LSQ<Impl>::DcachePort::recvRetry()
template <class Impl> template <class Impl>
LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) 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), LQEntries(params->LQEntries),
SQEntries(params->SQEntries), SQEntries(params->SQEntries),
numThreads(params->numberOfThreads), numThreads(params->numberOfThreads),

View file

@ -103,7 +103,6 @@ void
O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp) O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp)
{ {
if (vp != thread->getVirtPort()) { if (vp != thread->getVirtPort()) {
vp->removeConn();
delete vp; delete vp;
} }
} }

View file

@ -747,7 +747,6 @@ template <class Impl>
void void
OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp) OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp)
{ {
vp->removeConn();
delete vp; delete vp;
} }
#endif #endif

View file

@ -302,7 +302,6 @@ void
SimpleThread::delVirtPort(VirtualPort *vp) SimpleThread::delVirtPort(VirtualPort *vp)
{ {
if (vp != virtPort) { if (vp != virtPort) {
vp->removeConn();
delete vp; delete vp;
} }
} }

View file

@ -126,7 +126,7 @@ ThreadState::connectPhysPort()
// already existed. Fix this memory leak once the bus port IDs // already existed. Fix this memory leak once the bus port IDs
// for functional ports is resolved. // for functional ports is resolved.
if (physPort) if (physPort)
physPort->removeConn(); physPort->disconnectFromPeer();
else else
physPort = new FunctionalPort(csprintf("%s-%d-funcport", physPort = new FunctionalPort(csprintf("%s-%d-funcport",
baseCpu->name(), tid)); baseCpu->name(), tid));
@ -140,7 +140,7 @@ ThreadState::connectVirtPort()
// already existed. Fix this memory leak once the bus port IDs // already existed. Fix this memory leak once the bus port IDs
// for functional ports is resolved. // for functional ports is resolved.
if (virtPort) if (virtPort)
virtPort->removeConn(); virtPort->disconnectFromPeer();
else else
virtPort = new VirtualPort(csprintf("%s-%d-vport", virtPort = new VirtualPort(csprintf("%s-%d-vport",
baseCpu->name(), tid)); baseCpu->name(), tid));

View file

@ -47,7 +47,7 @@ Bridge::BridgePort::BridgePort(const std::string &_name,
int _delay, int _nack_delay, int _req_limit, int _delay, int _nack_delay, int _req_limit,
int _resp_limit, int _resp_limit,
std::vector<Range<Addr> > filter_ranges) 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), delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
outstandingResponses(0), queuedRequests(0), inRetry(false), outstandingResponses(0), queuedRequests(0), inRetry(false),
reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)

View file

@ -72,8 +72,8 @@ Bus::getPort(const std::string &if_name, int idx)
return bp; return bp;
} }
void bool
Bus::deletePortRefs(Port *p) Bus::deletePort(Port *p)
{ {
BusPort *bp = dynamic_cast<BusPort*>(p); BusPort *bp = dynamic_cast<BusPort*>(p);
@ -81,10 +81,11 @@ Bus::deletePortRefs(Port *p)
panic("Couldn't convert Port* to BusPort*\n"); panic("Couldn't convert Port* to BusPort*\n");
// If this is our one functional port // If this is our one functional port
if (funcPort == bp) if (funcPort == bp)
return; return false;
interfaces.erase(bp->getId()); interfaces.erase(bp->getId());
clearBusCache(); clearBusCache();
delete bp; delete bp;
return true;
} }
/** Get the ranges of anyone other buses that we are connected to. */ /** Get the ranges of anyone other buses that we are connected to. */

View file

@ -364,7 +364,7 @@ class Bus : public MemObject
/** A function used to return the port associated with this bus object. */ /** A function used to return the port associated with this bus object. */
virtual Port *getPort(const std::string &if_name, int idx = -1); 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 init();
virtual void startup(); virtual void startup();

View file

@ -217,7 +217,7 @@ class Cache : public BaseCache
Cache(const Params *p, TagStore *tags, BasePrefetcher *prefetcher); Cache(const Params *p, TagStore *tags, BasePrefetcher *prefetcher);
virtual Port *getPort(const std::string &if_name, int idx = -1); virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void deletePortRefs(Port *p); virtual bool deletePort(Port *p);
void regStats(); void regStats();

View file

@ -105,13 +105,14 @@ Cache<TagStore>::getPort(const std::string &if_name, int idx)
} }
template<class TagStore> template<class TagStore>
void bool
Cache<TagStore>::deletePortRefs(Port *p) Cache<TagStore>::deletePort(Port *p)
{ {
if (cpuSidePort == p || memSidePort == p) if (cpuSidePort == p || memSidePort == p)
panic("Can only delete functional ports\n"); panic("Can only delete functional ports\n");
delete p; delete p;
return true;
} }

View file

@ -43,8 +43,8 @@ MemObject::makeParams(const std::string &name)
return params; return params;
} }
void bool
MemObject::deletePortRefs(Port *p) MemObject::deletePort(Port *p)
{ {
panic("This object does not support port deletion\n"); panic("This object does not support port deletion\n");
} }

View file

@ -64,9 +64,13 @@ class MemObject : public SimObject
/** Additional function to return the Port of a memory object. */ /** Additional function to return the Port of a memory object. */
virtual Port *getPort(const std::string &if_name, int idx = -1) = 0; 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 /** Tell MemObject that this port is no longer in use, so it
* from any structures that it's keeping it in. */ * should remove it from any structures that it's keeping it in.
virtual void deletePortRefs(Port *p) ; * 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__ #endif //__MEM_MEM_OBJECT_HH__

View file

@ -39,17 +39,25 @@
#include "mem/mem_object.hh" #include "mem/mem_object.hh"
#include "mem/port.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 class DefaultPeerPort : public Port
{ {
protected: protected:
void blowUp() void blowUp()
{ {
fatal("%s: Unconnected port!", peer->name()); Port *peer = getPeer();
fatal("unconnected port: %s", peer ? peer->name() : "<unknown>");
} }
public: public:
DefaultPeerPort() DefaultPeerPort(Port *_peer)
: Port("default_port") : Port("default_port", NULL, _peer)
{ } { }
bool recvTiming(PacketPtr) bool recvTiming(PacketPtr)
@ -88,38 +96,61 @@ class DefaultPeerPort : public Port
bool isDefaultPort() const { return true; } bool isDefaultPort() const { return true; }
}; };
DefaultPeerPort defaultPeerPort;
Port::Port() Port::Port(const std::string &_name, MemObject *_owner, Port *_peer) :
: peer(&defaultPeerPort), owner(NULL) portName(_name),
{ peer(_peer ? _peer : new DefaultPeerPort(this)),
} owner(_owner)
Port::Port(const std::string &_name, MemObject *_owner)
: portName(_name), peer(&defaultPeerPort), owner(_owner)
{ {
} }
Port::~Port() 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 void
Port::setPeer(Port *port) 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; peer = port;
} }
void
Port::removeConn()
{
if (peer->getOwner())
peer->getOwner()->deletePortRefs(peer);
peer = NULL;
}
void void
Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd) Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd)
{ {

View file

@ -87,17 +87,14 @@ class Port
public: public:
Port();
/** /**
* Constructor. * Constructor.
* *
* @param _name Port name for DPRINTF output. Should include name * @param _name Port name for DPRINTF output. Should include name
* of memory system object to which the port belongs. * of memory system object to which the port belongs.
* @param _owner Pointer to the MemObject that owns this port. * @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). */ /** Return port name (for DPRINTF). */
const std::string &name() const { return portName; } const std::string &name() const { return portName; }
@ -111,24 +108,18 @@ class Port
RangeChange RangeChange
}; };
void setName(const std::string &name)
{ portName = name; }
/** Function to set the pointer for the peer port. */ /** Function to set the pointer for the peer port. */
virtual void setPeer(Port *port); virtual void setPeer(Port *port);
/** Function to get the pointer to the peer port. */ /** Function to get the pointer to the peer port. */
Port *getPeer() { return peer; } 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. */ /** Function to return the owner of this port. */
MemObject *getOwner() { return owner; } MemObject *getOwner() { return owner; }
/** Inform the peer port to delete itself and notify it's owner about it's /** Notify my peer port that I'm disconnecting (by calling its
* demise. */ * disconnect() method) so it can clean up. */
void removeConn(); void disconnectFromPeer();
virtual bool isDefaultPort() const { return false; } virtual bool isDefaultPort() const { return false; }
@ -254,6 +245,11 @@ class Port
/** Internal helper function for read/writeBlob(). /** Internal helper function for read/writeBlob().
*/ */
void blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd); 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 /** A simple functional port that is only meant for one way communication to