X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fbridge.cc;h=9c4241097ea21e33613e4641e3b1c84e00f92669;hb=e33b3aa6692b172f6db5957774a9e0289e81fa5b;hp=8bc34e12e70f37c2d5e7c6c428ead47bc4d3d3e0;hpb=ffb6aec603c38e16ae91ea975c16fc3e8fb337e5;p=gem5.git diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index 8bc34e12e..9c4241097 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 ARM Limited + * Copyright (c) 2011-2013, 2015 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,13 +44,14 @@ /** * @file - * Implementation of a memory-mapped bus bridge that connects a master + * Implementation of a memory-mapped bridge that connects a master * and a slave through a request and response queue. */ +#include "mem/bridge.hh" + #include "base/trace.hh" #include "debug/Bridge.hh" -#include "mem/bridge.hh" #include "params/Bridge.hh" Bridge::BridgeSlavePort::BridgeSlavePort(const std::string& _name, @@ -60,8 +61,8 @@ Bridge::BridgeSlavePort::BridgeSlavePort(const std::string& _name, std::vector _ranges) : SlavePort(_name, &_bridge), bridge(_bridge), masterPort(_masterPort), delay(_delay), ranges(_ranges.begin(), _ranges.end()), - outstandingResponses(0), retryReq(false), - respQueueLimit(_resp_limit), sendEvent(*this) + outstandingResponses(0), retryReq(false), respQueueLimit(_resp_limit), + sendEvent([this]{ trySendTiming(); }, _name) { } @@ -70,12 +71,13 @@ Bridge::BridgeMasterPort::BridgeMasterPort(const std::string& _name, BridgeSlavePort& _slavePort, Cycles _delay, int _req_limit) : MasterPort(_name, &_bridge), bridge(_bridge), slavePort(_slavePort), - delay(_delay), reqQueueLimit(_req_limit), sendEvent(*this) + delay(_delay), reqQueueLimit(_req_limit), + sendEvent([this]{ trySendTiming(); }, _name) { } Bridge::Bridge(Params *p) - : MemObject(p), + : ClockedObject(p), slavePort(p->name + ".slave", *this, masterPort, ticksToCycles(p->delay), p->resp_size, p->ranges), masterPort(p->name + ".master", *this, slavePort, @@ -83,24 +85,16 @@ Bridge::Bridge(Params *p) { } -MasterPort& -Bridge::getMasterPort(const std::string &if_name, int idx) +Port & +Bridge::getPort(const std::string &if_name, PortID idx) { if (if_name == "master") return masterPort; - else - // pass it along to our super class - return MemObject::getMasterPort(if_name, idx); -} - -SlavePort& -Bridge::getSlavePort(const std::string &if_name, int idx) -{ - if (if_name == "slave") + else if (if_name == "slave") return slavePort; else // pass it along to our super class - return MemObject::getSlavePort(if_name, idx); + return ClockedObject::getPort(if_name, idx); } void @@ -108,25 +102,20 @@ Bridge::init() { // make sure both sides are connected and have the same block size if (!slavePort.isConnected() || !masterPort.isConnected()) - fatal("Both ports of bus bridge are not connected to a bus.\n"); - - if (slavePort.peerBlockSize() != masterPort.peerBlockSize()) - fatal("Slave port size %d, master port size %d \n " \ - "Busses don't have the same block size... Not supported.\n", - slavePort.peerBlockSize(), masterPort.peerBlockSize()); + fatal("Both ports of a bridge must be connected.\n"); // notify the master side of our address ranges slavePort.sendRangeChange(); } bool -Bridge::BridgeSlavePort::respQueueFull() +Bridge::BridgeSlavePort::respQueueFull() const { return outstandingResponses == respQueueLimit; } bool -Bridge::BridgeMasterPort::reqQueueFull() +Bridge::BridgeMasterPort::reqQueueFull() const { return transmitList.size() == reqQueueLimit; } @@ -141,7 +130,14 @@ Bridge::BridgeMasterPort::recvTimingResp(PacketPtr pkt) DPRINTF(Bridge, "Request queue size: %d\n", transmitList.size()); - slavePort.schedTimingResp(pkt, bridge.clockEdge(delay)); + // technically the packet only reaches us after the header delay, + // and typically we also need to deserialise any payload (unless + // the two sides of the bridge are synchronous) + Tick receive_delay = pkt->headerDelay + pkt->payloadDelay; + pkt->headerDelay = pkt->payloadDelay = 0; + + slavePort.schedTimingResp(pkt, bridge.clockEdge(delay) + + receive_delay); return true; } @@ -152,26 +148,50 @@ Bridge::BridgeSlavePort::recvTimingReq(PacketPtr pkt) DPRINTF(Bridge, "recvTimingReq: %s addr 0x%x\n", pkt->cmdString(), pkt->getAddr()); - // ensure we do not have something waiting to retry - if(retryReq) + panic_if(pkt->cacheResponding(), "Should not see packets where cache " + "is responding"); + + // we should not get a new request after committing to retry the + // current one, but unfortunately the CPU violates this rule, so + // simply ignore it for now + if (retryReq) return false; DPRINTF(Bridge, "Response queue size: %d outresp: %d\n", transmitList.size(), outstandingResponses); + // if the request queue is full then there is no hope if (masterPort.reqQueueFull()) { DPRINTF(Bridge, "Request queue full\n"); retryReq = true; - } else if (pkt->needsResponse()) { - if (respQueueFull()) { - DPRINTF(Bridge, "Response queue full\n"); - retryReq = true; - } else { - DPRINTF(Bridge, "Reserving space for response\n"); - assert(outstandingResponses != respQueueLimit); - ++outstandingResponses; - retryReq = false; - masterPort.schedTimingReq(pkt, bridge.clockEdge(delay)); + } else { + // look at the response queue if we expect to see a response + bool expects_response = pkt->needsResponse(); + if (expects_response) { + if (respQueueFull()) { + DPRINTF(Bridge, "Response queue full\n"); + retryReq = true; + } else { + // ok to send the request with space for the response + DPRINTF(Bridge, "Reserving space for response\n"); + assert(outstandingResponses != respQueueLimit); + ++outstandingResponses; + + // no need to set retryReq to false as this is already the + // case + } + } + + if (!retryReq) { + // technically the packet only reaches us after the header + // delay, and typically we also need to deserialise any + // payload (unless the two sides of the bridge are + // synchronous) + Tick receive_delay = pkt->headerDelay + pkt->payloadDelay; + pkt->headerDelay = pkt->payloadDelay = 0; + + masterPort.schedTimingReq(pkt, bridge.clockEdge(delay) + + receive_delay); } } @@ -188,23 +208,13 @@ Bridge::BridgeSlavePort::retryStalledReq() if (retryReq) { DPRINTF(Bridge, "Request waiting for retry, now retrying\n"); retryReq = false; - sendRetry(); + sendRetryReq(); } } void Bridge::BridgeMasterPort::schedTimingReq(PacketPtr pkt, Tick when) { - // If we expect to see a response, we need to restore the source - // and destination field that is potentially changed by a second - // bus - if (!pkt->memInhibitAsserted() && pkt->needsResponse()) { - // Update the sender state so we can deal with the response - // appropriately - RequestState *req_state = new RequestState(pkt); - pkt->senderState = req_state; - } - // If we're about to put this packet at the head of the queue, we // need to schedule an event to do the transmit. Otherwise there // should already be an event scheduled for sending the head @@ -215,28 +225,13 @@ Bridge::BridgeMasterPort::schedTimingReq(PacketPtr pkt, Tick when) assert(transmitList.size() != reqQueueLimit); - transmitList.push_back(DeferredPacket(pkt, when)); + transmitList.emplace_back(pkt, when); } void Bridge::BridgeSlavePort::schedTimingResp(PacketPtr pkt, Tick when) { - // This is a response for a request we forwarded earlier. The - // corresponding request state should be stored in the packet's - // senderState field. - RequestState *req_state = dynamic_cast(pkt->senderState); - assert(req_state != NULL); - // set up new packet dest & senderState based on values saved - // from original request - req_state->fixResponse(pkt); - delete req_state; - - // the bridge assumes that at least one bus has set the - // destination field of the packet - assert(pkt->isDestValid()); - DPRINTF(Bridge, "response, new dest %d\n", pkt->getDest()); - // If we're about to put this packet at the head of the queue, we // need to schedule an event to do the transmit. Otherwise there // should already be an event scheduled for sending the head @@ -245,7 +240,7 @@ Bridge::BridgeSlavePort::schedTimingResp(PacketPtr pkt, Tick when) bridge.schedule(sendEvent, when); } - transmitList.push_back(DeferredPacket(pkt, when)); + transmitList.emplace_back(pkt, when); } void @@ -269,10 +264,10 @@ Bridge::BridgeMasterPort::trySendTiming() // If there are more packets to send, schedule event to try again. if (!transmitList.empty()) { - req = transmitList.front(); + DeferredPacket next_req = transmitList.front(); DPRINTF(Bridge, "Scheduling next send\n"); - bridge.schedule(sendEvent, std::max(req.tick, - bridge.nextCycle())); + bridge.schedule(sendEvent, std::max(next_req.tick, + bridge.clockEdge())); } // if we have stalled a request due to a full request queue, @@ -310,10 +305,10 @@ Bridge::BridgeSlavePort::trySendTiming() // If there are more packets to send, schedule event to try again. if (!transmitList.empty()) { - resp = transmitList.front(); + DeferredPacket next_resp = transmitList.front(); DPRINTF(Bridge, "Scheduling next send\n"); - bridge.schedule(sendEvent, std::max(resp.tick, - bridge.nextCycle())); + bridge.schedule(sendEvent, std::max(next_resp.tick, + bridge.clockEdge())); } // if there is space in the request queue and we were stalling @@ -322,7 +317,7 @@ Bridge::BridgeSlavePort::trySendTiming() if (!masterPort.reqQueueFull() && retryReq) { DPRINTF(Bridge, "Request waiting for retry, now retrying\n"); retryReq = false; - sendRetry(); + sendRetryReq(); } } @@ -331,48 +326,41 @@ Bridge::BridgeSlavePort::trySendTiming() } void -Bridge::BridgeMasterPort::recvRetry() +Bridge::BridgeMasterPort::recvReqRetry() { - Tick nextReady = transmitList.front().tick; - if (nextReady <= curTick()) - trySendTiming(); - else - bridge.schedule(sendEvent, nextReady); + trySendTiming(); } void -Bridge::BridgeSlavePort::recvRetry() +Bridge::BridgeSlavePort::recvRespRetry() { - Tick nextReady = transmitList.front().tick; - if (nextReady <= curTick()) - trySendTiming(); - else - bridge.schedule(sendEvent, nextReady); + trySendTiming(); } Tick Bridge::BridgeSlavePort::recvAtomic(PacketPtr pkt) { + panic_if(pkt->cacheResponding(), "Should not see packets where cache " + "is responding"); + return delay * bridge.clockPeriod() + masterPort.sendAtomic(pkt); } void Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt) { - std::list::iterator i; - pkt->pushLabel(name()); // check the response queue - for (i = transmitList.begin(); i != transmitList.end(); ++i) { - if (pkt->checkFunctional((*i).pkt)) { + for (auto i = transmitList.begin(); i != transmitList.end(); ++i) { + if (pkt->trySatisfyFunctional((*i).pkt)) { pkt->makeResponse(); return; } } // also check the master port's request queue - if (masterPort.checkFunctional(pkt)) { + if (masterPort.trySatisfyFunctional(pkt)) { return; } @@ -383,13 +371,13 @@ Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt) } bool -Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt) +Bridge::BridgeMasterPort::trySatisfyFunctional(PacketPtr pkt) { bool found = false; - std::list::iterator i = transmitList.begin(); + auto i = transmitList.begin(); - while(i != transmitList.end() && !found) { - if (pkt->checkFunctional((*i).pkt)) { + while (i != transmitList.end() && !found) { + if (pkt->trySatisfyFunctional((*i).pkt)) { pkt->makeResponse(); found = true; }