MEM: Make the bus default port yet another port
This patch removes the idiosyncratic nature of the default bus port and makes it yet another port in the list of interfaces. Rather than having a specific pointer to the default port we merely track the identifier of this port. This change makes future port diversification easier and overall cleans up the bus code.
This commit is contained in:
parent
55cf3f4ac1
commit
acd289b7ef
2 changed files with 35 additions and 125 deletions
|
@ -38,6 +38,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Ali Saidi
|
||||
* Andreas Hansson
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -45,9 +46,6 @@
|
|||
* Definition of a bus object.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "debug/Bus.hh"
|
||||
|
@ -58,8 +56,7 @@
|
|||
Bus::Bus(const BusParams *p)
|
||||
: MemObject(p), busId(p->bus_id), clock(p->clock),
|
||||
headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
|
||||
drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
|
||||
defaultPort(NULL),
|
||||
drainEvent(NULL), busIdle(this), inRetry(false), defaultPortId(-1),
|
||||
useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
|
||||
cachedBlockSize(0), cachedBlockSizeValid(false)
|
||||
{
|
||||
|
@ -70,28 +67,25 @@ Bus::Bus(const BusParams *p)
|
|||
fatal("Bus clock period must be positive\n");
|
||||
if (headerCycles <= 0)
|
||||
fatal("Number of header cycles must be positive\n");
|
||||
clearBusCache();
|
||||
clearPortCache();
|
||||
}
|
||||
|
||||
Port *
|
||||
Bus::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
std::string portName;
|
||||
int id = interfaces.size();
|
||||
if (if_name == "default") {
|
||||
if (defaultPort == NULL) {
|
||||
defaultPort = new BusPort(csprintf("%s-default",name()), this,
|
||||
defaultId);
|
||||
cachedBlockSizeValid = false;
|
||||
return defaultPort;
|
||||
if (defaultPortId == -1) {
|
||||
defaultPortId = id;
|
||||
portName = csprintf("%s-default", name());
|
||||
} else
|
||||
fatal("Default port already set\n");
|
||||
fatal("Default port already set on %s\n", name());
|
||||
} else {
|
||||
portName = csprintf("%s-p%d", name(), id);
|
||||
}
|
||||
int id;
|
||||
// if_name ignored? forced to be empty?
|
||||
id = maxId++;
|
||||
assert(maxId < std::numeric_limits<typeof(maxId)>::max());
|
||||
BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
|
||||
interfaces[id] = bp;
|
||||
BusPort *bp = new BusPort(portName, this, id);
|
||||
interfaces.push_back(bp);
|
||||
cachedBlockSizeValid = false;
|
||||
return bp;
|
||||
}
|
||||
|
@ -99,16 +93,16 @@ Bus::getPort(const std::string &if_name, int idx)
|
|||
void
|
||||
Bus::init()
|
||||
{
|
||||
m5::hash_map<short,BusPort*>::iterator intIter;
|
||||
std::vector<BusPort*>::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();
|
||||
intIter++) {
|
||||
if (intIter->second->getPeer()->isSnooping()) {
|
||||
if ((*intIter)->getPeer()->isSnooping()) {
|
||||
DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
|
||||
intIter->second->getPeer()->name());
|
||||
snoopPorts.push_back(intIter->second);
|
||||
(*intIter)->getPeer()->name());
|
||||
snoopPorts.push_back(*intIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,16 +182,7 @@ Bus::recvTiming(PacketPtr pkt)
|
|||
{
|
||||
short src = pkt->getSrc();
|
||||
|
||||
BusPort *src_port;
|
||||
if (src == defaultId)
|
||||
src_port = defaultPort;
|
||||
else {
|
||||
src_port = checkBusCache(src);
|
||||
if (src_port == NULL) {
|
||||
src_port = interfaces[src];
|
||||
updateBusCache(src, src_port);
|
||||
}
|
||||
}
|
||||
BusPort *src_port = interfaces[src];
|
||||
|
||||
// If the bus is busy, or other devices are in line ahead of the current
|
||||
// one, put this device on the retry list.
|
||||
|
@ -223,8 +208,7 @@ Bus::recvTiming(PacketPtr pkt)
|
|||
|
||||
if (dest == Packet::Broadcast) {
|
||||
dest_port_id = findPort(pkt->getAddr());
|
||||
dest_port = (dest_port_id == defaultId) ?
|
||||
defaultPort : interfaces[dest_port_id];
|
||||
dest_port = interfaces[dest_port_id];
|
||||
SnoopIter s_end = snoopPorts.end();
|
||||
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
|
||||
BusPort *p = *s_iter;
|
||||
|
@ -235,20 +219,10 @@ Bus::recvTiming(PacketPtr pkt)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
assert(dest < maxId);
|
||||
assert(dest < interfaces.size());
|
||||
assert(dest != src); // catch infinite loops
|
||||
dest_port_id = dest;
|
||||
if (dest_port_id == defaultId)
|
||||
dest_port = defaultPort;
|
||||
else {
|
||||
dest_port = checkBusCache(dest);
|
||||
if (dest_port == NULL) {
|
||||
dest_port = interfaces[dest_port_id];
|
||||
// updateBusCache(dest_port_id, dest_port);
|
||||
}
|
||||
}
|
||||
dest_port = (dest_port_id == defaultId) ?
|
||||
defaultPort : interfaces[dest_port_id];
|
||||
dest_port = interfaces[dest_port_id];
|
||||
}
|
||||
|
||||
if (dest_port_id == src) {
|
||||
|
@ -346,7 +320,7 @@ Bus::findPort(Addr addr)
|
|||
for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
|
||||
if (*i == addr) {
|
||||
DPRINTF(Bus, " found addr %#llx on default\n", addr);
|
||||
return defaultId;
|
||||
return defaultPortId;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +329,7 @@ Bus::findPort(Addr addr)
|
|||
|
||||
DPRINTF(Bus, "Unable to find destination for addr %#llx, "
|
||||
"will use default port\n", addr);
|
||||
return defaultId;
|
||||
return defaultPortId;
|
||||
}
|
||||
|
||||
|
||||
|
@ -379,16 +353,7 @@ Bus::recvAtomic(PacketPtr pkt)
|
|||
int orig_src = pkt->getSrc();
|
||||
|
||||
int target_port_id = findPort(pkt->getAddr());
|
||||
BusPort *target_port;
|
||||
if (target_port_id == defaultId)
|
||||
target_port = defaultPort;
|
||||
else {
|
||||
target_port = checkBusCache(target_port_id);
|
||||
if (target_port == NULL) {
|
||||
target_port = interfaces[target_port_id];
|
||||
updateBusCache(target_port_id, target_port);
|
||||
}
|
||||
}
|
||||
BusPort *target_port = interfaces[target_port_id];
|
||||
|
||||
SnoopIter s_end = snoopPorts.end();
|
||||
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
|
||||
|
@ -444,7 +409,7 @@ Bus::recvFunctional(PacketPtr pkt)
|
|||
assert(pkt->getDest() == Packet::Broadcast);
|
||||
|
||||
int port_id = findPort(pkt->getAddr());
|
||||
Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
|
||||
Port *port = interfaces[port_id];
|
||||
// The packet may be changed by another bus on snoops, restore the
|
||||
// id after each
|
||||
int src_id = pkt->getSrc();
|
||||
|
@ -491,11 +456,11 @@ Bus::recvRangeChange(int id)
|
|||
DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
|
||||
|
||||
clearPortCache();
|
||||
if (id == defaultId) {
|
||||
if (id == defaultPortId) {
|
||||
defaultRange.clear();
|
||||
// Only try to update these ranges if the user set a default responder.
|
||||
if (useDefaultRange) {
|
||||
AddrRangeList ranges = defaultPort->getPeer()->getAddrRanges();
|
||||
AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges();
|
||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||
defaultRange.push_back(*iter);
|
||||
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
|
||||
|
@ -504,7 +469,7 @@ Bus::recvRangeChange(int id)
|
|||
}
|
||||
} else {
|
||||
|
||||
assert((id < maxId && id >= 0) || id == defaultId);
|
||||
assert(id < interfaces.size() && id >= 0);
|
||||
BusPort *port = interfaces[id];
|
||||
|
||||
// Clean out any previously existent ids
|
||||
|
@ -533,14 +498,12 @@ 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
|
||||
m5::hash_map<short,BusPort*>::iterator intIter;
|
||||
std::vector<BusPort*>::const_iterator intIter;
|
||||
|
||||
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
|
||||
if (intIter->first != id)
|
||||
intIter->second->sendRangeChange();
|
||||
if ((*intIter)->getId() != id)
|
||||
(*intIter)->sendRangeChange();
|
||||
|
||||
if (id != defaultId && defaultPort)
|
||||
defaultPort->sendRangeChange();
|
||||
inRecvRangeChange.erase(id);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
*
|
||||
* Authors: Ron Dreslinski
|
||||
* Ali Saidi
|
||||
* Andreas Hansson
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -91,7 +92,7 @@ class Bus : public MemObject
|
|||
void onRetryList(bool newVal)
|
||||
{ _onRetryList = newVal; }
|
||||
|
||||
int getId() { return id; }
|
||||
int getId() const { return id; }
|
||||
|
||||
/**
|
||||
* Determine if this port should be considered a snooper. This
|
||||
|
@ -167,9 +168,6 @@ class Bus : public MemObject
|
|||
|
||||
Event * drainEvent;
|
||||
|
||||
|
||||
static const int defaultId = -3; //Make it unique from Broadcast
|
||||
|
||||
typedef range_map<Addr,int>::iterator PortIter;
|
||||
range_map<Addr, int> portMap;
|
||||
|
||||
|
@ -297,12 +295,9 @@ class Bus : public MemObject
|
|||
bool inRetry;
|
||||
std::set<int> inRecvRangeChange;
|
||||
|
||||
/** max number of bus ids we've handed out so far */
|
||||
short maxId;
|
||||
|
||||
/** An array of pointers to the peer port interfaces
|
||||
/** An ordered vector of pointers to the peer port interfaces
|
||||
connected to this bus.*/
|
||||
m5::hash_map<short,BusPort*> interfaces;
|
||||
std::vector<BusPort*> interfaces;
|
||||
|
||||
/** An array of pointers to ports that retry should be called on because the
|
||||
* original send failed for whatever reason.*/
|
||||
|
@ -331,7 +326,7 @@ class Bus : public MemObject
|
|||
}
|
||||
|
||||
/** Port that handles requests that don't match any of the interfaces.*/
|
||||
BusPort *defaultPort;
|
||||
short defaultPortId;
|
||||
|
||||
/** If true, use address range provided by default device. Any
|
||||
address not handled by another port and not in default device's
|
||||
|
@ -343,54 +338,6 @@ class Bus : public MemObject
|
|||
unsigned cachedBlockSize;
|
||||
bool cachedBlockSizeValid;
|
||||
|
||||
// Cache for the peer port interfaces
|
||||
struct BusCache {
|
||||
bool valid;
|
||||
short id;
|
||||
BusPort *port;
|
||||
};
|
||||
|
||||
BusCache busCache[3];
|
||||
|
||||
// Checks the peer port interfaces cache for the port id and returns
|
||||
// a pointer to the matching port
|
||||
inline BusPort* checkBusCache(short id) {
|
||||
if (busCache[0].valid && id == busCache[0].id) {
|
||||
return busCache[0].port;
|
||||
}
|
||||
if (busCache[1].valid && id == busCache[1].id) {
|
||||
return busCache[1].port;
|
||||
}
|
||||
if (busCache[2].valid && id == busCache[2].id) {
|
||||
return busCache[2].port;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Replaces the earliest entry in the cache with a new entry
|
||||
inline void updateBusCache(short id, BusPort *port) {
|
||||
busCache[2].valid = busCache[1].valid;
|
||||
busCache[2].id = busCache[1].id;
|
||||
busCache[2].port = busCache[1].port;
|
||||
|
||||
busCache[1].valid = busCache[0].valid;
|
||||
busCache[1].id = busCache[0].id;
|
||||
busCache[1].port = busCache[0].port;
|
||||
|
||||
busCache[0].valid = true;
|
||||
busCache[0].id = id;
|
||||
busCache[0].port = port;
|
||||
}
|
||||
|
||||
// Invalidates the cache. Needs to be called in constructor.
|
||||
inline void clearBusCache() {
|
||||
busCache[2].valid = false;
|
||||
busCache[1].valid = false;
|
||||
busCache[0].valid = false;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** A function used to return the port associated with this bus object. */
|
||||
|
|
Loading…
Reference in a new issue