diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index c4b137869..736e8dc81 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -31,209 +31,209 @@ * @file Definition of a simple bus bridge without buffering. */ +#include #include "base/trace.hh" #include "mem/bridge.hh" #include "sim/builder.hh" +Bridge::BridgePort::BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit) + : Port(_name), bridge(_bridge), otherPort(_otherPort), + delay(_delay), outstandingResponses(0), + queueLimit(_queueLimit), sendEvent(this) +{ +} + +Bridge::Bridge(const std::string &n, int qsa, int qsb, + Tick _delay, int write_ack) + : MemObject(n), + portA(n + "-portA", this, &portB, _delay, qsa), + portB(n + "-portB", this, &portA, _delay, qsa), + ackWrites(write_ack) +{ +} + +Port * +Bridge::getPort(const std::string &if_name) +{ + BridgePort *port; + + if (if_name == "side_a") + port = &portA; + else if (if_name == "side_b") + port = &portB; + else + return NULL; + + if (port->getPeer() != NULL) + panic("bridge side %s already connected to.", if_name); + return port; +} + + void Bridge::init() { // Make sure that both sides are connected to. - if (sideA == NULL || sideB == NULL) + if (portA.getPeer() == NULL || portB.getPeer() == NULL) panic("Both ports of bus bridge are not connected to a bus.\n"); } -/** Function called by the port when the bus is recieving a Timing +/** Function called by the port when the bus is receiving a Timing * transaction.*/ bool -Bridge::recvTiming(Packet *pkt, Side id) +Bridge::BridgePort::recvTiming(Packet *pkt) { - if (blockedA && id == SideA) - return false; - if (blockedB && id == SideB) + DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr()); + + 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. + PacketBuffer *buf = dynamic_cast(pkt->senderState); + assert(buf != NULL); + // set up new packet dest & senderState based on values saved + // from original request + buf->fixResponse(pkt); + DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); + delete buf; + } + + return otherPort->queueForSendTiming(pkt); +} + + +bool +Bridge::BridgePort::queueForSendTiming(Packet *pkt) +{ + if (queueFull()) return false; - if (delay) { - if (!sendEvent.scheduled()) - sendEvent.schedule(curTick + delay); - if (id == SideA) { - inboundA.push_back(std::make_pair(pkt, curTick)); - blockCheck(SideA); - } else { - inboundB.push_back(std::make_pair(pkt, curTick)); - blockCheck(SideB); - } - } else { - if (id == SideB) { - sideA->sendPkt(pkt); - blockCheck(SideB); - } else { - sideB->sendPkt(pkt); - blockCheck(SideA); - } + Tick readyTime = curTick + delay; + PacketBuffer *buf = new PacketBuffer(pkt, readyTime); + + // 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 (sendQueue.empty()) { + sendEvent.schedule(readyTime); } + + sendQueue.push_back(buf); + + // Did we just become blocked? If yes, let other side know. + if (queueFull()) + otherPort->sendStatusChange(Port::Blocked); + return true; - } + void -Bridge::blockCheck(Side id) +Bridge::BridgePort::finishSend(PacketBuffer *buf) { - /* Check that we still have buffer space available. */ - if (id == SideB) { - if (sideA->numQueued() + inboundB.size() >= queueSizeA && !blockedB) { - sideB->sendStatusChange(Port::Blocked); - blockedB = true; - } else if (sideA->numQueued() + inboundB.size() < queueSizeA && blockedB) { - sideB->sendStatusChange(Port::Unblocked); - blockedB = false; - } + if (buf->expectResponse) { + // Must wait for response. We just need to count outstanding + // responses (in case we want to cap them); PacketBuffer + // pointer will be recovered on response. + ++outstandingResponses; + DPRINTF(BusBridge, " successful: awaiting response (%d)\n", + outstandingResponses); } else { - if (sideB->numQueued() + inboundA.size() >= queueSizeB && !blockedA) { - sideA->sendStatusChange(Port::Blocked); - blockedA = true; - } else if (sideB->numQueued() + inboundA.size() < queueSizeB && blockedA) { - sideA->sendStatusChange(Port::Unblocked); - blockedA = false; - } + // no response expected... deallocate packet buffer now. + DPRINTF(BusBridge, " successful: no response expected\n"); + delete buf; + } + + // If there are more packets to send, schedule event to try again. + if (!sendQueue.empty()) { + buf = sendQueue.front(); + sendEvent.schedule(std::max(buf->ready, curTick + 1)); } } -void Bridge::timerEvent() -{ - Tick t = 0; - assert(inboundA.size() || inboundB.size()); - if (inboundA.size()) { - while (inboundA.front().second <= curTick + delay){ - sideB->sendPkt(inboundA.front()); - inboundA.pop_front(); - } - if (inboundA.size()) - t = inboundA.front().second + delay; - } - if (inboundB.size()) { - while (inboundB.front().second <= curTick + delay){ - sideB->sendPkt(inboundA.front()); - inboundB.pop_front(); - } - if (inboundB.size()) - if (t == 0) - t = inboundB.front().second + delay; - else - t = std::min(t,inboundB.front().second + delay); +void +Bridge::BridgePort::trySend() +{ + assert(!sendQueue.empty()); + + PacketBuffer *buf = sendQueue.front(); + + assert(buf->ready <= curTick); + + Packet *pkt = buf->pkt; + + DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", + buf->origSrc, pkt->getDest(), pkt->getAddr()); + + if (sendTiming(pkt)) { + // send successful + sendQueue.pop_front(); + buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it + finishSend(buf); } else { - panic("timerEvent() called but nothing to do?"); + DPRINTF(BusBridge, " unsuccessful\n"); } - - if (t != 0) - sendEvent.schedule(t); -} - - -void -Bridge::BridgePort::sendPkt(Packet *pkt) -{ - if (!sendTiming(pkt)) - outbound.push_back(std::make_pair(pkt, curTick)); -} - -void -Bridge::BridgePort::sendPkt(std::pair p) -{ - if (!sendTiming(p.first)) - outbound.push_back(p); } Packet * Bridge::BridgePort::recvRetry() { - Packet *pkt; - assert(outbound.size() > 0); - assert(outbound.front().second >= curTick + bridge->delay); - pkt = outbound.front().first; - outbound.pop_front(); - bridge->blockCheck(side); + PacketBuffer *buf = sendQueue.front(); + Packet *pkt = buf->pkt; + finishSend(buf); return pkt; } -/** Function called by the port when the bus is recieving a Atomic +/** Function called by the port when the bus is receiving a Atomic * transaction.*/ Tick -Bridge::recvAtomic(Packet *pkt, Side id) +Bridge::BridgePort::recvAtomic(Packet *pkt) { - pkt->time += delay; - - if (id == SideA) - return sideB->sendAtomic(pkt); - else - return sideA->sendAtomic(pkt); + return otherPort->sendAtomic(pkt) + delay; } -/** Function called by the port when the bus is recieving a Functional +/** Function called by the port when the bus is receiving a Functional * transaction.*/ void -Bridge::recvFunctional(Packet *pkt, Side id) +Bridge::BridgePort::recvFunctional(Packet *pkt) { - pkt->time += delay; - std::list >::iterator i; + std::list::iterator i; bool pktContinue = true; - for(i = inboundA.begin(); i != inboundA.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); - } - } - - for(i = inboundB.begin(); i != inboundB.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); - } - } - - for(i = sideA->outbound.begin(); i != sideA->outbound.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); - } - } - - for(i = sideB->outbound.begin(); i != sideB->outbound.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); + for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { + if (pkt->intersect((*i)->pkt)) { + pktContinue &= fixPacket(pkt, (*i)->pkt); } } if (pktContinue) { - if (id == SideA) - sideB->sendFunctional(pkt); - else - sideA->sendFunctional(pkt); + otherPort->sendFunctional(pkt); } } -/** Function called by the port when the bus is recieving a status change.*/ +/** Function called by the port when the bus is receiving a status change.*/ void -Bridge::recvStatusChange(Port::Status status, Side id) +Bridge::BridgePort::recvStatusChange(Port::Status status) { if (status == Port::Blocked || status == Port::Unblocked) - return ; + return; - if (id == SideA) - sideB->sendStatusChange(status); - else - sideA->sendStatusChange(status); + otherPort->sendStatusChange(status); } void -Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id) +Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) { - if (id == SideA) - sideB->getPeerAddressRanges(resp, snoop); - else - sideA->getPeerAddressRanges(resp, snoop); + otherPort->getPeerAddressRanges(resp, snoop); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 2672a6e8c..8a5cbf92a 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -46,132 +46,127 @@ class Bridge : public MemObject { - public: - enum Side - { - SideA, - SideB - }; - protected: - /** Function called by the port when the bus is recieving a Timing - transaction.*/ - bool recvTiming(Packet *pkt, Side id); - - /** Function called by the port when the bus is recieving a Atomic - transaction.*/ - Tick recvAtomic(Packet *pkt, Side id); - - /** Function called by the port when the bus is recieving a Functional - transaction.*/ - void recvFunctional(Packet *pkt, Side id); - - /** Function called by the port when the bus is recieving a status change.*/ - void recvStatusChange(Port::Status status, Side id); - - /** Process address range request. - * @param resp addresses that we can respond to - * @param snoop addresses that we would like to snoop - * @param id ide of the busport that made the request. - */ - void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id); - - - /** Event that the SendEvent calls when it fires. This code must reschedule - * the send event as required. */ - void timerEvent(); - /** Decleration of the buses port type, one will be instantiated for each of the interfaces connecting to the bus. */ class BridgePort : public Port { - /** A pointer to the bus to which this port belongs. */ + /** A pointer to the bridge to which this port belongs. */ Bridge *bridge; - /** A id to keep track of the intercafe ID this port is connected to. */ - Bridge::Side side; + /** + * Pointer to the port on the other side of the bridge + * (connected to the other bus). + */ + BridgePort *otherPort; + + /** Minimum delay though this bridge. */ + Tick delay; + + class PacketBuffer : public Packet::SenderState { + + public: + Tick ready; + Packet *pkt; + Packet::SenderState *origSenderState; + short origSrc; + bool expectResponse; + + PacketBuffer(Packet *_pkt, Tick t) + : ready(t), pkt(_pkt), + origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), + expectResponse(_pkt->needsResponse()) + { + pkt->senderState = this; + } + + void fixResponse(Packet *pkt) + { + assert(pkt->senderState == this); + pkt->setDest(origSrc); + pkt->senderState = origSenderState; + } + }; + + /** + * Outbound packet queue. Packets are held in this queue for a + * specified delay to model the processing delay of the + * bridge. + */ + std::list sendQueue; + + int outstandingResponses; + + /** Max queue size for outbound packets */ + int queueLimit; + + /** + * Is this side blocked from accepting outbound packets? + */ + bool queueFull() { return (sendQueue.size() == queueLimit); } + + bool queueForSendTiming(Packet *pkt); + + void finishSend(PacketBuffer *buf); + + /** + * Handle send event, scheduled when the packet at the head of + * the outbound queue is ready to transmit (for timing + * accesses only). + */ + void trySend(); + + class SendEvent : public Event + { + BridgePort *port; + + public: + SendEvent(BridgePort *p) + : Event(&mainEventQueue), port(p) {} + + virtual void process() { port->trySend(); } + + virtual const char *description() { return "bridge send event"; } + }; + + SendEvent sendEvent; public: /** Constructor for the BusPort.*/ - BridgePort(Bridge *_bridge, Side _side) - : Port(""), bridge(_bridge), side(_side) - { } - - int numQueued() { return outbound.size(); } + BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit); protected: - /** Data this is waiting to be transmitted. */ - std::list > outbound; - void sendPkt(Packet *pkt); - void sendPkt(std::pair p); - - /** When reciving a timing request from the peer port, + /** When receiving a timing request from the peer port, pass it to the bridge. */ - virtual bool recvTiming(Packet *pkt) - { return bridge->recvTiming(pkt, side); } + virtual bool recvTiming(Packet *pkt); - /** When reciving a retry request from the peer port, + /** When receiving a retry request from the peer port, pass it to the bridge. */ virtual Packet* recvRetry(); - /** When reciving a Atomic requestfrom the peer port, + /** When receiving a Atomic requestfrom the peer port, pass it to the bridge. */ - virtual Tick recvAtomic(Packet *pkt) - { return bridge->recvAtomic(pkt, side); } + virtual Tick recvAtomic(Packet *pkt); - /** When reciving a Functional request from the peer port, + /** When receiving a Functional request from the peer port, pass it to the bridge. */ - virtual void recvFunctional(Packet *pkt) - { bridge->recvFunctional(pkt, side); } + virtual void recvFunctional(Packet *pkt); - /** When reciving a status changefrom the peer port, + /** When receiving a status changefrom the peer port, pass it to the bridge. */ - virtual void recvStatusChange(Status status) - { bridge->recvStatusChange(status, side); } + virtual void recvStatusChange(Status status); - /** When reciving a address range request the peer port, + /** When receiving a address range request the peer port, pass it to the bridge. */ - virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { bridge->addressRanges(resp, snoop, side); } - - friend class Bridge; + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop); }; - class SendEvent : public Event - { - Bridge *bridge; - - SendEvent(Bridge *b) - : Event(&mainEventQueue), bridge(b) {} - - virtual void process() { bridge->timerEvent(); } - - virtual const char *description() { return "bridge delay event"; } - friend class Bridge; - }; - - SendEvent sendEvent; - - /** Sides of the bus bridges. */ - BridgePort* sideA; - BridgePort* sideB; - - /** inbound queues on both sides. */ - std::list > inboundA; - std::list > inboundB; - - /** The size of the queue for data coming into side a */ - int queueSizeA; - int queueSizeB; - - /* if the side is blocked or not. */ - bool blockedA; - bool blockedB; - - /** Miminum delay though this bridge. */ - Tick delay; + BridgePort portA, portB; /** If this bridge should acknowledge writes. */ bool ackWrites; @@ -179,36 +174,11 @@ class Bridge : public MemObject public: /** A function used to return the port associated with this bus object. */ - virtual Port *getPort(const std::string &if_name) - { - if (if_name == "side_a") { - if (sideA != NULL) - panic("bridge side a already connected to."); - sideA = new BridgePort(this, SideA); - return sideA; - } else if (if_name == "side_b") { - if (sideB != NULL) - panic("bridge side b already connected to."); - sideB = new BridgePort(this, SideB); - return sideB; - } else - return NULL; - } + virtual Port *getPort(const std::string &if_name); virtual void init(); - Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack) - : MemObject(n), sendEvent(this), sideA(NULL), sideB(NULL), - queueSizeA(qsa), queueSizeB(qsb), blockedA(false), blockedB(false), - delay(_delay), ackWrites(write_ack) - {} - - /** Check if the port should block/unblock after recieving/sending a packet. - * */ - void blockCheck(Side id); - - friend class Bridge::SendEvent; - + Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack); }; #endif //__MEM_BUS_HH__