summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2006-10-08 14:09:13 -0400
committerGabe Black <gblack@eecs.umich.edu>2006-10-08 14:09:13 -0400
commit63023ba4c21e293e93d799815b94f41024da0f97 (patch)
tree5a0d9a9f72f761a55d71953146035d33a9e2807c /src/mem
parentc2f954ac692e664ba105f94c64c8c408cf1b4380 (diff)
parent00481d1f192c832d654379c2296d5b6020c12b1a (diff)
downloadgem5-63023ba4c21e293e93d799815b94f41024da0f97.tar.xz
Merge zizzer.eecs.umich.edu:/bk/newmem
into zeep.eecs.umich.edu:/home/gblack/m5/newmem_bus --HG-- extra : convert_revision : 1749397443ccb320d32f8dd23c71ed0431d30cb7
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/bus.cc145
-rw-r--r--src/mem/bus.hh59
-rw-r--r--src/mem/packet.hh33
3 files changed, 189 insertions, 48 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index 3c5283a77..2a38cb635 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -67,6 +67,44 @@ Bus::init()
(*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
* transaction.*/
@@ -77,52 +115,89 @@ Bus::recvTiming(Packet *pkt)
DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
- short dest = pkt->getDest();
- if (dest == Packet::Broadcast) {
- if ( timingSnoopPhase1(pkt) )
- {
- timingSnoopPhase2(pkt);
- port = findPort(pkt->getAddr(), pkt->getSrc());
- }
- else
- {
- //Snoop didn't succeed
- retryList.push_back(interfaces[pkt->getSrc()]);
- return false;
+ Port *pktPort = interfaces[pkt->getSrc()];
+
+ // If the bus is busy, or other devices are in line ahead of the current one,
+ // put this device on the retry list.
+ if (tickNextIdle > curTick || (retryList.size() && pktPort != retryingPort)) {
+ addToRetryList(pktPort);
+ return false;
+ }
+
+ // 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++;
}
- } else {
- assert(dest >= 0 && dest < interfaces.size());
- assert(dest != pkt->getSrc()); // catch infinite loops
- port = interfaces[dest];
}
+
+ occupyBus(numCycles);
+
if (port->sendTiming(pkt)) {
- // packet was successfully sent, just return true.
+ // Packet was successfully sent. Return true.
return true;
}
- // packet not successfully sent
- retryList.push_back(interfaces[pkt->getSrc()]);
+ // Packet not successfully sent. Leave or put it on the retry list.
+ addToRetryList(pktPort);
return false;
}
void
Bus::recvRetry(int id)
{
- // Go through all the elements on the list calling sendRetry on each
- // This is not very efficient at all but it works. Ultimately we should end
- // up with something that is more intelligent.
- int initialSize = retryList.size();
- int i;
- Port *p;
-
- for (i = 0; i < initialSize; i++) {
- assert(retryList.size() > 0);
- p = retryList.front();
- retryList.pop_front();
- p->sendRetry();
+ //If there's anything waiting...
+ if (retryList.size()) {
+ retryingPort = retryList.front();
+ retryingPort->sendRetry();
+ //If the retryingPort pointer isn't null, either sendTiming wasn't
+ //called, or it was and the packet was successfully sent.
+ if (retryingPort) {
+ retryList.pop_front();
+ retryingPort = 0;
+ }
}
}
+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 *
Bus::findPort(Addr addr, int id)
@@ -381,16 +456,20 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
Param<int> bus_id;
+ Param<int> clock;
+ Param<int> width;
END_DECLARE_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)
CREATE_SIM_OBJECT(Bus)
{
- return new Bus(getInstanceName(), bus_id);
+ return new Bus(getInstanceName(), bus_id, clock, width);
}
REGISTER_SIM_OBJECT("Bus", Bus)
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index 941389296..96f1152a6 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -46,11 +46,18 @@
#include "mem/packet.hh"
#include "mem/port.hh"
#include "mem/request.hh"
+#include "sim/eventq.hh"
class Bus : public MemObject
{
/** a globally unique id for this bus. */
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;
@@ -93,6 +100,15 @@ class Bus : public MemObject
*/
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
* that the ranges shouldn't overlap or you will get a double snoop to the same
* 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
connected to this bus.*/
std::vector<Port*> interfaces;
@@ -189,6 +221,23 @@ class Bus : public MemObject
* original send failed for whatever reason.*/
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 *defaultPort;
@@ -199,8 +248,14 @@ class Bus : public MemObject
virtual void init();
- Bus(const std::string &n, int bus_id)
- : MemObject(n), busId(bus_id), defaultPort(NULL) {}
+ Bus(const std::string &n, int bus_id, int _clock, int _width)
+ : 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);
+ }
};
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index be9bf5f57..5c513ae7a 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -58,10 +58,6 @@ typedef std::list<PacketPtr> PacketList;
#define NO_ALLOCATE 1 << 5
#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
* the memory system (e.g., the L1 and L2 cache). (In contrast, a
@@ -164,6 +160,8 @@ class Packet
private:
/** List of command attributes. */
+ // If you add a new CommandAttribute, make sure to increase NUM_MEM_CMDS
+ // as well.
enum CommandAttribute
{
IsRead = 1 << 0,
@@ -174,30 +172,38 @@ class Packet
IsResponse = 1 << 5,
NeedsResponse = 1 << 6,
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:
/** List of all commands associated with a packet. */
enum Command
{
InvalidCmd = 0,
ReadReq = IsRead | IsRequest | NeedsResponse,
- WriteReq = IsWrite | IsRequest | NeedsResponse,
- WriteReqNoAck = IsWrite | IsRequest,
- ReadResp = IsRead | IsResponse | NeedsResponse,
+ WriteReq = IsWrite | IsRequest | NeedsResponse | HasData,
+ WriteReqNoAck = IsWrite | IsRequest | HasData,
+ ReadResp = IsRead | IsResponse | NeedsResponse | HasData,
WriteResp = IsWrite | IsResponse | NeedsResponse,
- Writeback = IsWrite | IsRequest,
+ Writeback = IsWrite | IsRequest | HasData,
SoftPFReq = IsRead | IsRequest | IsSWPrefetch | NeedsResponse,
HardPFReq = IsRead | IsRequest | IsHWPrefetch | NeedsResponse,
- SoftPFResp = IsRead | IsResponse | IsSWPrefetch | NeedsResponse,
- HardPFResp = IsRead | IsResponse | IsHWPrefetch | NeedsResponse,
+ SoftPFResp = IsRead | IsResponse | IsSWPrefetch
+ | NeedsResponse | HasData,
+ HardPFResp = IsRead | IsResponse | IsHWPrefetch
+ | NeedsResponse | HasData,
InvalidateReq = IsInvalidate | IsRequest,
- WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest,
+ WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest | HasData,
UpgradeReq = IsInvalidate | IsRequest | NeedsResponse,
UpgradeResp = IsInvalidate | IsResponse | 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
@@ -219,6 +225,7 @@ class Packet
bool isResponse() { return (cmd & IsResponse) != 0; }
bool needsResponse() { return (cmd & NeedsResponse) != 0; }
bool isInvalidate() { return (cmd & IsInvalidate) != 0; }
+ bool hasData() { return (cmd & HasData) != 0; }
bool isCacheFill() { return (flags & CACHE_LINE_FILL) != 0; }
bool isNoAllocate() { return (flags & NO_ALLOCATE) != 0; }