Merge zizzer.eecs.umich.edu:/bk/newmem
into zeep.eecs.umich.edu:/home/gblack/m5/newmem_bus --HG-- extra : convert_revision : 1749397443ccb320d32f8dd23c71ed0431d30cb7
This commit is contained in:
commit
63023ba4c2
4 changed files with 192 additions and 49 deletions
147
src/mem/bus.cc
147
src/mem/bus.cc
|
@ -67,6 +67,44 @@ Bus::init()
|
||||||
(*intIter)->sendStatusChange(Port::RangeChange);
|
(*intIter)->sendStatusChange(Port::RangeChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Bus::BusFreeEvent::process()
|
||||||
|
{
|
||||||
|
bus->recvRetry(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * Bus::BusFreeEvent::description()
|
||||||
|
{
|
||||||
|
return "bus became available";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Bus::occupyBus(int numCycles)
|
||||||
|
{
|
||||||
|
//Move up when the bus will next be free
|
||||||
|
//We avoid the use of divide by adding repeatedly
|
||||||
|
//This should be faster if the value is updated frequently, but should
|
||||||
|
//be may be slower otherwise.
|
||||||
|
|
||||||
|
//Bring tickNextIdle up to the present tick
|
||||||
|
//There is some potential ambiguity where a cycle starts, which might make
|
||||||
|
//a difference when devices are acting right around a cycle boundary. Using
|
||||||
|
//a < allows things which happen exactly on a cycle boundary to take up only
|
||||||
|
//the following cycle. Anthing that happens later will have to "wait" for the
|
||||||
|
//end of that cycle, and then start using the bus after that.
|
||||||
|
while (tickNextIdle < curTick)
|
||||||
|
tickNextIdle += clock;
|
||||||
|
//Advance it numCycles bus cycles.
|
||||||
|
//XXX Should this use the repeating add trick as well?
|
||||||
|
tickNextIdle += (numCycles * clock);
|
||||||
|
if (!busIdle.scheduled()) {
|
||||||
|
busIdle.schedule(tickNextIdle);
|
||||||
|
} else {
|
||||||
|
busIdle.reschedule(tickNextIdle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Function called by the port when the bus is receiving a Timing
|
/** Function called by the port when the bus is receiving a Timing
|
||||||
* transaction.*/
|
* transaction.*/
|
||||||
|
@ -77,52 +115,89 @@ Bus::recvTiming(Packet *pkt)
|
||||||
DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
|
DPRINTF(Bus, "recvTiming: 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());
|
||||||
|
|
||||||
short dest = pkt->getDest();
|
Port *pktPort = interfaces[pkt->getSrc()];
|
||||||
if (dest == Packet::Broadcast) {
|
|
||||||
if ( timingSnoopPhase1(pkt) )
|
// If the bus is busy, or other devices are in line ahead of the current one,
|
||||||
{
|
// put this device on the retry list.
|
||||||
timingSnoopPhase2(pkt);
|
if (tickNextIdle > curTick || (retryList.size() && pktPort != retryingPort)) {
|
||||||
port = findPort(pkt->getAddr(), pkt->getSrc());
|
addToRetryList(pktPort);
|
||||||
}
|
return false;
|
||||||
else
|
|
||||||
{
|
|
||||||
//Snoop didn't succeed
|
|
||||||
retryList.push_back(interfaces[pkt->getSrc()]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(dest >= 0 && dest < interfaces.size());
|
|
||||||
assert(dest != pkt->getSrc()); // catch infinite loops
|
|
||||||
port = interfaces[dest];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the bus is blocked, make the device wait.
|
||||||
|
if (!(port = findDestPort(pkt, pkt->getSrc()))) {
|
||||||
|
addToRetryList(pktPort);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The packet will be sent. Figure out how long it occupies the bus.
|
||||||
|
int numCycles = 0;
|
||||||
|
// Requests need one cycle to send an address
|
||||||
|
if (pkt->isRequest())
|
||||||
|
numCycles++;
|
||||||
|
else if (pkt->isResponse() || pkt->hasData()) {
|
||||||
|
// If a packet has data, it needs ceil(size/width) cycles to send it
|
||||||
|
// We're using the "adding instead of dividing" trick again here
|
||||||
|
if (pkt->hasData()) {
|
||||||
|
int dataSize = pkt->getSize();
|
||||||
|
for (int transmitted = 0; transmitted < dataSize;
|
||||||
|
transmitted += width) {
|
||||||
|
numCycles++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the packet didn't have data, it must have been a response.
|
||||||
|
// Those use the bus for one cycle to send their data.
|
||||||
|
numCycles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
occupyBus(numCycles);
|
||||||
|
|
||||||
if (port->sendTiming(pkt)) {
|
if (port->sendTiming(pkt)) {
|
||||||
// packet was successfully sent, just return true.
|
// Packet was successfully sent. Return true.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// packet not successfully sent
|
// Packet not successfully sent. Leave or put it on the retry list.
|
||||||
retryList.push_back(interfaces[pkt->getSrc()]);
|
addToRetryList(pktPort);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Bus::recvRetry(int id)
|
Bus::recvRetry(int id)
|
||||||
{
|
{
|
||||||
// Go through all the elements on the list calling sendRetry on each
|
//If there's anything waiting...
|
||||||
// This is not very efficient at all but it works. Ultimately we should end
|
if (retryList.size()) {
|
||||||
// up with something that is more intelligent.
|
retryingPort = retryList.front();
|
||||||
int initialSize = retryList.size();
|
retryingPort->sendRetry();
|
||||||
int i;
|
//If the retryingPort pointer isn't null, either sendTiming wasn't
|
||||||
Port *p;
|
//called, or it was and the packet was successfully sent.
|
||||||
|
if (retryingPort) {
|
||||||
for (i = 0; i < initialSize; i++) {
|
retryList.pop_front();
|
||||||
assert(retryList.size() > 0);
|
retryingPort = 0;
|
||||||
p = retryList.front();
|
}
|
||||||
retryList.pop_front();
|
|
||||||
p->sendRetry();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Port *
|
||||||
|
Bus::findDestPort(PacketPtr pkt, int id)
|
||||||
|
{
|
||||||
|
Port * port = NULL;
|
||||||
|
short dest = pkt->getDest();
|
||||||
|
|
||||||
|
if (dest == Packet::Broadcast) {
|
||||||
|
if (timingSnoopPhase1(pkt)) {
|
||||||
|
timingSnoopPhase2(pkt);
|
||||||
|
port = findPort(pkt->getAddr(), pkt->getSrc());
|
||||||
|
}
|
||||||
|
//else, port stays NULL
|
||||||
|
} else {
|
||||||
|
assert(dest >= 0 && dest < interfaces.size());
|
||||||
|
assert(dest != pkt->getSrc()); // catch infinite loops
|
||||||
|
port = interfaces[dest];
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
Port *
|
Port *
|
||||||
Bus::findPort(Addr addr, int id)
|
Bus::findPort(Addr addr, int id)
|
||||||
|
@ -381,16 +456,20 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
|
||||||
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
|
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
|
||||||
|
|
||||||
Param<int> bus_id;
|
Param<int> bus_id;
|
||||||
|
Param<int> clock;
|
||||||
|
Param<int> width;
|
||||||
|
|
||||||
END_DECLARE_SIM_OBJECT_PARAMS(Bus)
|
END_DECLARE_SIM_OBJECT_PARAMS(Bus)
|
||||||
|
|
||||||
BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
|
BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
|
||||||
INIT_PARAM(bus_id, "a globally unique bus id")
|
INIT_PARAM(bus_id, "a globally unique bus id"),
|
||||||
|
INIT_PARAM(clock, "bus clock speed"),
|
||||||
|
INIT_PARAM(width, "width of the bus (bits)")
|
||||||
END_INIT_SIM_OBJECT_PARAMS(Bus)
|
END_INIT_SIM_OBJECT_PARAMS(Bus)
|
||||||
|
|
||||||
CREATE_SIM_OBJECT(Bus)
|
CREATE_SIM_OBJECT(Bus)
|
||||||
{
|
{
|
||||||
return new Bus(getInstanceName(), bus_id);
|
return new Bus(getInstanceName(), bus_id, clock, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_SIM_OBJECT("Bus", Bus)
|
REGISTER_SIM_OBJECT("Bus", Bus)
|
||||||
|
|
|
@ -46,11 +46,18 @@
|
||||||
#include "mem/packet.hh"
|
#include "mem/packet.hh"
|
||||||
#include "mem/port.hh"
|
#include "mem/port.hh"
|
||||||
#include "mem/request.hh"
|
#include "mem/request.hh"
|
||||||
|
#include "sim/eventq.hh"
|
||||||
|
|
||||||
class Bus : public MemObject
|
class Bus : public MemObject
|
||||||
{
|
{
|
||||||
/** a globally unique id for this bus. */
|
/** a globally unique id for this bus. */
|
||||||
int busId;
|
int busId;
|
||||||
|
/** the clock speed for the bus */
|
||||||
|
int clock;
|
||||||
|
/** the width of the bus in bits */
|
||||||
|
int width;
|
||||||
|
/** the next tick at which the bus will be idle */
|
||||||
|
Tick tickNextIdle;
|
||||||
|
|
||||||
static const int defaultId = -1;
|
static const int defaultId = -1;
|
||||||
|
|
||||||
|
@ -93,6 +100,15 @@ class Bus : public MemObject
|
||||||
*/
|
*/
|
||||||
Port *findPort(Addr addr, int id);
|
Port *findPort(Addr addr, int id);
|
||||||
|
|
||||||
|
/** Finds the port a packet should be sent to. If the bus is blocked, no port
|
||||||
|
* is returned.
|
||||||
|
* @param pkt Packet to find a destination port for.
|
||||||
|
* @param id Id of the port this packet was received from
|
||||||
|
* (to prevent loops)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Port *findDestPort(PacketPtr pkt, int id);
|
||||||
|
|
||||||
/** Find all ports with a matching snoop range, except src port. Keep in mind
|
/** 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
|
* that the ranges shouldn't overlap or you will get a double snoop to the same
|
||||||
* interface.and the cache will assert out.
|
* interface.and the cache will assert out.
|
||||||
|
@ -181,6 +197,22 @@ class Bus : public MemObject
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BusFreeEvent : public Event
|
||||||
|
{
|
||||||
|
Bus * bus;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BusFreeEvent(Bus * _bus);
|
||||||
|
void process();
|
||||||
|
const char *description();
|
||||||
|
};
|
||||||
|
|
||||||
|
BusFreeEvent busIdle;
|
||||||
|
|
||||||
|
void occupyBus(int numCycles);
|
||||||
|
|
||||||
|
Port * retryingPort;
|
||||||
|
|
||||||
/** An array of pointers to the peer port interfaces
|
/** An array of pointers to the peer port interfaces
|
||||||
connected to this bus.*/
|
connected to this bus.*/
|
||||||
std::vector<Port*> interfaces;
|
std::vector<Port*> interfaces;
|
||||||
|
@ -189,6 +221,23 @@ class Bus : public MemObject
|
||||||
* original send failed for whatever reason.*/
|
* original send failed for whatever reason.*/
|
||||||
std::list<Port*> retryList;
|
std::list<Port*> retryList;
|
||||||
|
|
||||||
|
void addToRetryList(Port * port)
|
||||||
|
{
|
||||||
|
if (!retryingPort) {
|
||||||
|
// The device wasn't retrying a packet, or wasn't at an appropriate
|
||||||
|
// time.
|
||||||
|
retryList.push_back(port);
|
||||||
|
} else {
|
||||||
|
// The device was retrying a packet. It didn't work, so we'll leave
|
||||||
|
// it at the head of the retry list.
|
||||||
|
retryingPort = 0;
|
||||||
|
|
||||||
|
// We shouldn't be receiving a packet from one port when a different
|
||||||
|
// one is retrying.
|
||||||
|
assert(port == retryingPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Port that handles requests that don't match any of the interfaces.*/
|
/** Port that handles requests that don't match any of the interfaces.*/
|
||||||
Port *defaultPort;
|
Port *defaultPort;
|
||||||
|
|
||||||
|
@ -199,8 +248,14 @@ class Bus : public MemObject
|
||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
Bus(const std::string &n, int bus_id)
|
Bus(const std::string &n, int bus_id, int _clock, int _width)
|
||||||
: MemObject(n), busId(bus_id), defaultPort(NULL) {}
|
: MemObject(n), busId(bus_id), clock(_clock), width(_width),
|
||||||
|
tickNextIdle(0), busIdle(this), retryingPort(0), defaultPort(NULL)
|
||||||
|
{
|
||||||
|
//Both the width and clock period must be positive
|
||||||
|
assert(width);
|
||||||
|
assert(clock);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,6 @@ typedef std::list<PacketPtr> PacketList;
|
||||||
#define NO_ALLOCATE 1 << 5
|
#define NO_ALLOCATE 1 << 5
|
||||||
#define SNOOP_COMMIT 1 << 6
|
#define SNOOP_COMMIT 1 << 6
|
||||||
|
|
||||||
//For statistics we need max number of commands, hard code it at
|
|
||||||
//20 for now. @todo fix later
|
|
||||||
#define NUM_MEM_CMDS 1 << 9
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Packet is used to encapsulate a transfer between two objects in
|
* A Packet is used to encapsulate a transfer between two objects in
|
||||||
* the memory system (e.g., the L1 and L2 cache). (In contrast, a
|
* the memory system (e.g., the L1 and L2 cache). (In contrast, a
|
||||||
|
@ -164,6 +160,8 @@ class Packet
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** List of command attributes. */
|
/** List of command attributes. */
|
||||||
|
// If you add a new CommandAttribute, make sure to increase NUM_MEM_CMDS
|
||||||
|
// as well.
|
||||||
enum CommandAttribute
|
enum CommandAttribute
|
||||||
{
|
{
|
||||||
IsRead = 1 << 0,
|
IsRead = 1 << 0,
|
||||||
|
@ -174,30 +172,38 @@ class Packet
|
||||||
IsResponse = 1 << 5,
|
IsResponse = 1 << 5,
|
||||||
NeedsResponse = 1 << 6,
|
NeedsResponse = 1 << 6,
|
||||||
IsSWPrefetch = 1 << 7,
|
IsSWPrefetch = 1 << 7,
|
||||||
IsHWPrefetch = 1 << 8
|
IsHWPrefetch = 1 << 8,
|
||||||
|
HasData = 1 << 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//For statistics we need max number of commands, hard code it at
|
||||||
|
//20 for now. @todo fix later
|
||||||
|
#define NUM_MEM_CMDS 1 << 10
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** List of all commands associated with a packet. */
|
/** List of all commands associated with a packet. */
|
||||||
enum Command
|
enum Command
|
||||||
{
|
{
|
||||||
InvalidCmd = 0,
|
InvalidCmd = 0,
|
||||||
ReadReq = IsRead | IsRequest | NeedsResponse,
|
ReadReq = IsRead | IsRequest | NeedsResponse,
|
||||||
WriteReq = IsWrite | IsRequest | NeedsResponse,
|
WriteReq = IsWrite | IsRequest | NeedsResponse | HasData,
|
||||||
WriteReqNoAck = IsWrite | IsRequest,
|
WriteReqNoAck = IsWrite | IsRequest | HasData,
|
||||||
ReadResp = IsRead | IsResponse | NeedsResponse,
|
ReadResp = IsRead | IsResponse | NeedsResponse | HasData,
|
||||||
WriteResp = IsWrite | IsResponse | NeedsResponse,
|
WriteResp = IsWrite | IsResponse | NeedsResponse,
|
||||||
Writeback = IsWrite | IsRequest,
|
Writeback = IsWrite | IsRequest | HasData,
|
||||||
SoftPFReq = IsRead | IsRequest | IsSWPrefetch | NeedsResponse,
|
SoftPFReq = IsRead | IsRequest | IsSWPrefetch | NeedsResponse,
|
||||||
HardPFReq = IsRead | IsRequest | IsHWPrefetch | NeedsResponse,
|
HardPFReq = IsRead | IsRequest | IsHWPrefetch | NeedsResponse,
|
||||||
SoftPFResp = IsRead | IsResponse | IsSWPrefetch | NeedsResponse,
|
SoftPFResp = IsRead | IsResponse | IsSWPrefetch
|
||||||
HardPFResp = IsRead | IsResponse | IsHWPrefetch | NeedsResponse,
|
| NeedsResponse | HasData,
|
||||||
|
HardPFResp = IsRead | IsResponse | IsHWPrefetch
|
||||||
|
| NeedsResponse | HasData,
|
||||||
InvalidateReq = IsInvalidate | IsRequest,
|
InvalidateReq = IsInvalidate | IsRequest,
|
||||||
WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest,
|
WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest | HasData,
|
||||||
UpgradeReq = IsInvalidate | IsRequest | NeedsResponse,
|
UpgradeReq = IsInvalidate | IsRequest | NeedsResponse,
|
||||||
UpgradeResp = IsInvalidate | IsResponse | NeedsResponse,
|
UpgradeResp = IsInvalidate | IsResponse | NeedsResponse,
|
||||||
ReadExReq = IsRead | IsInvalidate | IsRequest | NeedsResponse,
|
ReadExReq = IsRead | IsInvalidate | IsRequest | NeedsResponse,
|
||||||
ReadExResp = IsRead | IsInvalidate | IsResponse | NeedsResponse
|
ReadExResp = IsRead | IsInvalidate | IsResponse
|
||||||
|
| NeedsResponse | HasData
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Return the string name of the cmd field (for debugging and
|
/** Return the string name of the cmd field (for debugging and
|
||||||
|
@ -219,6 +225,7 @@ class Packet
|
||||||
bool isResponse() { return (cmd & IsResponse) != 0; }
|
bool isResponse() { return (cmd & IsResponse) != 0; }
|
||||||
bool needsResponse() { return (cmd & NeedsResponse) != 0; }
|
bool needsResponse() { return (cmd & NeedsResponse) != 0; }
|
||||||
bool isInvalidate() { return (cmd & IsInvalidate) != 0; }
|
bool isInvalidate() { return (cmd & IsInvalidate) != 0; }
|
||||||
|
bool hasData() { return (cmd & HasData) != 0; }
|
||||||
|
|
||||||
bool isCacheFill() { return (flags & CACHE_LINE_FILL) != 0; }
|
bool isCacheFill() { return (flags & CACHE_LINE_FILL) != 0; }
|
||||||
bool isNoAllocate() { return (flags & NO_ALLOCATE) != 0; }
|
bool isNoAllocate() { return (flags & NO_ALLOCATE) != 0; }
|
||||||
|
|
|
@ -6,3 +6,5 @@ class Bus(MemObject):
|
||||||
port = VectorPort("vector port for connecting devices")
|
port = VectorPort("vector port for connecting devices")
|
||||||
default = Port("Default port for requests that aren't handeled by a device.")
|
default = Port("Default port for requests that aren't handeled by a device.")
|
||||||
bus_id = Param.Int(0, "blah")
|
bus_id = Param.Int(0, "blah")
|
||||||
|
clock = Param.Clock("1GHz", "bus clock speed")
|
||||||
|
width = Param.Int(64, "bus width (bits)")
|
||||||
|
|
Loading…
Reference in a new issue