Merge zizzer.eecs.umich.edu:/bk/newmem

into  zeep.eecs.umich.edu:/home/gblack/m5/newmem_bus

src/mem/bus.cc:
    Hand merged. Needs to be fixed

--HG--
extra : convert_revision : df03219ccfd18431cc726a063bd29d30554944a1
This commit is contained in:
Gabe Black 2006-10-08 19:14:09 -04:00
commit 2df9053bb0
5 changed files with 166 additions and 34 deletions

View file

@ -67,6 +67,47 @@ Bus::init()
(*intIter)->sendStatusChange(Port::RangeChange);
}
Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
{
assert(!scheduled());
}
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);
}
DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", curTick, tickNextIdle);
}
/** Function called by the port when the bus is receiving a Timing
* transaction.*/
@ -79,8 +120,10 @@ Bus::recvTiming(Packet *pkt)
short dest = pkt->getDest();
if (dest == Packet::Broadcast) {
if ( timingSnoopPhase1(pkt) )
if (timingSnoop(pkt))
{
timingSnoopPhase2(pkt);
pkt->flags |= SNOOP_COMMIT;
bool success = timingSnoop(pkt);
assert(success);
@ -102,33 +145,55 @@ Bus::recvTiming(Packet *pkt)
port = interfaces[dest];
}
if (port->sendTiming(pkt)) {
// packet was successfully sent, just return true.
// Packet was successfully sent. Return true.
// Also take care of retries
if (retryingPort) {
retryList.pop_front();
retryingPort = NULL;
}
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, sendTiming wasn't called
if (retryingPort) {
warn("sendRetry didn't call sendTiming\n");
retryList.pop_front();
retryingPort = NULL;
}
}
}
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)
@ -365,16 +430,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)

View file

@ -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 bytes */
int width;
/** the next tick at which the bus will be idle */
Tick tickNextIdle;
static const int defaultId = -1;
@ -90,6 +97,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.
@ -173,6 +189,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;
@ -181,6 +213,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 = NULL;
// 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;
@ -191,8 +240,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(NULL), defaultPort(NULL)
{
//Both the width and clock period must be positive
assert(width);
assert(clock);
}
};

View file

@ -105,8 +105,7 @@ BaseCache::CachePort::recvRetry()
drainList.pop_front();
}
}
if (!isCpuSide)
else if (!isCpuSide)
{
pkt = cache->getPacket();
bool success = sendTiming(pkt);

View file

@ -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; }

View file

@ -6,3 +6,5 @@ class Bus(MemObject):
port = VectorPort("vector port for connecting devices")
default = Port("Default port for requests that aren't handeled by a device.")
bus_id = Param.Int(0, "blah")
clock = Param.Clock("1GHz", "bus clock speed")
width = Param.Int(64, "bus width (bytes)")