diff options
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/bridge.cc | 45 | ||||
-rw-r--r-- | src/mem/bridge.hh | 21 | ||||
-rw-r--r-- | src/mem/bus.cc | 117 | ||||
-rw-r--r-- | src/mem/bus.hh | 103 | ||||
-rw-r--r-- | src/mem/cache/base.cc | 25 | ||||
-rw-r--r-- | src/mem/cache/base.hh | 11 | ||||
-rw-r--r-- | src/mem/cache/builder.cc | 1 | ||||
-rw-r--r-- | src/mem/cache/cache.hh | 2 | ||||
-rw-r--r-- | src/mem/cache/cache_impl.hh | 15 | ||||
-rw-r--r-- | src/mem/fs_translating_port_proxy.cc | 2 | ||||
-rw-r--r-- | src/mem/fs_translating_port_proxy.hh | 2 | ||||
-rw-r--r-- | src/mem/mem_object.cc | 25 | ||||
-rw-r--r-- | src/mem/mem_object.hh | 43 | ||||
-rw-r--r-- | src/mem/mport.cc | 17 | ||||
-rw-r--r-- | src/mem/mport.hh | 41 | ||||
-rw-r--r-- | src/mem/physical.cc | 23 | ||||
-rw-r--r-- | src/mem/physical.hh | 4 | ||||
-rw-r--r-- | src/mem/port.cc | 105 | ||||
-rw-r--r-- | src/mem/port.hh | 267 | ||||
-rw-r--r-- | src/mem/port_proxy.hh | 4 | ||||
-rw-r--r-- | src/mem/qport.hh | 50 | ||||
-rw-r--r-- | src/mem/ruby/system/RubyPort.cc | 137 | ||||
-rw-r--r-- | src/mem/ruby/system/RubyPort.hh | 25 | ||||
-rw-r--r-- | src/mem/se_translating_port_proxy.cc | 2 | ||||
-rw-r--r-- | src/mem/se_translating_port_proxy.hh | 2 | ||||
-rw-r--r-- | src/mem/tport.cc | 5 | ||||
-rw-r--r-- | src/mem/tport.hh | 2 |
27 files changed, 749 insertions, 347 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index 0733b6ea8..ebb37e792 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 ARM Limited + * Copyright (c) 2011-2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -59,7 +59,7 @@ Bridge::BridgeSlavePort::BridgeSlavePort(const std::string &_name, int _delay, int _nack_delay, int _resp_limit, std::vector<Range<Addr> > _ranges) - : Port(_name, _bridge), bridge(_bridge), masterPort(_masterPort), + : SlavePort(_name, _bridge), bridge(_bridge), masterPort(_masterPort), delay(_delay), nackDelay(_nack_delay), ranges(_ranges.begin(), _ranges.end()), outstandingResponses(0), inRetry(false), @@ -71,7 +71,7 @@ Bridge::BridgeMasterPort::BridgeMasterPort(const std::string &_name, Bridge* _bridge, BridgeSlavePort& _slavePort, int _delay, int _req_limit) - : Port(_name, _bridge), bridge(_bridge), slavePort(_slavePort), + : MasterPort(_name, _bridge), bridge(_bridge), slavePort(_slavePort), delay(_delay), inRetry(false), reqQueueLimit(_req_limit), sendEvent(*this) { @@ -88,19 +88,25 @@ Bridge::Bridge(Params *p) panic("No support for acknowledging writes\n"); } -Port* -Bridge::getPort(const std::string &if_name, int idx) +MasterPort& +Bridge::getMasterPort(const std::string &if_name, int idx) { - if (if_name == "slave") - return &slavePort; - else if (if_name == "master") - return &masterPort; - else { - panic("Bridge %s has no port named %s\n", name(), if_name); - return NULL; - } + if (if_name == "master") + return masterPort; + else + // pass it along to our super class + return MemObject::getMasterPort(if_name, idx); } +SlavePort& +Bridge::getSlavePort(const std::string &if_name, int idx) +{ + if (if_name == "slave") + return slavePort; + else + // pass it along to our super class + return MemObject::getSlavePort(if_name, idx); +} void Bridge::init() @@ -473,19 +479,6 @@ Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt) return found; } -/** Function called by the port when the bridge is receiving a range change.*/ -void -Bridge::BridgeMasterPort::recvRangeChange() -{ - // no need to forward as the bridge has a fixed set of ranges -} - -void -Bridge::BridgeSlavePort::recvRangeChange() -{ - // is a slave port so do nothing -} - AddrRangeList Bridge::BridgeSlavePort::getAddrRanges() { diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 3e0040514..e7dbc0a28 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 ARM Limited + * Copyright (c) 2011-2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -122,7 +122,7 @@ class Bridge : public MemObject * is responsible for. The slave port also has a buffer for the * responses not yet sent. */ - class BridgeSlavePort : public Port + class BridgeSlavePort : public SlavePort { private: @@ -244,11 +244,6 @@ class Bridge : public MemObject pass it to the bridge. */ virtual void recvFunctional(PacketPtr pkt); - /** - * When receiving a range change on the slave side do nothing. - */ - virtual void recvRangeChange(); - /** When receiving a address range request the peer port, pass it to the bridge. */ virtual AddrRangeList getAddrRanges(); @@ -260,7 +255,7 @@ class Bridge : public MemObject * responses. The master port has a buffer for the requests not * yet sent. */ - class BridgeMasterPort : public Port + class BridgeMasterPort : public MasterPort { private: @@ -371,11 +366,6 @@ class Bridge : public MemObject /** When receiving a Functional request from the peer port, pass it to the bridge. */ virtual void recvFunctional(PacketPtr pkt); - - /** - * When receiving a range change, pass it through the bridge. - */ - virtual void recvRangeChange(); }; /** Slave port of the bridge. */ @@ -396,8 +386,9 @@ class Bridge : public MemObject public: const Params *params() const { return _params; } - /** A function used to return the port associated with this bus object. */ - virtual Port *getPort(const std::string &if_name, int idx = -1); + virtual MasterPort& getMasterPort(const std::string& if_name, + int idx = -1); + virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); virtual void init(); diff --git a/src/mem/bus.cc b/src/mem/bus.cc index 0c0e3c3e2..c89455f02 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -39,6 +39,7 @@ * * Authors: Ali Saidi * Andreas Hansson + * William Wang */ /** @@ -72,12 +73,14 @@ Bus::Bus(const BusParams *p) // create the ports based on the size of the master and slave // vector ports, and the presence of the default master - // id used to index into interfaces which is a flat vector of all - // ports + // id used to index into master and slave ports, that currently + // has holes to be able to use the id to index into either int id = 0; for (int i = 0; i < p->port_master_connection_count; ++i) { std::string portName = csprintf("%s-p%d", name(), id); - interfaces.push_back(new BusPort(portName, this, id)); + BusMasterPort* bp = new BusMasterPort(portName, this, id); + masterPorts.push_back(bp); + slavePorts.push_back(NULL); ++id; } @@ -86,7 +89,9 @@ Bus::Bus(const BusParams *p) if (p->port_default_connection_count) { defaultPortId = id; std::string portName = csprintf("%s-default", name()); - interfaces.push_back(new BusPort(portName, this, id)); + BusMasterPort* bp = new BusMasterPort(portName, this, id); + masterPorts.push_back(bp); + slavePorts.push_back(NULL); ++id; // this is an additional master port ++nbrMasterPorts; @@ -96,44 +101,55 @@ Bus::Bus(const BusParams *p) // nbrMasterPorts in the vector for (int i = 0; i < p->port_slave_connection_count; ++i) { std::string portName = csprintf("%s-p%d", name(), id); - interfaces.push_back(new BusPort(portName, this, id)); + BusSlavePort* bp = new BusSlavePort(portName, this, id); + masterPorts.push_back(NULL); + slavePorts.push_back(bp); ++id; } clearPortCache(); } -Port * -Bus::getPort(const std::string &if_name, int idx) +MasterPort & +Bus::getMasterPort(const std::string &if_name, int idx) { if (if_name == "master") { // the master index translates directly to the interfaces // vector as they are stored first - return interfaces[idx]; - } else if (if_name == "slave") { - // the slaves are stored after the masters and we must thus - // offset the slave index with the number of master ports - return interfaces[nbrMasterPorts + idx]; + return *masterPorts[idx]; } else if (if_name == "default") { - return interfaces[defaultPortId]; + return *masterPorts[defaultPortId]; } else { - panic("No port %s %d on bus %s\n", if_name, idx, name()); + return MemObject::getMasterPort(if_name, idx); + } +} + +SlavePort & +Bus::getSlavePort(const std::string &if_name, int idx) +{ + if (if_name == "slave") { + return *slavePorts[nbrMasterPorts + idx]; + } else { + return MemObject::getSlavePort(if_name, idx); } } void Bus::init() { - std::vector<BusPort*>::iterator intIter; + std::vector<BusSlavePort*>::iterator intIter; // iterate over our interfaces and determine which of our neighbours // are snooping and add them as snoopers - for (intIter = interfaces.begin(); intIter != interfaces.end(); + for (intIter = slavePorts.begin(); intIter != slavePorts.end(); intIter++) { - if ((*intIter)->getPeer()->isSnooping()) { - DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", - (*intIter)->getPeer()->name()); - snoopPorts.push_back(*intIter); + // since there are holes in the vector, check for NULL + if (*intIter != NULL) { + if ((*intIter)->getMasterPort().isSnooping()) { + DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", + (*intIter)->getMasterPort().name()); + snoopPorts.push_back(*intIter); + } } } } @@ -194,7 +210,9 @@ Bus::recvTiming(PacketPtr pkt) // get the source id and port Packet::NodeID src_id = pkt->getSrc(); - BusPort *src_port = interfaces[src_id]; + // determine the source port based on the id + Port *src_port = slavePorts[src_id] ? + (Port*) slavePorts[src_id] : (Port*) masterPorts[src_id]; // If the bus is busy, or other devices are in line ahead of the current // one, put this device on the retry list. @@ -218,14 +236,14 @@ Bus::recvTiming(PacketPtr pkt) int dest_id; Port *dest_port; - if (dest == Packet::Broadcast) { + if (pkt->isRequest()) { // the packet is a memory-mapped request and should be broadcasted to // our snoopers - assert(pkt->isRequest()); + assert(dest == Packet::Broadcast); SnoopIter s_end = snoopPorts.end(); for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { - BusPort *p = *s_iter; + BusSlavePort *p = *s_iter; // we got this request from a snooping master // (corresponding to our own slave port that is also in // snoopPorts) and should not send it back to where it @@ -241,16 +259,28 @@ Bus::recvTiming(PacketPtr pkt) // determine the destination based on the address and forward // through the corresponding master port dest_id = findPort(pkt->getAddr()); - dest_port = interfaces[dest_id]; + dest_port = masterPorts[dest_id]; } else { // the packet is a response, and it should always go back to // the port determined by the destination field dest_id = dest; assert(dest_id != src_id); // catch infinite loops - assert(dest_id < interfaces.size()); - dest_port = interfaces[dest_id]; + dest_port = slavePorts[dest_id] ? + (Port*) slavePorts[dest_id] : (Port*) masterPorts[dest_id]; + + // a normal response from the memory system (i.e. from a + // connected slave) should always go back to the master + // that issued it through one of our slave ports, however + // if this is a snoop response it could go either way, for + // example, it could be coming from a slave port + // connecting an L1 with a coherent master and another L1 + // coherent master (one of our slave ports), or coming + // from the L1 and going to the L2 slave port (through one + // of our master ports) } + assert(dest_port != NULL); + // if this is a snoop from a slave (corresponding to our own // master), i.e. the memory side of the bus, then do not send it // back to where it came from @@ -318,8 +348,6 @@ Bus::retryWaiting() // send a retry to the port at the head of the retry list inRetry = true; - DPRINTF(Bus, "Sending a retry to %s\n", - retryList.front()->getPeer()->name()); // note that we might have blocked on the receiving port being // busy (rather than the bus itself) and now call retry before the @@ -427,7 +455,7 @@ Bus::recvAtomic(PacketPtr pkt) SnoopIter s_end = snoopPorts.end(); for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { - BusPort *p = *s_iter; + BusSlavePort *p = *s_iter; // we could have gotten this request from a snooping master // (corresponding to our own slave port that is also in // snoopPorts) and should not send it back to where it came @@ -464,7 +492,7 @@ Bus::recvAtomic(PacketPtr pkt) // master), i.e. the memory side of the bus, then do not send it // back to where it came from if (dest_id != src_id) { - response_latency = interfaces[dest_id]->sendAtomic(pkt); + response_latency = masterPorts[dest_id]->sendAtomic(pkt); } // if we got a response from a snooper, restore it here @@ -504,7 +532,7 @@ Bus::recvFunctional(PacketPtr pkt) SnoopIter s_end = snoopPorts.end(); for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { - BusPort *p = *s_iter; + BusSlavePort *p = *s_iter; // we could have gotten this request from a snooping master // (corresponding to our own slave port that is also in // snoopPorts) and should not send it back to where it came @@ -528,7 +556,7 @@ Bus::recvFunctional(PacketPtr pkt) // master), i.e. the memory side of the bus, then do not send // it back to where it came from, if (dest_id != src_id) { - interfaces[dest_id]->sendFunctional(pkt); + masterPorts[dest_id]->sendFunctional(pkt); } } } @@ -551,7 +579,8 @@ Bus::recvRangeChange(int id) defaultRange.clear(); // Only try to update these ranges if the user set a default responder. if (useDefaultRange) { - AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges(); + AddrRangeList ranges = + masterPorts[id]->getSlavePort().getAddrRanges(); for(iter = ranges.begin(); iter != ranges.end(); iter++) { defaultRange.push_back(*iter); DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", @@ -560,8 +589,8 @@ Bus::recvRangeChange(int id) } } else { - assert(id < interfaces.size() && id >= 0); - BusPort *port = interfaces[id]; + assert(id < masterPorts.size() && id >= 0); + BusMasterPort *port = masterPorts[id]; // Clean out any previously existent ids for (PortIter portIter = portMap.begin(); @@ -572,7 +601,7 @@ Bus::recvRangeChange(int id) portIter++; } - ranges = port->getPeer()->getAddrRanges(); + ranges = port->getSlavePort().getAddrRanges(); for (iter = ranges.begin(); iter != ranges.end(); iter++) { DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", @@ -580,8 +609,8 @@ Bus::recvRangeChange(int id) if (portMap.insert(*iter, id) == portMap.end()) { int conflict_id = portMap.find(*iter)->second; fatal("%s has two ports with same range:\n\t%s\n\t%s\n", - name(), interfaces[id]->getPeer()->name(), - interfaces[conflict_id]->getPeer()->name()); + name(), masterPorts[id]->getSlavePort().name(), + masterPorts[conflict_id]->getSlavePort().name()); } } } @@ -589,10 +618,10 @@ Bus::recvRangeChange(int id) // tell all our peers that our address range has changed. // Don't tell the device that caused this change, it already knows - std::vector<BusPort*>::const_iterator intIter; + std::vector<BusSlavePort*>::const_iterator intIter; - for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) - if ((*intIter)->getId() != id) + for (intIter = slavePorts.begin(); intIter != slavePorts.end(); intIter++) + if (*intIter != NULL && (*intIter)->getId() != id) (*intIter)->sendRangeChange(); inRecvRangeChange.erase(id); @@ -640,7 +669,7 @@ Bus::getAddrRanges(int id) } bool -Bus::isSnooping(int id) +Bus::isSnooping(int id) const { // in essence, answer the question if there are snooping ports return !snoopPorts.empty(); @@ -656,7 +685,7 @@ Bus::findBlockSize(int id) PortIter p_end = portMap.end(); for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { - unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize(); + unsigned tmp_bs = masterPorts[p_iter->second]->peerBlockSize(); if (tmp_bs > max_bs) max_bs = tmp_bs; } diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 4ea92308a..e79e9df9e 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -40,6 +40,7 @@ * Authors: Ron Dreslinski * Ali Saidi * Andreas Hansson + * William Wang */ /** @@ -65,21 +66,85 @@ class Bus : public MemObject { - /** Declaration of the buses port type, one will be instantiated for each - of the interfaces connecting to the bus. */ - class BusPort : public Port + /** + * Declaration of the bus slave port type, one will be + * instantiated for each of the master interfaces connecting to + * the bus. + */ + class BusSlavePort : public SlavePort + { + private: + /** A pointer to the bus to which this port belongs. */ + Bus *bus; + + /** A id to keep track of the interface ID of this port. */ + int id; + + public: + + /** Constructor for the BusSlavePort.*/ + BusSlavePort(const std::string &_name, Bus *_bus, int _id) + : SlavePort(_name, _bus), bus(_bus), id(_id) + { } + + int getId() const { return id; } + + protected: + + /** When reciving a timing request from the peer port (at id), + pass it to the bus. */ + virtual bool recvTiming(PacketPtr pkt) + { pkt->setSrc(id); return bus->recvTiming(pkt); } + + /** When reciving a Atomic requestfrom the peer port (at id), + pass it to the bus. */ + virtual Tick recvAtomic(PacketPtr pkt) + { pkt->setSrc(id); return bus->recvAtomic(pkt); } + + /** When reciving a Functional requestfrom the peer port (at id), + pass it to the bus. */ + virtual void recvFunctional(PacketPtr pkt) + { pkt->setSrc(id); bus->recvFunctional(pkt); } + + /** When reciving a retry from the peer port (at id), + pass it to the bus. */ + virtual void recvRetry() + { bus->recvRetry(id); } + + // This should return all the 'owned' addresses that are + // downstream from this bus, yes? That is, the union of all + // the 'owned' address ranges of all the other interfaces on + // this bus... + virtual AddrRangeList getAddrRanges() + { return bus->getAddrRanges(id); } + + // Ask the bus to ask everyone on the bus what their block size is and + // take the max of it. This might need to be changed a bit if we ever + // support multiple block sizes. + virtual unsigned deviceBlockSize() const + { return bus->findBlockSize(id); } + + }; + + /** + * Declaration of the bus master port type, one will be + * instantiated for each of the slave interfaces connecting to the + * bus. + */ + class BusMasterPort : public MasterPort { + private: /** A pointer to the bus to which this port belongs. */ Bus *bus; - /** A id to keep track of the intercafe ID this port is connected to. */ + /** A id to keep track of the interface ID of this port. */ int id; public: - /** Constructor for the BusPort.*/ - BusPort(const std::string &_name, Bus *_bus, int _id) - : Port(_name, _bus), bus(_bus), id(_id) + /** Constructor for the BusMasterPort.*/ + BusMasterPort(const std::string &_name, Bus *_bus, int _id) + : MasterPort(_name, _bus), bus(_bus), id(_id) { } int getId() const { return id; } @@ -90,7 +155,7 @@ class Bus : public MemObject * * @return a boolean that is true if this port is snooping */ - virtual bool isSnooping() + virtual bool isSnooping() const { return bus->isSnooping(id); } protected: @@ -120,13 +185,6 @@ class Bus : public MemObject virtual void recvRetry() { bus->recvRetry(id); } - // This should return all the 'owned' addresses that are - // downstream from this bus, yes? That is, the union of all - // the 'owned' address ranges of all the other interfaces on - // this bus... - virtual AddrRangeList getAddrRanges() - { return bus->getAddrRanges(id); } - // Ask the bus to ask everyone on the bus what their block size is and // take the max of it. This might need to be changed a bit if we ever // support multiple block sizes. @@ -151,8 +209,8 @@ class Bus : public MemObject AddrRangeList defaultRange; - typedef std::vector<BusPort*>::iterator SnoopIter; - std::vector<BusPort*> snoopPorts; + typedef std::vector<BusSlavePort*>::iterator SnoopIter; + std::vector<BusSlavePort*> snoopPorts; /** Function called by the port when the bus is recieving a Timing transaction.*/ @@ -250,7 +308,7 @@ class Bus : public MemObject * * @return a boolean indicating if this port is snooping or not */ - bool isSnooping(int id); + bool isSnooping(int id) const; /** Calculate the timing parameters for the packet. Updates the * firstWordTime and finishTime fields of the packet object. @@ -292,9 +350,9 @@ class Bus : public MemObject // interfaces vector unsigned int nbrMasterPorts; - /** An ordered vector of pointers to the peer port interfaces - connected to this bus.*/ - std::vector<BusPort*> interfaces; + /** The master and slave ports of the bus */ + std::vector<BusSlavePort*> slavePorts; + std::vector<BusMasterPort*> masterPorts; /** An array of pointers to ports that retry should be called on because the * original send failed for whatever reason.*/ @@ -338,7 +396,8 @@ class Bus : public MemObject public: /** A function used to return the port associated with this bus object. */ - virtual Port *getPort(const std::string &if_name, int idx = -1); + virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1); + virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); virtual void init(); virtual void startup(); diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index a2cb59a76..4ae6376db 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -57,7 +57,7 @@ using namespace std; BaseCache::CacheSlavePort::CacheSlavePort(const std::string &_name, BaseCache *_cache, const std::string &_label) - : QueuedPort(_name, _cache, queue), queue(*_cache, *this, _label), + : QueuedSlavePort(_name, _cache, queue), queue(*_cache, *this, _label), blocked(false), mustSendRetry(false), sendRetryEvent(this) { } @@ -99,7 +99,7 @@ BaseCache::CacheSlavePort::clearBlocked() DPRINTF(CachePort, "Cache port %s sending retry\n", name()); mustSendRetry = false; // @TODO: need to find a better time (next bus cycle?) - owner->schedule(sendRetryEvent, curTick() + 1); + owner.schedule(sendRetryEvent, curTick() + 1); } } @@ -108,10 +108,29 @@ void BaseCache::init() { if (!cpuSidePort->isConnected() || !memSidePort->isConnected()) - panic("Cache %s not hooked up on both sides\n", name()); + fatal("Cache ports on %s are not connected\n", name()); cpuSidePort->sendRangeChange(); } +MasterPort & +BaseCache::getMasterPort(const std::string &if_name, int idx) +{ + if (if_name == "mem_side") { + return *memSidePort; + } else { + return MemObject::getMasterPort(if_name, idx); + } +} + +SlavePort & +BaseCache::getSlavePort(const std::string &if_name, int idx) +{ + if (if_name == "cpu_side") { + return *cpuSidePort; + } else { + return MemObject::getSlavePort(if_name, idx); + } +} void BaseCache::regStats() diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh index c13d27d42..47cbaf7a0 100644 --- a/src/mem/cache/base.hh +++ b/src/mem/cache/base.hh @@ -118,7 +118,7 @@ class BaseCache : public MemObject * and the sendDeferredPacket of the timing port is modified to * consider both the transmit list and the requests from the MSHR. */ - class CacheMasterPort : public QueuedPort + class CacheMasterPort : public QueuedMasterPort { public: @@ -149,7 +149,7 @@ class BaseCache : public MemObject CacheMasterPort(const std::string &_name, BaseCache *_cache, PacketQueue &_queue) : - QueuedPort(_name, _cache, _queue) + QueuedMasterPort(_name, _cache, _queue) { } /** @@ -157,7 +157,7 @@ class BaseCache : public MemObject * * @return always true */ - virtual bool isSnooping() { return true; } + virtual bool isSnooping() const { return true; } }; /** @@ -168,7 +168,7 @@ class BaseCache : public MemObject * incoming requests. If blocked, the port will issue a retry once * unblocked. */ - class CacheSlavePort : public QueuedPort + class CacheSlavePort : public QueuedSlavePort { public: @@ -444,6 +444,9 @@ class BaseCache : public MemObject virtual void init(); + virtual MasterPort &getMasterPort(const std::string &if_name, int idx = -1); + virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1); + /** * Query block size of a cache. * @return The block size diff --git a/src/mem/cache/builder.cc b/src/mem/cache/builder.cc index cc206b784..ca8c378fb 100644 --- a/src/mem/cache/builder.cc +++ b/src/mem/cache/builder.cc @@ -40,7 +40,6 @@ #include "mem/cache/base.hh" #include "mem/cache/cache.hh" #include "mem/config/cache.hh" -#include "mem/bus.hh" #include "params/BaseCache.hh" // Tag Templates diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index 782749aab..e745529a7 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -249,8 +249,6 @@ class Cache : public BaseCache /** Instantiates a basic cache object. */ Cache(const Params *p, TagStore *tags); - virtual Port *getPort(const std::string &if_name, int idx = -1); - void regStats(); /** diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 2463071de..3525e0777 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -92,19 +92,6 @@ Cache<TagStore>::regStats() } template<class TagStore> -Port * -Cache<TagStore>::getPort(const std::string &if_name, int idx) -{ - if (if_name == "cpu_side") { - return cpuSidePort; - } else if (if_name == "mem_side") { - return memSidePort; - } else { - panic("Port name %s unrecognized\n", if_name); - } -} - -template<class TagStore> void Cache<TagStore>::cmpAndSwap(BlkType *blk, PacketPtr pkt) { @@ -795,7 +782,7 @@ Cache<TagStore>::functionalAccess(PacketPtr pkt, bool fromCpuSide) // continues towards the memory side if (fromCpuSide) { memSidePort->sendFunctional(pkt); - } else if (forwardSnoops) { + } else if (forwardSnoops && cpuSidePort->getMasterPort().isSnooping()) { // if it came from the memory side, it must be a snoop request // and we should only forward it if we are forwarding snoops cpuSidePort->sendFunctional(pkt); diff --git a/src/mem/fs_translating_port_proxy.cc b/src/mem/fs_translating_port_proxy.cc index 2e9a0fa00..bf0c076c6 100644 --- a/src/mem/fs_translating_port_proxy.cc +++ b/src/mem/fs_translating_port_proxy.cc @@ -58,7 +58,7 @@ FSTranslatingPortProxy::FSTranslatingPortProxy(ThreadContext *tc) { } -FSTranslatingPortProxy::FSTranslatingPortProxy(Port &port) +FSTranslatingPortProxy::FSTranslatingPortProxy(MasterPort &port) : PortProxy(port), _tc(NULL) { } diff --git a/src/mem/fs_translating_port_proxy.hh b/src/mem/fs_translating_port_proxy.hh index 2217a46aa..c022f3d09 100644 --- a/src/mem/fs_translating_port_proxy.hh +++ b/src/mem/fs_translating_port_proxy.hh @@ -78,7 +78,7 @@ class FSTranslatingPortProxy : public PortProxy FSTranslatingPortProxy(ThreadContext* tc); - FSTranslatingPortProxy(Port &port); + FSTranslatingPortProxy(MasterPort &port); virtual ~FSTranslatingPortProxy(); diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc index 111d3718c..ce8badbe7 100644 --- a/src/mem/mem_object.cc +++ b/src/mem/mem_object.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012 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. * @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Steve Reinhardt + * Andreas Hansson */ #include "mem/mem_object.hh" @@ -34,3 +47,15 @@ MemObject::MemObject(const Params *params) : SimObject(params) { } + +MasterPort& +MemObject::getMasterPort(const std::string& if_name, int idx) +{ + fatal("%s does not have any master port named %s\n", name(), if_name); +} + +SlavePort& +MemObject::getSlavePort(const std::string& if_name, int idx) +{ + fatal("%s does not have any slave port named %s\n", name(), if_name); +} diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh index 5865fc935..d8e6bdcb0 100644 --- a/src/mem/mem_object.hh +++ b/src/mem/mem_object.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012 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. * @@ -26,11 +38,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Ron Dreslinski + * Andreas Hansson */ /** * @file - * Base Memory Object declaration. + * MemObject declaration. */ #ifndef __MEM_MEM_OBJECT_HH__ @@ -41,8 +54,8 @@ #include "sim/sim_object.hh" /** - * The base MemoryObject class, allows for an accesor function to a - * simobj that returns the Port. + * The MemObject class extends the SimObject with accessor functions + * to get its master and slave ports. */ class MemObject : public SimObject { @@ -53,9 +66,27 @@ class MemObject : public SimObject MemObject(const Params *params); - public: - /** Additional function to return the Port of a memory object. */ - virtual Port *getPort(const std::string &if_name, int idx = -1) = 0; + /** + * Get a master port with a given name and index. + * + * @param if_name Port name + * @param idx Index in the case of a VectorPort + * + * @return A reference to the given port + */ + virtual MasterPort& getMasterPort(const std::string& if_name, + int idx = -1); + + /** + * Get a slave port with a given name and index. + * + * @param if_name Port name + * @param idx Index in the case of a VectorPort + * + * @return A reference to the given port + */ + virtual SlavePort& getSlavePort(const std::string& if_name, + int idx = -1); }; #endif //__MEM_MEM_OBJECT_HH__ diff --git a/src/mem/mport.cc b/src/mem/mport.cc index 2c57030b1..9af394d27 100644 --- a/src/mem/mport.cc +++ b/src/mem/mport.cc @@ -43,17 +43,26 @@ #include "mem/mport.hh" Tick -MessagePort::recvAtomic(PacketPtr pkt) +MessageSlavePort::recvAtomic(PacketPtr pkt) { if (pkt->cmd == MemCmd::MessageReq) { return recvMessage(pkt); - } else if (pkt->cmd == MemCmd::MessageResp) { + } else { + panic("%s received unexpected atomic command %s from %s.\n", + name(), pkt->cmd.toString(), getMasterPort().name()); + } +} + +Tick +MessageMasterPort::recvAtomic(PacketPtr pkt) +{ + if (pkt->cmd == MemCmd::MessageResp) { // normally we would never see responses in recvAtomic, but // since the timing port uses recvAtomic to implement - // recvTiming we have to deal with both cases + // recvTiming we have to deal with them here return recvResponse(pkt); } else { panic("%s received unexpected atomic command %s from %s.\n", - name(), pkt->cmd.toString(), getPeer()->name()); + name(), pkt->cmd.toString(), getSlavePort().name()); } } diff --git a/src/mem/mport.hh b/src/mem/mport.hh index 7f167c227..664acc559 100644 --- a/src/mem/mport.hh +++ b/src/mem/mport.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012 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) 2008 The Regents of The University of Michigan * All rights reserved. * @@ -41,15 +53,15 @@ * the underpinnings of SimpleTimingPort, but it tweaks some of the external * functions. */ -class MessagePort : public SimpleTimingPort +class MessageSlavePort : public SimpleTimingPort { public: - MessagePort(const std::string &name, MemObject *owner) : + MessageSlavePort(const std::string &name, MemObject *owner) : SimpleTimingPort(name, owner) {} - virtual ~MessagePort() + virtual ~MessageSlavePort() {} protected: @@ -57,6 +69,29 @@ class MessagePort : public SimpleTimingPort Tick recvAtomic(PacketPtr pkt); virtual Tick recvMessage(PacketPtr pkt) = 0; +}; + +class MessageMasterPort : public QueuedMasterPort +{ + public: + + MessageMasterPort(const std::string &name, MemObject *owner) : + QueuedMasterPort(name, owner, queue), queue(*owner, *this) + {} + + virtual ~MessageMasterPort() + {} + + void recvFunctional(PacketPtr pkt) { assert(false); } + + Tick recvAtomic(PacketPtr pkt); + + bool recvTiming(PacketPtr pkt) { recvAtomic(pkt); return true; } + + protected: + + /** A packet queue for outgoing packets. */ + PacketQueue queue; // Accept and ignore responses. virtual Tick recvResponse(PacketPtr pkt) diff --git a/src/mem/physical.cc b/src/mem/physical.cc index f11fbb947..9c953e562 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -439,18 +439,18 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt) } -Port * -PhysicalMemory::getPort(const std::string &if_name, int idx) +SlavePort & +PhysicalMemory::getSlavePort(const std::string &if_name, int idx) { if (if_name != "port") { - panic("PhysicalMemory::getPort: unknown port %s requested\n", if_name); - } + return MemObject::getSlavePort(if_name, idx); + } else { + if (idx >= static_cast<int>(ports.size())) { + fatal("PhysicalMemory::getSlavePort: unknown index %d\n", idx); + } - if (idx >= static_cast<int>(ports.size())) { - panic("PhysicalMemory::getPort: unknown index %d requested\n", idx); + return *ports[idx]; } - - return ports[idx]; } PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, @@ -458,13 +458,6 @@ PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, : SimpleTimingPort(_name, _memory), memory(_memory) { } -void -PhysicalMemory::MemoryPort::recvRangeChange() -{ - // memory is a slave and thus should never have to worry about its - // neighbours address ranges -} - AddrRangeList PhysicalMemory::MemoryPort::getAddrRanges() { diff --git a/src/mem/physical.hh b/src/mem/physical.hh index b447237c7..452ac3fc0 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -67,8 +67,6 @@ class PhysicalMemory : public MemObject virtual void recvFunctional(PacketPtr pkt); - virtual void recvRangeChange(); - virtual AddrRangeList getAddrRanges(); virtual unsigned deviceBlockSize() const; @@ -196,7 +194,7 @@ class PhysicalMemory : public MemObject public: unsigned deviceBlockSize() const; AddrRangeList getAddrRanges(); - virtual Port *getPort(const std::string &if_name, int idx = -1); + virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1); void virtual init(); unsigned int drain(Event *de); diff --git a/src/mem/port.cc b/src/mem/port.cc index 8edca16f7..3305541c7 100644 --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012 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. * @@ -26,6 +38,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Steve Reinhardt + * Andreas Hansson + * William Wang */ /** @@ -33,11 +47,10 @@ * Port object definitions. */ #include "base/trace.hh" -#include "debug/Config.hh" #include "mem/mem_object.hh" #include "mem/port.hh" -Port::Port(const std::string &_name, MemObject *_owner) +Port::Port(const std::string &_name, MemObject& _owner) : portName(_name), peer(NULL), owner(_owner) { } @@ -46,22 +59,53 @@ Port::~Port() { } -void -Port::setPeer(Port *port) +/** + * Master port + */ +MasterPort::MasterPort(const std::string& name, MemObject* owner) + : Port(name, *owner), _slavePort(NULL) { - DPRINTF(Config, "setting peer to %s\n", port->name()); +} - peer = port; +MasterPort::~MasterPort() +{ } -void -Port::setOwner(MemObject *_owner) +SlavePort& +MasterPort::getSlavePort() const { - owner = _owner; + if(_slavePort == NULL) + panic("Cannot getSlavePort on master port %s that is not connected\n", + name()); + + return *_slavePort; } void -Port::printAddr(Addr a) +MasterPort::bind(SlavePort& slave_port) +{ + // master port keeps track of the slave port + _slavePort = &slave_port; + peer = &slave_port; + + // slave port also keeps track of master port + _slavePort->bind(*this); +} + +bool +MasterPort::isConnected() const +{ + return _slavePort != NULL; +} + +unsigned +MasterPort::peerBlockSize() const +{ + return _slavePort->deviceBlockSize(); +} + + void +MasterPort::printAddr(Addr a) { Request req(a, 1, 0, Request::funcMasterId); Packet pkt(&req, MemCmd::PrintReq, Packet::Broadcast); @@ -70,3 +114,44 @@ Port::printAddr(Addr a) sendFunctional(&pkt); } + +/** + * Slave port + */ +SlavePort::SlavePort(const std::string& name, MemObject* owner) + : Port(name, *owner), _masterPort(NULL) +{ +} + +SlavePort::~SlavePort() +{ +} + +void +SlavePort::bind(MasterPort& master_port) +{ + _masterPort = &master_port; + peer = &master_port; +} + +MasterPort& +SlavePort::getMasterPort() const +{ + if (_masterPort == NULL) + panic("Cannot getMasterPort on slave port %s that is not connected\n", + name()); + + return *_masterPort; +} + +unsigned +SlavePort::peerBlockSize() const +{ + return _masterPort->deviceBlockSize(); +} + +bool +SlavePort::isConnected() const +{ + return _masterPort != NULL; +} diff --git a/src/mem/port.hh b/src/mem/port.hh index fef0c839d..80bb3b085 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -39,15 +39,12 @@ * * Authors: Ron Dreslinski * Andreas Hansson + * William Wang */ /** * @file - * Port Object Declaration. Ports are used to interface memory objects to - * each other. They will always come in pairs, and we refer to the other - * port object as the peer. These are used to make the design more - * modular so that a specific interface between every type of objcet doesn't - * have to be created. + * Port Object Declaration. */ #ifndef __MEM_PORT_HH__ @@ -58,7 +55,8 @@ #include "base/range.hh" #include "mem/packet.hh" -/** This typedef is used to clean up getAddrRanges(). It's declared +/** + * This typedef is used to clean up getAddrRanges(). It's declared * outside the Port object since it's also used by some mem objects. * Eventually we should move this typedef to wherever Addr is * defined. @@ -70,62 +68,47 @@ typedef std::list<Range<Addr> >::iterator AddrRangeIter; class MemObject; /** - * Ports are used to interface memory objects to - * each other. They will always come in pairs, and we refer to the other - * port object as the peer. These are used to make the design more - * modular so that a specific interface between every type of objcet doesn't - * have to be created. + * Ports are used to interface memory objects to each other. A port is + * either a master or a slave and the connected peer is always of the + * opposite role. * - * Recv accesor functions are being called from the peer interface. - * Send accessor functions are being called from the device the port is - * associated with, and it will call the peer recv. accessor function. + * Each port has a name and an owner, and enables three basic types of + * accesses to the peer port: sendFunctional, sendAtomic and + * sendTiming. */ class Port { - protected: + + private: + /** Descriptive name (for DPRINTF output) */ - mutable std::string portName; + std::string portName; - /** A pointer to the peer port. Ports always come in pairs, that way they - can use a standardized interface to communicate between different - memory objects. */ - Port *peer; + protected: - /** A pointer to the MemObject that owns this port. This may not be set. */ - MemObject *owner; + /** A pointer to the peer port. */ + Port* peer; + + /** A reference to the MemObject that owns this port. */ + MemObject& owner; - public: /** - * Constructor. + * Abstract base class for ports * - * @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. + * @param _name Port name including the owners name + * @param _owner The MemObject that is the structural owner of this port */ - Port(const std::string &_name, MemObject *_owner); - - /** Return port name (for DPRINTF). */ - const std::string &name() const { return portName; } + Port(const std::string& _name, MemObject& _owner); + /** + * Virtual destructor due to inheritance. + */ virtual ~Port(); - 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); - - /** Function to return the owner of this port. */ - MemObject *getOwner() { return owner; } + public: - bool isConnected() { return peer != NULL; } + /** Return port name (for DPRINTF). */ + const std::string name() const { return portName; } protected: @@ -141,89 +124,109 @@ class Port /** Called to recive a functional call from the peer port. */ virtual void recvFunctional(PacketPtr pkt) = 0; - /** Called to recieve an address range change from the peer port. */ - virtual void recvRangeChange() = 0; + /** + * Called by a peer port if sendTiming was unsuccesful, and had to + * wait. + */ + virtual void recvRetry() = 0; - /** Called by a peer port if the send was unsuccesful, and had to - wait. This shouldn't be valid for response paths (IO Devices). - so it is set to panic if it isn't already defined. - */ - virtual void recvRetry() { panic("??"); } + public: - /** Called by a peer port in order to determine the block size of the - device connected to this port. It sometimes doesn't make sense for - this function to be called, so it just returns 0. Anytthing that is - concerned with the size should just ignore that. + /** + * Attempt to send a timing packet to the peer port by calling its + * receive function. If the send does not succeed, as indicated by + * the return value, then the sender must wait for a recvRetry at + * which point it can re-issue a sendTiming. + * + * @param pkt Packet to send. + * + * @return If the send was succesful or not. */ - virtual unsigned deviceBlockSize() const { return 0; } + bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); } - public: + /** + * Send a retry to a peer port that previously attempted a sendTiming + * which was unsuccessful. + */ + void sendRetry() { return peer->recvRetry(); } /** - * Get a list of the non-overlapping address ranges we are - * responsible for. The default implementation returns an empty - * list and thus no address ranges. Any slave port must override - * this function and return a populated list with at least one - * item. + * Send an atomic packet, where the data is moved and the state + * is updated in zero time, without interleaving with other + * memory accesses. * - * @return a list of ranges responded to + * @param pkt Packet to send. + * + * @return Estimated latency of access. */ - virtual AddrRangeList getAddrRanges() - { AddrRangeList ranges; return ranges; } + Tick sendAtomic(PacketPtr pkt) { return peer->recvAtomic(pkt); } /** - * Determine if this port is snooping or not. The default - * implementation returns false and thus tells the neighbour we - * are not snooping. Any port that is to snoop (e.g. a cache - * connected to a bus) has to override this function. + * Send a functional packet, where the data is instantly updated + * everywhere in the memory system, without affecting the current + * state of any block or moving the block. * - * @return true if the port should be considered a snooper + * @param pkt Packet to send. */ - virtual bool isSnooping() - { return false; } - - /** Function called by associated memory device (cache, memory, iodevice) - in order to send a timing request to the port. Simply calls the peer - port receive function. - @return This function returns if the send was succesful in it's - recieve. If it was a failure, then the port will wait for a recvRetry - at which point it can possibly issue a successful sendTiming. This is used in - case a cache has a higher priority request come in while waiting for - the bus to arbitrate. - */ - bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); } + void sendFunctional(PacketPtr pkt) { return peer->recvFunctional(pkt); } - /** Function called by the associated device to send an atomic - * access, an access in which the data is moved and the state is - * updated in one cycle, without interleaving with other memory - * accesses. Returns estimated latency of access. - */ - Tick sendAtomic(PacketPtr pkt) - { return peer->recvAtomic(pkt); } +}; - /** Function called by the associated device to send a functional access, - an access in which the data is instantly updated everywhere in the - memory system, without affecting the current state of any block or - moving the block. - */ - void sendFunctional(PacketPtr pkt) - { return peer->recvFunctional(pkt); } +/** Forward declaration */ +class SlavePort; + +/** + * A MasterPort is a specialisation of a port. In addition to the + * basic functionality of sending packets to its slave peer, it also + * has functions specific to a master, e.g. to receive range changes + * or determine if the port is snooping or not. + */ +class MasterPort : public Port +{ + + private: + + SlavePort* _slavePort; + + public: + + MasterPort(const std::string& name, MemObject* owner); + virtual ~MasterPort(); + + void bind(SlavePort& slave_port); + SlavePort& getSlavePort() const; + bool isConnected() const; /** - * Called by the associated device to send a status range to the - * peer interface. + * Called to receive an address range change from the peer slave + * port. the default implementation ignored the change and does + * nothing. Override this function in a derived class if the owner + * needs to be aware of he laesddress ranges, e.g. in an + * interconnect component like a bus. */ - void sendRangeChange() const { peer->recvRangeChange(); } + virtual void recvRangeChange() { } - /** When a timing access doesn't return a success, some time later the - Retry will be sent. - */ - void sendRetry() { return peer->recvRetry(); } + /** + * Determine if this master port is snooping or not. The default + * implementation returns false and thus tells the neighbour we + * are not snooping. Any master port that wants to receive snoop + * requests (e.g. a cache connected to a bus) has to override this + * function. + * + * @return true if the port should be considered a snooper + */ + virtual bool isSnooping() const { return false; } + + /** + * Called by a peer port in order to determine the block size of + * the owner of this port. + */ + virtual unsigned deviceBlockSize() const { return 0; } /** Called by the associated device if it wishes to find out the blocksize of the device on attached to the peer port. */ - unsigned peerBlockSize() const { return peer->deviceBlockSize(); } + unsigned peerBlockSize() const; /** Inject a PrintReq for the given address to print the state of * that address throughout the memory system. For debugging. @@ -231,4 +234,52 @@ class Port void printAddr(Addr a); }; +/** + * A SlavePort is a specialisation of a port. In addition to the + * basic functionality of sending packets to its master peer, it also + * has functions specific to a slave, e.g. to send range changes + * and get the address ranges that the port responds to. + */ +class SlavePort : public Port +{ + + private: + + MasterPort* _masterPort; + + public: + + SlavePort(const std::string& name, MemObject* owner); + virtual ~SlavePort(); + + void bind(MasterPort& master_port); + MasterPort& getMasterPort() const; + bool isConnected() const; + + /** + * Called by a peer port in order to determine the block size of + * the owner of this port. + */ + virtual unsigned deviceBlockSize() const { return 0; } + + /** Called by the associated device if it wishes to find out the blocksize + of the device on attached to the peer port. + */ + unsigned peerBlockSize() const; + + /** + * Called by the owner to send a range change + */ + void sendRangeChange() const { _masterPort->recvRangeChange(); } + + /** + * Get a list of the non-overlapping address ranges the owner is + * responsible for. All slave ports must override this function + * and return a populated list with at least one item. + * + * @return a list of ranges responded to + */ + virtual AddrRangeList getAddrRanges() = 0; +}; + #endif //__MEM_PORT_HH__ diff --git a/src/mem/port_proxy.hh b/src/mem/port_proxy.hh index b2b27312e..4600cd407 100644 --- a/src/mem/port_proxy.hh +++ b/src/mem/port_proxy.hh @@ -86,12 +86,12 @@ class PortProxy private: /** The actual physical port used by this proxy. */ - Port &_port; + MasterPort &_port; void blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd) const; public: - PortProxy(Port &port) : _port(port) { } + PortProxy(MasterPort &port) : _port(port) { } virtual ~PortProxy() { } /** diff --git a/src/mem/qport.hh b/src/mem/qport.hh index 39612d22f..6ee71a572 100644 --- a/src/mem/qport.hh +++ b/src/mem/qport.hh @@ -56,7 +56,7 @@ * queue is a parameter to allow tailoring of the queue implementation * (used in the cache). */ -class QueuedPort : public Port +class QueuedSlavePort : public SlavePort { protected: @@ -68,7 +68,46 @@ class QueuedPort : public Port * packet again. */ virtual void recvRetry() { queue.retry(); } - virtual void recvRangeChange() { } + public: + + /** + * Create a QueuedPort with a given name, owner, and a supplied + * implementation of a packet queue. The external definition of + * the queue enables e.g. the cache to implement a specific queue + * behaviuor in a subclass, and provide the latter to the + * QueuePort constructor. + */ + QueuedSlavePort(const std::string& name, MemObject* owner, + PacketQueue &queue) : + SlavePort(name, owner), queue(queue) + { } + + virtual ~QueuedSlavePort() { } + + /** Check the list of buffered packets against the supplied + * functional request. */ + bool checkFunctional(PacketPtr pkt) { return queue.checkFunctional(pkt); } + + /** + * Hook for draining the queued port. + * + * @param de an event which is used to signal back to the caller + * @returns a number indicating how many times process will be called + */ + unsigned int drain(Event *de) { return queue.drain(de); } +}; + +class QueuedMasterPort : public MasterPort +{ + + protected: + + /** Packet queue used to store outgoing requests and responses. */ + PacketQueue &queue; + + /** This function is notification that the device should attempt to send a + * packet again. */ + virtual void recvRetry() { queue.retry(); } public: @@ -79,11 +118,12 @@ class QueuedPort : public Port * behaviuor in a subclass, and provide the latter to the * QueuePort constructor. */ - QueuedPort(const std::string& name, MemObject* owner, PacketQueue &queue) : - Port(name, owner), queue(queue) + QueuedMasterPort(const std::string& name, MemObject* owner, + PacketQueue &queue) : + MasterPort(name, owner), queue(queue) { } - virtual ~QueuedPort() { } + virtual ~QueuedMasterPort() { } /** Check the list of buffered packets against the supplied * functional request. */ diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index aca6604c6..1769c51fd 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012 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) 2009 Advanced Micro Devices, Inc. * Copyright (c) 2011 Mark D. Hill and David A. Wood * All rights reserved. @@ -35,26 +47,27 @@ #include "mem/ruby/system/RubyPort.hh" RubyPort::RubyPort(const Params *p) - : MemObject(p), pio_port(csprintf("%s-pio-port", name()), this), - physMemPort(csprintf("%s-physMemPort", name()), this) + : MemObject(p), m_version(p->version), m_controller(NULL), + m_mandatory_q_ptr(NULL), + pio_port(csprintf("%s-pio-port", name()), this), + m_usingRubyTester(p->using_ruby_tester), m_request_cnt(0), + physMemPort(csprintf("%s-physMemPort", name()), this), + drainEvent(NULL), physmem(p->physmem), ruby_system(p->ruby_system), + waitingOnSequencer(false), access_phys_mem(p->access_phys_mem) { - m_version = p->version; assert(m_version != -1); - physmem = p->physmem; - - m_controller = NULL; - m_mandatory_q_ptr = NULL; - - m_request_cnt = 0; - - m_usingRubyTester = p->using_ruby_tester; - access_phys_mem = p->access_phys_mem; - - drainEvent = NULL; + // create the slave ports based on the number of connected ports + for (size_t i = 0; i < p->port_slave_connection_count; ++i) { + slave_ports.push_back(new M5Port(csprintf("%s-slave%d", name(), i), + this, ruby_system, access_phys_mem)); + } - ruby_system = p->ruby_system; - waitingOnSequencer = false; + // create the master ports based on the number of connected ports + for (size_t i = 0; i < p->port_master_connection_count; ++i) { + master_ports.push_back(new PioPort(csprintf("%s-master%d", name(), i), + this)); + } } void @@ -64,52 +77,63 @@ RubyPort::init() m_mandatory_q_ptr = m_controller->getMandatoryQueue(); } -Port * -RubyPort::getPort(const std::string &if_name, int idx) +MasterPort & +RubyPort::getMasterPort(const std::string &if_name, int idx) { - // used by the CPUs to connect the caches to the interconnect, and - // for the x86 case also the interrupt master - if (if_name == "slave") { - M5Port* cpuPort = new M5Port(csprintf("%s-slave%d", name(), idx), - this, ruby_system, access_phys_mem); - cpu_ports.push_back(cpuPort); - return cpuPort; + if (if_name == "pio_port") { + return pio_port; + } + + if (if_name == "physMemPort") { + return physMemPort; } // used by the x86 CPUs to connect the interrupt PIO and interrupt slave // port - if (if_name == "master") { - PioPort* masterPort = new PioPort(csprintf("%s-master%d", name(), idx), - this); + if (if_name != "master") { + // pass it along to our super class + return MemObject::getMasterPort(if_name, idx); + } else { + if (idx >= static_cast<int>(master_ports.size())) { + panic("RubyPort::getMasterPort: unknown index %d\n", idx); + } - return masterPort; + return *master_ports[idx]; } +} - if (if_name == "pio_port") { - return &pio_port; - } +SlavePort & +RubyPort::getSlavePort(const std::string &if_name, int idx) +{ + // used by the CPUs to connect the caches to the interconnect, and + // for the x86 case also the interrupt master + if (if_name != "slave") { + // pass it along to our super class + return MemObject::getSlavePort(if_name, idx); + } else { + if (idx >= static_cast<int>(slave_ports.size())) { + panic("RubyPort::getSlavePort: unknown index %d\n", idx); + } - if (if_name == "physMemPort") { - return &physMemPort; + return *slave_ports[idx]; } - - return NULL; } RubyPort::PioPort::PioPort(const std::string &_name, RubyPort *_port) - : QueuedPort(_name, _port, queue), queue(*_port, *this), ruby_port(_port) + : QueuedMasterPort(_name, _port, queue), queue(*_port, *this), + ruby_port(_port) { - DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name); + DPRINTF(RubyPort, "creating master port on ruby sequencer %s\n", _name); } RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, RubySystem *_system, bool _access_phys_mem) - : QueuedPort(_name, _port, queue), queue(*_port, *this), + : QueuedSlavePort(_name, _port, queue), queue(*_port, *this), ruby_port(_port), ruby_system(_system), _onRetryList(false), access_phys_mem(_access_phys_mem) { - DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name); + DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name); } Tick @@ -549,11 +573,15 @@ RubyPort::getDrainCount(Event *de) DPRINTF(Config, "count after physmem check %d\n", count); } - for (CpuPortIter p_iter = cpu_ports.begin(); p_iter != cpu_ports.end(); - p_iter++) { - M5Port* cpu_port = *p_iter; - count += cpu_port->drain(de); - DPRINTF(Config, "count after cpu port check %d\n", count); + for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) { + count += (*p)->drain(de); + DPRINTF(Config, "count after slave port check %d\n", count); + } + + for (std::vector<PioPort*>::iterator p = master_ports.begin(); + p != master_ports.end(); ++p) { + count += (*p)->drain(de); + DPRINTF(Config, "count after master port check %d\n", count); } DPRINTF(Config, "final count %d\n", count); @@ -657,11 +685,19 @@ RubyPort::PioPort::sendNextCycle(PacketPtr pkt) return true; } +AddrRangeList +RubyPort::M5Port::getAddrRanges() +{ + // at the moment the assumption is that the master does not care + AddrRangeList ranges; + return ranges; +} + bool RubyPort::M5Port::isPhysMemAddress(Addr addr) { AddrRangeList physMemAddrList = - ruby_port->physMemPort.getPeer()->getAddrRanges(); + ruby_port->physMemPort.getSlavePort().getAddrRanges(); for (AddrRangeIter iter = physMemAddrList.begin(); iter != physMemAddrList.end(); iter++) { @@ -684,9 +720,12 @@ void RubyPort::ruby_eviction_callback(const Address& address) { DPRINTF(RubyPort, "Sending invalidations.\n"); + // should this really be using funcMasterId? Request req(address.getAddress(), 0, 0, Request::funcMasterId); - for (CpuPortIter it = cpu_ports.begin(); it != cpu_ports.end(); it++) { - Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1); - (*it)->sendNextCycle(pkt); + for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) { + if ((*p)->getMasterPort().isSnooping()) { + Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1); + (*p)->sendNextCycle(pkt); + } } } diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh index bef291d63..d97f6e69e 100644 --- a/src/mem/ruby/system/RubyPort.hh +++ b/src/mem/ruby/system/RubyPort.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012 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) 2009 Advanced Micro Devices, Inc. * Copyright (c) 2011 Mark D. Hill and David A. Wood * All rights reserved. @@ -46,7 +58,7 @@ class AbstractController; class RubyPort : public MemObject { public: - class M5Port : public QueuedPort + class M5Port : public QueuedSlavePort { private: @@ -74,6 +86,7 @@ class RubyPort : public MemObject virtual bool recvTiming(PacketPtr pkt); virtual Tick recvAtomic(PacketPtr pkt); virtual void recvFunctional(PacketPtr pkt); + virtual AddrRangeList getAddrRanges(); private: bool isPhysMemAddress(Addr addr); @@ -83,7 +96,7 @@ class RubyPort : public MemObject friend class M5Port; - class PioPort : public QueuedPort + class PioPort : public QueuedMasterPort { private: @@ -119,7 +132,8 @@ class RubyPort : public MemObject void init(); - Port *getPort(const std::string &if_name, int idx); + MasterPort &getMasterPort(const std::string &if_name, int idx); + SlavePort &getSlavePort(const std::string &if_name, int idx); virtual RequestStatus makeRequest(PacketPtr pkt) = 0; virtual int outstandingCount() const = 0; @@ -163,9 +177,10 @@ class RubyPort : public MemObject PioPort physMemPort; - /*! Vector of CPU Port attached to this Ruby port. */ + /** Vector of M5 Ports attached to this Ruby port. */ typedef std::vector<M5Port*>::iterator CpuPortIter; - std::vector<M5Port*> cpu_ports; + std::vector<M5Port*> slave_ports; + std::vector<PioPort*> master_ports; Event *drainEvent; diff --git a/src/mem/se_translating_port_proxy.cc b/src/mem/se_translating_port_proxy.cc index 2ab130744..72466655c 100644 --- a/src/mem/se_translating_port_proxy.cc +++ b/src/mem/se_translating_port_proxy.cc @@ -53,7 +53,7 @@ using namespace TheISA; -SETranslatingPortProxy::SETranslatingPortProxy(Port& port, Process *p, +SETranslatingPortProxy::SETranslatingPortProxy(MasterPort& port, Process *p, AllocType alloc) : PortProxy(port), pTable(p->pTable), process(p), allocating(alloc) diff --git a/src/mem/se_translating_port_proxy.hh b/src/mem/se_translating_port_proxy.hh index 31874e6b8..c0e522611 100644 --- a/src/mem/se_translating_port_proxy.hh +++ b/src/mem/se_translating_port_proxy.hh @@ -80,7 +80,7 @@ class SETranslatingPortProxy : public PortProxy AllocType allocating; public: - SETranslatingPortProxy(Port& port, Process* p, AllocType alloc); + SETranslatingPortProxy(MasterPort& port, Process* p, AllocType alloc); virtual ~SETranslatingPortProxy(); bool tryReadBlob(Addr addr, uint8_t *p, int size) const; diff --git a/src/mem/tport.cc b/src/mem/tport.cc index bf3d59a8f..db2c72bbc 100644 --- a/src/mem/tport.cc +++ b/src/mem/tport.cc @@ -46,7 +46,7 @@ SimpleTimingPort::SimpleTimingPort(const std::string& _name, MemObject* _owner) : - QueuedPort(_name, _owner, queue), queue(*_owner, *this) + QueuedSlavePort(_name, _owner, queue), queue(*_owner, *this) { } @@ -63,6 +63,9 @@ SimpleTimingPort::recvFunctional(PacketPtr pkt) bool SimpleTimingPort::recvTiming(PacketPtr pkt) { + // the port is a slave and should hence only get timing requests + assert(pkt->isRequest()); + if (pkt->memInhibitAsserted()) { // snooper will supply based on copy of packet // still target's responsibility to delete packet diff --git a/src/mem/tport.hh b/src/mem/tport.hh index c77166386..91706fbe9 100644 --- a/src/mem/tport.hh +++ b/src/mem/tport.hh @@ -57,7 +57,7 @@ * recvFunctional and recvTiming through recvAtomic. It is always a * slave port. */ -class SimpleTimingPort : public QueuedPort +class SimpleTimingPort : public QueuedSlavePort { protected: |