#include "base/trace.hh"
#include "mem/bus.hh"
+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), funcPort(NULL), funcPortId(-4),
+ useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
+ cachedBlockSize(0), cachedBlockSizeValid(false)
+{
+ //width, clock period, and header cycles must be positive
+ if (width <= 0)
+ fatal("Bus width must be positive\n");
+ if (clock <= 0)
+ 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)
{
return bp;
}
-bool
-Bus::deletePort(Port *p)
+void
+Bus::deletePortRefs(Port *p)
{
BusPort *bp = dynamic_cast<BusPort*>(p);
panic("Couldn't convert Port* to BusPort*\n");
// If this is our one functional port
if (funcPort == bp)
- return false;
+ return;
interfaces.erase(bp->getId());
clearBusCache();
delete bp;
- return true;
}
/** Get the ranges of anyone other buses that we are connected to. */
intIter->second->sendStatusChange(Port::RangeChange);
}
-Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
+Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
+ : bus(_bus)
{}
-void Bus::BusFreeEvent::process()
+void
+Bus::BusFreeEvent::process()
{
bus->recvRetry(-1);
}
-const char * Bus::BusFreeEvent::description() const
+const char *
+Bus::BusFreeEvent::description() const
{
return "bus became available";
}
-Tick Bus::calcPacketTiming(PacketPtr pkt)
+Tick
+Bus::calcPacketTiming(PacketPtr pkt)
{
// Bring tickNextIdle up to the present tick.
// There is some potential ambiguity where a cycle starts, which
// a cycle boundary to take up only the following cycle. Anything
// that happens later will have to "wait" for the end of that
// cycle, and then start using the bus after that.
- if (tickNextIdle < curTick) {
- tickNextIdle = curTick;
+ if (tickNextIdle < curTick()) {
+ tickNextIdle = curTick();
if (tickNextIdle % clock != 0)
- tickNextIdle = curTick - (curTick % clock) + clock;
+ tickNextIdle = curTick() - (curTick() % clock) + clock;
}
Tick headerTime = tickNextIdle + headerCycles * clock;
}
tickNextIdle = until;
+ reschedule(busIdle, tickNextIdle, true);
- 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);
+ curTick(), tickNextIdle);
}
/** Function called by the port when the bus is receiving a Timing
// If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list.
if (!pkt->isExpressSnoop() &&
- (tickNextIdle > curTick ||
+ (tickNextIdle > curTick() ||
(retryList.size() && (!inRetry || src_port != retryList.front()))))
{
addToRetryList(src_port);
}
}
} else {
- assert(dest >= 0 && dest < maxId);
+ assert(dest < maxId);
assert(dest != src); // catch infinite loops
dest_port_id = dest;
if (dest_port_id == defaultId)
if (dest_port_id == src) {
// Must be forwarded snoop up from below...
assert(dest == Packet::Broadcast);
- assert(src != defaultId); // catch infinite loops
} else {
// send to actual target
if (!dest_port->sendTiming(pkt)) {
// Packet not successfully sent. Leave or put it on the retry list.
// illegal to block responses... can lead to deadlock
assert(!pkt->isResponse());
+ // It's also illegal to force a transaction to retry after
+ // someone else has committed to respond.
+ assert(!pkt->memInhibitAsserted());
DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
addToRetryList(src_port);
Bus::recvRetry(int id)
{
// If there's anything waiting, and the bus isn't busy...
- if (retryList.size() && curTick >= tickNextIdle) {
+ if (retryList.size() && curTick() >= tickNextIdle) {
//retryingPort = retryList.front();
inRetry = true;
DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
inRetry = false;
//Bring tickNextIdle up to the present
- while (tickNextIdle < curTick)
+ while (tickNextIdle < curTick())
tickNextIdle += clock;
//Burn a cycle for the missed grant.
tickNextIdle += clock;
- busIdle.reschedule(tickNextIdle, true);
+ reschedule(busIdle, tickNextIdle, true);
}
}
//If we weren't able to drain before, we might be able to now.
- if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) {
+ if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) {
drainEvent->process();
// Clear the drain event once we're done with it.
drainEvent = NULL;
Bus::findPort(Addr addr)
{
/* An interval tree would be a better way to do this. --ali. */
- int dest_id = -1;
+ int dest_id;
dest_id = checkPortCache(addr);
- if (dest_id == -1) {
- PortIter i = portMap.find(RangeSize(addr,1));
- if (i != portMap.end()) {
- dest_id = i->second;
- updatePortCache(dest_id, i->first.start, i->first.end);
- }
+ if (dest_id != -1)
+ return dest_id;
+
+ // Check normal port ranges
+ PortIter i = portMap.find(RangeSize(addr,1));
+ if (i != portMap.end()) {
+ dest_id = i->second;
+ updatePortCache(dest_id, i->first.start, i->first.end);
+ return dest_id;
}
// Check if this matches the default range
- if (dest_id == -1) {
+ if (useDefaultRange) {
AddrRangeIter a_end = defaultRange.end();
for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
if (*i == addr) {
}
}
- if (responderSet) {
- panic("Unable to find destination for addr (user set default "
- "responder): %#llx", addr);
- } else {
- DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use "
- "default port", addr);
-
- return defaultId;
- }
+ panic("Unable to find destination for addr %#llx\n", addr);
}
- return dest_id;
+ DPRINTF(Bus, "Unable to find destination for addr %#llx, "
+ "will use default port\n", addr);
+ return defaultId;
}
}
// why do we have this packet field and the return value both???
- pkt->finishTime = curTick + response_latency;
+ pkt->finishTime = curTick() + response_latency;
return response_latency;
}
if (id == defaultId) {
defaultRange.clear();
// Only try to update these ranges if the user set a default responder.
- if (responderSet) {
+ if (useDefaultRange) {
defaultPort->getPeerAddressRanges(ranges, snoops);
assert(snoops == false);
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
}
}
-int
+unsigned
Bus::findBlockSize(int id)
{
if (cachedBlockSizeValid)
return cachedBlockSize;
- int max_bs = -1;
+ unsigned max_bs = 0;
PortIter p_end = portMap.end();
for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
- int tmp_bs = interfaces[p_iter->second]->peerBlockSize();
+ unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
if (tmp_bs > max_bs)
max_bs = tmp_bs;
}
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
- int tmp_bs = (*s_iter)->peerBlockSize();
+ unsigned tmp_bs = (*s_iter)->peerBlockSize();
if (tmp_bs > max_bs)
max_bs = tmp_bs;
}
- if (max_bs <= 0)
+ if (max_bs == 0)
max_bs = defaultBlockSize;
if (max_bs != 64)
//We should check that we're not "doing" anything, and that noone is
//waiting. We might be idle but have someone waiting if the device we
//contacted for a retry didn't actually retry.
- if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) {
+ if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) {
drainEvent = de;
return 1;
}
void
Bus::startup()
{
- if (tickNextIdle < curTick)
- tickNextIdle = (curTick / clock) * clock + clock;
+ if (tickNextIdle < curTick())
+ tickNextIdle = (curTick() / clock) * clock + clock;
}
Bus *