summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/bridge.cc45
-rw-r--r--src/mem/bridge.hh21
-rw-r--r--src/mem/bus.cc117
-rw-r--r--src/mem/bus.hh103
-rw-r--r--src/mem/cache/base.cc25
-rw-r--r--src/mem/cache/base.hh11
-rw-r--r--src/mem/cache/builder.cc1
-rw-r--r--src/mem/cache/cache.hh2
-rw-r--r--src/mem/cache/cache_impl.hh15
-rw-r--r--src/mem/fs_translating_port_proxy.cc2
-rw-r--r--src/mem/fs_translating_port_proxy.hh2
-rw-r--r--src/mem/mem_object.cc25
-rw-r--r--src/mem/mem_object.hh43
-rw-r--r--src/mem/mport.cc17
-rw-r--r--src/mem/mport.hh41
-rw-r--r--src/mem/physical.cc23
-rw-r--r--src/mem/physical.hh4
-rw-r--r--src/mem/port.cc105
-rw-r--r--src/mem/port.hh267
-rw-r--r--src/mem/port_proxy.hh4
-rw-r--r--src/mem/qport.hh50
-rw-r--r--src/mem/ruby/system/RubyPort.cc137
-rw-r--r--src/mem/ruby/system/RubyPort.hh25
-rw-r--r--src/mem/se_translating_port_proxy.cc2
-rw-r--r--src/mem/se_translating_port_proxy.hh2
-rw-r--r--src/mem/tport.cc5
-rw-r--r--src/mem/tport.hh2
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: