Commiting a version of the multi-phase snoop atomic bus so people can see the framework. Doesn't work, but also doesn't break uni-processor systems.
Working on pulling out the changes in the cache so that it remains working. src/mem/bus.cc: Changes for multi-phase snoop Some code for registering snoop ranges (a version that compiles and runs, but does nothing) src/mem/bus.hh: Changes for multi-phase snoop src/mem/packet.hh: Flag for multi-phase snoop src/mem/port.hh: Status for multi-phase snoop --HG-- extra : convert_revision : 4c2e5263bba16e3bcf03aabe36ff45ec36de4720
This commit is contained in:
parent
3a45e9b8cb
commit
9f18764441
4 changed files with 131 additions and 5 deletions
104
src/mem/bus.cc
104
src/mem/bus.cc
|
@ -79,7 +79,17 @@ Bus::recvTiming(Packet *pkt)
|
||||||
|
|
||||||
short dest = pkt->getDest();
|
short dest = pkt->getDest();
|
||||||
if (dest == Packet::Broadcast) {
|
if (dest == Packet::Broadcast) {
|
||||||
|
if ( timingSnoopPhase1(pkt) )
|
||||||
|
{
|
||||||
|
timingSnoopPhase2(pkt);
|
||||||
port = findPort(pkt->getAddr(), pkt->getSrc());
|
port = findPort(pkt->getAddr(), pkt->getSrc());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Snoop didn't succeed
|
||||||
|
retryList.push_back(interfaces[pkt->getSrc()]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(dest >= 0 && dest < interfaces.size());
|
assert(dest >= 0 && dest < interfaces.size());
|
||||||
assert(dest != pkt->getSrc()); // catch infinite loops
|
assert(dest != pkt->getSrc()); // catch infinite loops
|
||||||
|
@ -151,6 +161,77 @@ Bus::findPort(Addr addr, int id)
|
||||||
return interfaces[dest_id];
|
return interfaces[dest_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int>
|
||||||
|
Bus::findSnoopPorts(Addr addr, int id)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
AddrRangeIter iter;
|
||||||
|
std::vector<int> ports;
|
||||||
|
|
||||||
|
while (i < portSnoopList.size())
|
||||||
|
{
|
||||||
|
if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
|
||||||
|
//Careful to not overlap ranges
|
||||||
|
//or snoop will be called more than once on the port
|
||||||
|
ports.push_back(portSnoopList[i].portId);
|
||||||
|
DPRINTF(Bus, " found snoop addr 0x%llx on device%d\n", addr,
|
||||||
|
portSnoopList[i].portId);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Bus::atomicSnoop(Packet *pkt)
|
||||||
|
{
|
||||||
|
std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
|
||||||
|
|
||||||
|
while (!ports.empty())
|
||||||
|
{
|
||||||
|
interfaces[ports.back()]->sendAtomic(pkt);
|
||||||
|
ports.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Bus::timingSnoopPhase1(Packet *pkt)
|
||||||
|
{
|
||||||
|
std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
while (!ports.empty() && success)
|
||||||
|
{
|
||||||
|
snoopCallbacks.push_back(ports.back());
|
||||||
|
success = interfaces[ports.back()]->sendTiming(pkt);
|
||||||
|
ports.pop_back();
|
||||||
|
}
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
while (!snoopCallbacks.empty())
|
||||||
|
{
|
||||||
|
interfaces[snoopCallbacks.back()]->sendStatusChange(Port::SnoopSquash);
|
||||||
|
snoopCallbacks.pop_back();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Bus::timingSnoopPhase2(Packet *pkt)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
pkt->flags |= SNOOP_COMMIT;
|
||||||
|
while (!snoopCallbacks.empty())
|
||||||
|
{
|
||||||
|
success = interfaces[snoopCallbacks.back()]->sendTiming(pkt);
|
||||||
|
//We should not fail on snoop callbacks
|
||||||
|
assert(success);
|
||||||
|
snoopCallbacks.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Function called by the port when the bus is receiving a Atomic
|
/** Function called by the port when the bus is receiving a Atomic
|
||||||
* transaction.*/
|
* transaction.*/
|
||||||
Tick
|
Tick
|
||||||
|
@ -159,6 +240,7 @@ Bus::recvAtomic(Packet *pkt)
|
||||||
DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
|
DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
|
||||||
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
|
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
|
||||||
assert(pkt->getDest() == Packet::Broadcast);
|
assert(pkt->getDest() == Packet::Broadcast);
|
||||||
|
atomicSnoop(pkt);
|
||||||
return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
|
return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +275,7 @@ Bus::recvStatusChange(Port::Status status, int id)
|
||||||
assert(snoops.size() == 0);
|
assert(snoops.size() == 0);
|
||||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||||
defaultRange.push_back(*iter);
|
defaultRange.push_back(*iter);
|
||||||
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default\n",
|
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default range\n",
|
||||||
iter->start, iter->end);
|
iter->start, iter->end);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,6 +283,7 @@ Bus::recvStatusChange(Port::Status status, int id)
|
||||||
assert((id < interfaces.size() && id >= 0) || id == -1);
|
assert((id < interfaces.size() && id >= 0) || id == -1);
|
||||||
Port *port = interfaces[id];
|
Port *port = interfaces[id];
|
||||||
std::vector<DevMap>::iterator portIter;
|
std::vector<DevMap>::iterator portIter;
|
||||||
|
std::vector<DevMap>::iterator snoopIter;
|
||||||
|
|
||||||
// Clean out any previously existent ids
|
// Clean out any previously existent ids
|
||||||
for (portIter = portList.begin(); portIter != portList.end(); ) {
|
for (portIter = portList.begin(); portIter != portList.end(); ) {
|
||||||
|
@ -210,10 +293,25 @@ Bus::recvStatusChange(Port::Status status, int id)
|
||||||
portIter++;
|
portIter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
|
||||||
|
if (snoopIter->portId == id)
|
||||||
|
snoopIter = portSnoopList.erase(snoopIter);
|
||||||
|
else
|
||||||
|
snoopIter++;
|
||||||
|
}
|
||||||
|
|
||||||
port->getPeerAddressRanges(ranges, snoops);
|
port->getPeerAddressRanges(ranges, snoops);
|
||||||
|
|
||||||
// not dealing with snooping yet either
|
for(iter = snoops.begin(); iter != snoops.end(); iter++) {
|
||||||
assert(snoops.size() == 0);
|
DevMap dm;
|
||||||
|
dm.portId = id;
|
||||||
|
dm.range = *iter;
|
||||||
|
|
||||||
|
DPRINTF(BusAddrRanges, "Adding snoop range %llx - %llx for id %d\n",
|
||||||
|
dm.range.start, dm.range.end, id);
|
||||||
|
portSnoopList.push_back(dm);
|
||||||
|
}
|
||||||
|
|
||||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||||
DevMap dm;
|
DevMap dm;
|
||||||
dm.portId = id;
|
dm.portId = id;
|
||||||
|
|
|
@ -60,6 +60,9 @@ class Bus : public MemObject
|
||||||
};
|
};
|
||||||
std::vector<DevMap> portList;
|
std::vector<DevMap> portList;
|
||||||
AddrRangeList defaultRange;
|
AddrRangeList defaultRange;
|
||||||
|
std::vector<DevMap> portSnoopList;
|
||||||
|
|
||||||
|
std::vector<int> snoopCallbacks;
|
||||||
|
|
||||||
|
|
||||||
/** Function called by the port when the bus is recieving a Timing
|
/** Function called by the port when the bus is recieving a Timing
|
||||||
|
@ -90,6 +93,29 @@ class Bus : public MemObject
|
||||||
*/
|
*/
|
||||||
Port *findPort(Addr addr, int id);
|
Port *findPort(Addr addr, int id);
|
||||||
|
|
||||||
|
/** Find all ports with a matching snoop range, except src port. Keep in mind
|
||||||
|
* that the ranges shouldn't overlap or you will get a double snoop to the same
|
||||||
|
* interface.and the cache will assert out.
|
||||||
|
* @param addr Address to find snoop prts for.
|
||||||
|
* @param id Id of the src port of the request to avoid calling snoop on src
|
||||||
|
* @return vector of IDs to snoop on
|
||||||
|
*/
|
||||||
|
std::vector<int> findSnoopPorts(Addr addr, int id);
|
||||||
|
|
||||||
|
/** Snoop all relevant ports atomicly. */
|
||||||
|
void atomicSnoop(Packet *pkt);
|
||||||
|
|
||||||
|
/** Snoop for NACK and Blocked in phase 1
|
||||||
|
* @return True if succeds.
|
||||||
|
*/
|
||||||
|
bool timingSnoopPhase1(Packet *pkt);
|
||||||
|
|
||||||
|
/** @todo Don't need to commit all snoops just those that need it
|
||||||
|
*(register somehow). */
|
||||||
|
/** Commit all snoops now that we know if any of them would have blocked.
|
||||||
|
*/
|
||||||
|
void timingSnoopPhase2(Packet *pkt);
|
||||||
|
|
||||||
/** Process address range request.
|
/** Process address range request.
|
||||||
* @param resp addresses that we can respond to
|
* @param resp addresses that we can respond to
|
||||||
* @param snoop addresses that we would like to snoop
|
* @param snoop addresses that we would like to snoop
|
||||||
|
|
|
@ -56,6 +56,7 @@ typedef std::list<PacketPtr> PacketList;
|
||||||
#define CACHE_LINE_FILL 1 << 3
|
#define CACHE_LINE_FILL 1 << 3
|
||||||
#define COMPRESSED 1 << 4
|
#define COMPRESSED 1 << 4
|
||||||
#define NO_ALLOCATE 1 << 5
|
#define NO_ALLOCATE 1 << 5
|
||||||
|
#define SNOOP_COMMIT 1 << 6
|
||||||
|
|
||||||
//For statistics we need max number of commands, hard code it at
|
//For statistics we need max number of commands, hard code it at
|
||||||
//20 for now. @todo fix later
|
//20 for now. @todo fix later
|
||||||
|
|
|
@ -106,7 +106,8 @@ class Port
|
||||||
/** Holds the ports status. Currently just that a range recomputation needs
|
/** Holds the ports status. Currently just that a range recomputation needs
|
||||||
* to be done. */
|
* to be done. */
|
||||||
enum Status {
|
enum Status {
|
||||||
RangeChange
|
RangeChange,
|
||||||
|
SnoopSquash
|
||||||
};
|
};
|
||||||
|
|
||||||
void setName(const std::string &name)
|
void setName(const std::string &name)
|
||||||
|
|
Loading…
Reference in a new issue