X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fxbar.cc;h=b139cdc9b9dabd2a5b366b7e0007438bb60d4dde;hb=24bfdc36f19fddbfcb33cc2f33fb216e8da0382d;hp=d56e726d56ba10e096de97632c0ab198e653c3bb;hpb=b7f1d675da6e3887e956bf253fef77913d38a3dc;p=gem5.git diff --git a/src/mem/xbar.cc b/src/mem/xbar.cc index d56e726d5..b139cdc9b 100644 --- a/src/mem/xbar.cc +++ b/src/mem/xbar.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 ARM Limited + * Copyright (c) 2011-2015, 2018 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -47,16 +47,20 @@ * Definition of a crossbar object. */ -#include "base/misc.hh" +#include "mem/xbar.hh" + +#include "base/logging.hh" #include "base/trace.hh" #include "debug/AddrRanges.hh" #include "debug/Drain.hh" #include "debug/XBar.hh" -#include "mem/xbar.hh" BaseXBar::BaseXBar(const BaseXBarParams *p) : MemObject(p), - headerCycles(p->header_cycles), width(p->width), + frontendLatency(p->frontend_latency), + forwardLatency(p->forward_latency), + responseLatency(p->response_latency), + width(p->width), gotAddrRanges(p->port_default_connection_count + p->port_master_connection_count, false), gotAllAddrRanges(false), defaultPortID(InvalidPortID), @@ -102,37 +106,48 @@ BaseXBar::getSlavePort(const std::string &if_name, PortID idx) } void -BaseXBar::calcPacketTiming(PacketPtr pkt) +BaseXBar::calcPacketTiming(PacketPtr pkt, Tick header_delay) { // the crossbar will be called at a time that is not necessarily // coinciding with its own clock, so start by determining how long // until the next clock edge (could be zero) Tick offset = clockEdge() - curTick(); - // determine how many cycles are needed to send the data - unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; - - // before setting the bus delay fields of the packet, ensure that - // the delay from any previous crossbar has been accounted for - if (pkt->firstWordDelay != 0 || pkt->lastWordDelay != 0) - panic("Packet %s already has delay (%d, %d) that should be " - "accounted for.\n", pkt->cmdString(), pkt->firstWordDelay, - pkt->lastWordDelay); - - // The first word will be delivered on the cycle after the header. - pkt->firstWordDelay = (headerCycles + 1) * clockPeriod() + offset; + // the header delay depends on the path through the crossbar, and + // we therefore rely on the caller to provide the actual + // value + pkt->headerDelay += offset + header_delay; + + // note that we add the header delay to the existing value, and + // align it to the crossbar clock + + // do a quick sanity check to ensure the timings are not being + // ignored, note that this specific value may cause problems for + // slower interconnects + panic_if(pkt->headerDelay > SimClock::Int::us, + "Encountered header delay exceeding 1 us\n"); + + if (pkt->hasData()) { + // the payloadDelay takes into account the relative time to + // deliver the payload of the packet, after the header delay, + // we take the maximum since the payload delay could already + // be longer than what this parcitular crossbar enforces. + pkt->payloadDelay = std::max(pkt->payloadDelay, + divCeil(pkt->getSize(), width) * + clockPeriod()); + } - // Note that currently lastWordDelay can be smaller than - // firstWordDelay if the packet has no data - pkt->lastWordDelay = (headerCycles + dataCycles) * clockPeriod() + - offset; + // the payload delay is not paying for the clock offset as that is + // already done using the header delay, and the payload delay is + // also used to determine how long the crossbar layer is busy and + // thus regulates throughput } template BaseXBar::Layer::Layer(DstType& _port, BaseXBar& _xbar, const std::string& _name) : - port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL), - waitingForPeer(NULL), releaseEvent(this) + port(_port), xbar(_xbar), _name(_name), state(IDLE), + waitingForPeer(NULL), releaseEvent([this]{ releaseLayer(); }, name()) { } @@ -238,12 +253,10 @@ BaseXBar::Layer::releaseLayer() // waiting for the peer if (waitingForPeer == NULL) retryWaiting(); - } else if (waitingForPeer == NULL && drainManager) { + } else if (waitingForPeer == NULL && drainState() == DrainState::Draining) { DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n"); //If we weren't able to drain before, do it now. - drainManager->signalDrainDone(); - // Clear the drain event once we're done with it. - drainManager = NULL; + signalDrainDone(); } } @@ -267,17 +280,18 @@ BaseXBar::Layer::retryWaiting() // tell the port to retry, which in some cases ends up calling the // layer again - retryingPort->sendRetry(); + sendRetry(retryingPort); // If the layer is still in the retry state, sendTiming wasn't - // called in zero time (e.g. the cache does this), burn a cycle + // called in zero time (e.g. the cache does this when a writeback + // is squashed) if (state == RETRY) { // update the state to busy and reset the retrying port, we // have done our bit and sent the retry state = BUSY; - // occupy the crossbar layer until the next cycle ends - occupyLayer(xbar.clockEdge(Cycles(1))); + // occupy the crossbar layer until the next clock edge + occupyLayer(xbar.clockEdge()); } } @@ -307,41 +321,34 @@ BaseXBar::Layer::recvRetry() } PortID -BaseXBar::findPort(Addr addr) +BaseXBar::findPort(AddrRange addr_range) { // we should never see any address lookups before we've got the // ranges of all connected slave modules assert(gotAllAddrRanges); - // Check the cache - PortID dest_id = checkPortCache(addr); - if (dest_id != InvalidPortID) - return dest_id; - // Check the address map interval tree - auto i = portMap.find(addr); + auto i = portMap.contains(addr_range); if (i != portMap.end()) { - dest_id = i->second; - updatePortCache(dest_id, i->first); - return dest_id; + return i->second; } // Check if this matches the default range if (useDefaultRange) { - if (defaultRange.contains(addr)) { - DPRINTF(AddrRanges, " found addr %#llx on default\n", - addr); + if (addr_range.isSubset(defaultRange)) { + DPRINTF(AddrRanges, " found addr %s on default\n", + addr_range.to_string()); return defaultPortID; } } else if (defaultPortID != InvalidPortID) { - DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, " - "will use default port\n", addr); + DPRINTF(AddrRanges, "Unable to find destination for %s, " + "will use default port\n", addr_range.to_string()); return defaultPortID; } // we should use the range for the default port and it did not // match, or the default port is not set - fatal("Unable to find destination for addr %#llx on %s\n", addr, + fatal("Unable to find destination for %s on %s\n", addr_range.to_string(), name()); } @@ -406,8 +413,9 @@ BaseXBar::recvRangeChange(PortID master_port_id) DPRINTF(AddrRanges, "Adding range %s for id %d\n", r.to_string(), master_port_id); if (portMap.insert(r, master_port_id) == portMap.end()) { - PortID conflict_id = portMap.find(r)->second; - fatal("%s has two ports responding within range %s:\n\t%s\n\t%s\n", + PortID conflict_id = portMap.intersects(r)->second; + fatal("%s has two ports responding within range " + "%s:\n\t%s\n\t%s\n", name(), r.to_string(), masterPorts[master_port_id]->getSlavePort().name(), @@ -482,7 +490,7 @@ BaseXBar::recvRangeChange(PortID master_port_id) } } - // also check that no range partially overlaps with the + // also check that no range partially intersects with the // default range, this has to be done after all ranges are set // as there are no guarantees for when the default range is // update with respect to the other ones @@ -503,8 +511,6 @@ BaseXBar::recvRangeChange(PortID master_port_id) for (const auto& s: slavePorts) s->sendRangeChange(); } - - clearPortCache(); } AddrRangeList @@ -528,6 +534,8 @@ BaseXBar::getAddrRanges() const void BaseXBar::regStats() { + ClockedObject::regStats(); + using namespace Stats; transDist @@ -572,18 +580,18 @@ BaseXBar::regStats() } template -unsigned int -BaseXBar::Layer::drain(DrainManager *dm) +DrainState +BaseXBar::Layer::drain() { //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 (state != IDLE) { DPRINTF(Drain, "Crossbar not drained\n"); - drainManager = dm; - return 1; + return DrainState::Draining; + } else { + return DrainState::Drained; } - return 0; } template