1d0
<
2a2,13
> * Copyright (c) 2011 ARM Limited
> * All rights reserved
> *
> * The license below extends only to copyright in the software and shall
> * not be construed as granting a license to any other intellectual
> * property including but not limited to intellectual property relating
> * to a hardware implementation of the functionality of the software
> * licensed hereunder. You may use the software subject to the license
> * terms below provided that you ensure that this notice is replicated
> * unmodified and in its entirety in all distributions of the software,
> * modified or unmodified, in source code or in binary form.
> *
30a42
> * Andreas Hansson
35c47,48
< * Definition of a simple bus bridge without buffering.
---
> * Implementation of a memory-mapped bus bridge that connects a master
> * and a slave through a request and response queue.
38,40d50
< #include <algorithm>
<
< #include "base/range_ops.hh"
46,54c56,66
< Bridge::BridgePort::BridgePort(const std::string &_name,
< Bridge *_bridge, BridgePort *_otherPort,
< int _delay, int _nack_delay, int _req_limit,
< int _resp_limit,
< std::vector<Range<Addr> > filter_ranges)
< : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort),
< delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
< outstandingResponses(0), queuedRequests(0), inRetry(false),
< reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
---
> Bridge::BridgeSlavePort::BridgeSlavePort(const std::string &_name,
> Bridge* _bridge,
> BridgeMasterPort* _masterPort,
> int _delay, int _nack_delay,
> int _resp_limit,
> std::vector<Range<Addr> > _ranges)
> : Port(_name, _bridge), bridge(_bridge), masterPort(_masterPort),
> delay(_delay), nackDelay(_nack_delay),
> ranges(_ranges.begin(), _ranges.end()),
> outstandingResponses(0), inRetry(false),
> respQueueLimit(_resp_limit), sendEvent(this)
57a70,78
> Bridge::BridgeMasterPort::BridgeMasterPort(const std::string &_name,
> Bridge* _bridge,
> BridgeSlavePort* _slavePort,
> int _delay, int _req_limit)
> : Port(_name, _bridge), bridge(_bridge), slavePort(_slavePort),
> delay(_delay), inRetry(false), reqQueueLimit(_req_limit), sendEvent(this)
> {
> }
>
60,63c81,83
< portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
< p->req_size_a, p->resp_size_a, p->filter_ranges_a),
< portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay,
< p->req_size_b, p->resp_size_b, p->filter_ranges_b),
---
> slavePort(p->name + "-slave", this, &masterPort, p->delay,
> p->nack_delay, p->resp_size, p->ranges),
> masterPort(p->name + "-master", this, &slavePort, p->delay, p->req_size),
70c90
< Port *
---
> Port*
73c93
< BridgePort *port;
---
> Port* port;
75,78c95,98
< if (if_name == "side_a")
< port = &portA;
< else if (if_name == "side_b")
< port = &portB;
---
> if (if_name == "slave")
> port = &slavePort;
> else if (if_name == "master")
> port = &masterPort;
92,93c112,113
< // Make sure that both sides are connected to.
< if (!portA.isConnected() || !portB.isConnected())
---
> // make sure both sides are connected and have the same block size
> if (!slavePort.isConnected() || !masterPort.isConnected())
96,97c116,117
< if (portA.peerBlockSize() != portB.peerBlockSize())
< fatal("port A size %d, port B size %d \n " \
---
> if (slavePort.peerBlockSize() != masterPort.peerBlockSize())
> fatal("Slave port size %d, master port size %d \n " \
99c119,122
< portA.peerBlockSize(), portB.peerBlockSize());
---
> slavePort.peerBlockSize(), masterPort.peerBlockSize());
>
> // notify the master side of our address ranges
> slavePort.sendRangeChange();
103c126
< Bridge::BridgePort::respQueueFull()
---
> Bridge::BridgeSlavePort::respQueueFull()
105,106c128
< assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit);
< return outstandingResponses >= respQueueLimit;
---
> return outstandingResponses == respQueueLimit;
110c132
< Bridge::BridgePort::reqQueueFull()
---
> Bridge::BridgeMasterPort::reqQueueFull()
112,113c134
< assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit);
< return queuedRequests >= reqQueueLimit;
---
> return requestQueue.size() == reqQueueLimit;
116,117d136
< /** Function called by the port when the bus is receiving a Timing
< * transaction.*/
119c138
< Bridge::BridgePort::recvTiming(PacketPtr pkt)
---
> Bridge::BridgeMasterPort::recvTiming(PacketPtr pkt)
120a140,145
> // should only see responses on the master side
> assert(pkt->isResponse());
>
> // all checks are done when the request is accepted on the slave
> // side, so we are guaranteed to have space for the response
>
122c147
< pkt->getSrc(), pkt->getDest(), pkt->getAddr());
---
> pkt->getSrc(), pkt->getDest(), pkt->getAddr());
124,128c149
< DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
< sendQueue.size(), queuedRequests, outstandingResponses);
< DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n",
< otherPort->sendQueue.size(), otherPort->queuedRequests,
< otherPort->outstandingResponses);
---
> DPRINTF(BusBridge, "Request queue size: %d\n", requestQueue.size());
130,131c151,169
< if (pkt->isRequest() && otherPort->reqQueueFull()) {
< DPRINTF(BusBridge, "Remote queue full, nacking\n");
---
> slavePort->queueForSendTiming(pkt);
>
> return true;
> }
>
> bool
> Bridge::BridgeSlavePort::recvTiming(PacketPtr pkt)
> {
> // should only see requests on the slave side
> assert(pkt->isRequest());
>
> DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
> pkt->getSrc(), pkt->getDest(), pkt->getAddr());
>
> DPRINTF(BusBridge, "Response queue size: %d outresp: %d\n",
> responseQueue.size(), outstandingResponses);
>
> if (masterPort->reqQueueFull()) {
> DPRINTF(BusBridge, "Request queue full, nacking\n");
138,140c176,180
< DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
< DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
< sendQueue.size(), queuedRequests, outstandingResponses);
---
> DPRINTF(BusBridge,
> "Response queue full, no space for response, nacking\n");
> DPRINTF(BusBridge,
> "queue size: %d outstanding resp: %d\n",
> responseQueue.size(), outstandingResponses);
144a185
> assert(outstandingResponses != respQueueLimit);
149c190
< otherPort->queueForSendTiming(pkt);
---
> masterPort->queueForSendTiming(pkt);
155c196
< Bridge::BridgePort::nackRequest(PacketPtr pkt)
---
> Bridge::BridgeSlavePort::nackRequest(PacketPtr pkt)
161c202,208
< //put it on the list to send
---
> // The Nack packets are stored in the response queue just like any
> // other response, but they do not occupy any space as this is
> // tracked by the outstandingResponses, this guarantees space for
> // the Nack packets, but implicitly means we have an (unrealistic)
> // unbounded Nack queue.
>
> // put it on the list to send
166c213
< if (sendQueue.empty()) {
---
> if (responseQueue.empty()) {
169c216
< sendQueue.push_back(buf);
---
> responseQueue.push_back(buf);
176,177c223,224
< if (readyTime >= sendQueue.back()->ready) {
< sendQueue.push_back(buf);
---
> if (readyTime >= responseQueue.back()->ready) {
> responseQueue.push_back(buf);
182,184c229,231
< std::list<PacketBuffer*>::iterator i = sendQueue.begin();
< std::list<PacketBuffer*>::iterator end = sendQueue.end();
< std::list<PacketBuffer*>::iterator begin = sendQueue.begin();
---
> std::list<PacketBuffer*>::iterator i = responseQueue.begin();
> std::list<PacketBuffer*>::iterator end = responseQueue.end();
> std::list<PacketBuffer*>::iterator begin = responseQueue.begin();
191c238
< sendQueue.insert(i,buf);
---
> responseQueue.insert(i,buf);
199d245
<
201c247
< Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
---
> Bridge::BridgeMasterPort::queueForSendTiming(PacketPtr pkt)
203,206c249,250
< if (pkt->isResponse()) {
< // This is a response for a request we forwarded earlier. The
< // corresponding PacketBuffer should be stored in the packet's
< // senderState field.
---
> Tick readyTime = curTick() + delay;
> PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
208,215c252,257
< PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
< assert(buf != NULL);
< // set up new packet dest & senderState based on values saved
< // from original request
< buf->fixResponse(pkt);
<
< DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
< delete buf;
---
> // 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
> // packet.
> if (requestQueue.empty()) {
> bridge->schedule(sendEvent, readyTime);
217a260
> assert(requestQueue.size() != reqQueueLimit);
219,221c262,263
< if (pkt->isRequest()) {
< ++queuedRequests;
< }
---
> requestQueue.push_back(buf);
> }
223a266,276
> void
> Bridge::BridgeSlavePort::queueForSendTiming(PacketPtr pkt)
> {
> // This is a response for a request we forwarded earlier. The
> // corresponding PacketBuffer should be stored in the packet's
> // senderState field.
> PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
> assert(buf != NULL);
> // set up new packet dest & senderState based on values saved
> // from original request
> buf->fixResponse(pkt);
224a278,280
> DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
> delete buf;
>
226c282
< PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
---
> buf = new PacketBuffer(pkt, readyTime);
232c288
< if (sendQueue.empty()) {
---
> if (responseQueue.empty()) {
235c291
< sendQueue.push_back(buf);
---
> responseQueue.push_back(buf);
239c295
< Bridge::BridgePort::trySend()
---
> Bridge::BridgeMasterPort::trySend()
241c297
< assert(!sendQueue.empty());
---
> assert(!requestQueue.empty());
243c299
< PacketBuffer *buf = sendQueue.front();
---
> PacketBuffer *buf = requestQueue.front();
252,254d307
< bool wasReq = pkt->isRequest();
< bool was_nacked_here = buf->nackedHere;
<
260c313
< if (pkt->isRequest() && !buf->expectResponse)
---
> if (!buf->expectResponse)
265,266c318,320
< sendQueue.pop_front();
< buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it
---
> requestQueue.pop_front();
> // we no longer own packet, so it's not safe to look at it
> buf->pkt = NULL;
268,272c322
< if (buf->expectResponse) {
< // Must wait for response
< DPRINTF(BusBridge, " successful: awaiting response (%d)\n",
< outstandingResponses);
< } else {
---
> if (!buf->expectResponse) {
278,280c328,371
< if (wasReq)
< --queuedRequests;
< else if (!was_nacked_here)
---
> // If there are more packets to send, schedule event to try again.
> if (!requestQueue.empty()) {
> buf = requestQueue.front();
> DPRINTF(BusBridge, "Scheduling next send\n");
> bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
> }
> } else {
> DPRINTF(BusBridge, " unsuccessful\n");
> pkt->senderState = old_sender_state;
> inRetry = true;
> }
>
> DPRINTF(BusBridge, "trySend: request queue size: %d\n",
> requestQueue.size());
> }
>
> void
> Bridge::BridgeSlavePort::trySend()
> {
> assert(!responseQueue.empty());
>
> PacketBuffer *buf = responseQueue.front();
>
> assert(buf->ready <= curTick());
>
> PacketPtr pkt = buf->pkt;
>
> DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
> buf->origSrc, pkt->getDest(), pkt->getAddr());
>
> bool was_nacked_here = buf->nackedHere;
>
> // no need to worry about the sender state since we are not
> // modifying it
>
> if (sendTiming(pkt)) {
> DPRINTF(BusBridge, " successful\n");
> // send successful
> responseQueue.pop_front();
> // this is a response... deallocate packet buffer now.
> delete buf;
>
> if (!was_nacked_here) {
> assert(outstandingResponses != 0);
281a373
> }
284,285c376,377
< if (!sendQueue.empty()) {
< buf = sendQueue.front();
---
> if (!responseQueue.empty()) {
> buf = responseQueue.front();
291d382
< pkt->senderState = old_sender_state;
295,296c386,387
< DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
< sendQueue.size(), queuedRequests, outstandingResponses);
---
> DPRINTF(BusBridge, "trySend: queue size: %d outstanding resp: %d\n",
> responseQueue.size(), outstandingResponses);
298a390,399
> void
> Bridge::BridgeMasterPort::recvRetry()
> {
> inRetry = false;
> Tick nextReady = requestQueue.front()->ready;
> if (nextReady <= curTick())
> trySend();
> else
> bridge->schedule(sendEvent, nextReady);
> }
301c402
< Bridge::BridgePort::recvRetry()
---
> Bridge::BridgeSlavePort::recvRetry()
304c405
< Tick nextReady = sendQueue.front()->ready;
---
> Tick nextReady = responseQueue.front()->ready;
311,312d411
< /** Function called by the port when the bus is receiving a Atomic
< * transaction.*/
314c413
< Bridge::BridgePort::recvAtomic(PacketPtr pkt)
---
> Bridge::BridgeMasterPort::recvAtomic(PacketPtr pkt)
316c415,419
< return delay + otherPort->sendAtomic(pkt);
---
> // master port should never receive any atomic access (panic only
> // works once the other side, i.e. the busses, respects this)
> //
> //panic("Master port on %s got a recvAtomic\n", bridge->name());
> return 0;
319,320c422,427
< /** Function called by the port when the bus is receiving a Functional
< * transaction.*/
---
> Tick
> Bridge::BridgeSlavePort::recvAtomic(PacketPtr pkt)
> {
> return delay + masterPort->sendAtomic(pkt);
> }
>
322c429
< Bridge::BridgePort::recvFunctional(PacketPtr pkt)
---
> Bridge::BridgeMasterPort::recvFunctional(PacketPtr pkt)
323a431,439
> // master port should never receive any functional access (panic
> // only works once the other side, i.e. the busses, respect this)
>
> // panic("Master port on %s got a recvFunctional\n", bridge->name());
> }
>
> void
> Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt)
> {
328c444,445
< for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
---
> // check the response queue
> for (i = responseQueue.begin(); i != responseQueue.end(); ++i) {
334a452,456
> // also check the master port's request queue
> if (masterPort->checkFunctional(pkt)) {
> return;
> }
>
338c460
< otherPort->sendFunctional(pkt);
---
> masterPort->sendFunctional(pkt);
340a463,479
> bool
> Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt)
> {
> bool found = false;
> std::list<PacketBuffer*>::iterator i = requestQueue.begin();
>
> while(i != requestQueue.end() && !found) {
> if (pkt->checkFunctional((*i)->pkt)) {
> pkt->makeResponse();
> found = true;
> }
> ++i;
> }
>
> return found;
> }
>
343c482
< Bridge::BridgePort::recvRangeChange()
---
> Bridge::BridgeMasterPort::recvRangeChange()
345c484
< otherPort->sendRangeChange();
---
> // no need to forward as the bridge has a fixed set of ranges
347a487,492
> void
> Bridge::BridgeSlavePort::recvRangeChange()
> {
> // is a slave port so do nothing
> }
>
349c494
< Bridge::BridgePort::getAddrRanges()
---
> Bridge::BridgeSlavePort::getAddrRanges()
351,352d495
< AddrRangeList ranges = otherPort->getPeer()->getAddrRanges();
< FilterRangeList(filterRanges, ranges);