bridge.cc revision 4762
1545SN/A
21762SN/A/*
3545SN/A * Copyright (c) 2006 The Regents of The University of Michigan
4545SN/A * All rights reserved.
5545SN/A *
6545SN/A * Redistribution and use in source and binary forms, with or without
7545SN/A * modification, are permitted provided that the following conditions are
8545SN/A * met: redistributions of source code must retain the above copyright
9545SN/A * notice, this list of conditions and the following disclaimer;
10545SN/A * redistributions in binary form must reproduce the above copyright
11545SN/A * notice, this list of conditions and the following disclaimer in the
12545SN/A * documentation and/or other materials provided with the distribution;
13545SN/A * neither the name of the copyright holders nor the names of its
14545SN/A * contributors may be used to endorse or promote products derived from
15545SN/A * this software without specific prior written permission.
16545SN/A *
17545SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18545SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19545SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20545SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21545SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22545SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23545SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24545SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25545SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26545SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu *
292665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
30545SN/A *          Steve Reinhardt
31545SN/A */
321310SN/A
331310SN/A/**
34545SN/A * @file
355386Sstever@gmail.com * Definition of a simple bus bridge without buffering.
362542SN/A */
373348Sbinkertn@umich.edu
383348Sbinkertn@umich.edu#include <algorithm>
394762Snate@binkert.org
404762Snate@binkert.org#include "base/trace.hh"
414762Snate@binkert.org#include "mem/bridge.hh"
422489SN/A#include "params/Bridge.hh"
43545SN/A
443090Sstever@eecs.umich.eduBridge::BridgePort::BridgePort(const std::string &_name,
451310SN/A                               Bridge *_bridge, BridgePort *_otherPort,
462384SN/A                               int _delay, int _nack_delay, int _req_limit,
472489SN/A                               int _resp_limit, bool fix_partial_write)
482522SN/A    : Port(_name), bridge(_bridge), otherPort(_otherPort),
49545SN/A      delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write),
502489SN/A      outstandingResponses(0), queuedRequests(0), inRetry(false),
512489SN/A      reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
522489SN/A{
532489SN/A}
542489SN/A
553090Sstever@eecs.umich.eduBridge::Bridge(Params *p)
563090Sstever@eecs.umich.edu    : MemObject(p->name),
572914Ssaidi@eecs.umich.edu      portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
58545SN/A              p->req_size_a, p->resp_size_a, p->fix_partial_write_a),
59545SN/A      portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay,
602489SN/A              p->req_size_b, p->resp_size_b, p->fix_partial_write_b),
612384SN/A      ackWrites(p->write_ack), _params(p)
622384SN/A{
633349Sbinkertn@umich.edu    if (ackWrites)
642384SN/A        panic("No support for acknowledging writes\n");
653090Sstever@eecs.umich.edu}
664475Sstever@eecs.umich.edu
672384SN/APort *
682384SN/ABridge::getPort(const std::string &if_name, int idx)
693091Sstever@eecs.umich.edu{
702901Ssaidi@eecs.umich.edu    BridgePort *port;
712384SN/A
722384SN/A    if (if_name == "side_a")
732565SN/A        port = &portA;
742384SN/A    else if (if_name == "side_b")
752384SN/A        port = &portB;
762384SN/A    else
775386Sstever@gmail.com        return NULL;
782784Ssaidi@eecs.umich.edu
792784Ssaidi@eecs.umich.edu    if (port->getPeer() != NULL)
802784Ssaidi@eecs.umich.edu        panic("bridge side %s already connected to.", if_name);
812784Ssaidi@eecs.umich.edu    return port;
822784Ssaidi@eecs.umich.edu}
832784Ssaidi@eecs.umich.edu
842784Ssaidi@eecs.umich.edu
852784Ssaidi@eecs.umich.eduvoid
862784Ssaidi@eecs.umich.eduBridge::init()
872784Ssaidi@eecs.umich.edu{
882784Ssaidi@eecs.umich.edu    // Make sure that both sides are connected to.
892784Ssaidi@eecs.umich.edu    if (portA.getPeer() == NULL || portB.getPeer() == NULL)
902784Ssaidi@eecs.umich.edu        fatal("Both ports of bus bridge are not connected to a bus.\n");
912784Ssaidi@eecs.umich.edu
925534Ssaidi@eecs.umich.edu    if (portA.peerBlockSize() != portB.peerBlockSize())
935534Ssaidi@eecs.umich.edu        fatal("Busses don't have the same block size... Not supported.\n");
945534Ssaidi@eecs.umich.edu}
955534Ssaidi@eecs.umich.edu
965534Ssaidi@eecs.umich.edubool
975534Ssaidi@eecs.umich.eduBridge::BridgePort::respQueueFull()
982784Ssaidi@eecs.umich.edu{
992784Ssaidi@eecs.umich.edu    assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit);
1002784Ssaidi@eecs.umich.edu    return outstandingResponses >= respQueueLimit;
1012565SN/A}
1023349Sbinkertn@umich.edu
1032384SN/Abool
1042901Ssaidi@eecs.umich.eduBridge::BridgePort::reqQueueFull()
1052565SN/A{
1062901Ssaidi@eecs.umich.edu    assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit);
1072565SN/A    return queuedRequests >= reqQueueLimit;
1082565SN/A}
1092565SN/A
1102384SN/A/** Function called by the port when the bus is receiving a Timing
1112901Ssaidi@eecs.umich.edu * transaction.*/
1122901Ssaidi@eecs.umich.edubool
1132901Ssaidi@eecs.umich.eduBridge::BridgePort::recvTiming(PacketPtr pkt)
1142901Ssaidi@eecs.umich.edu{
1152901Ssaidi@eecs.umich.edu    if (!(pkt->flags & SNOOP_COMMIT))
1162901Ssaidi@eecs.umich.edu        return true;
1172901Ssaidi@eecs.umich.edu
1184435Ssaidi@eecs.umich.edu
1194435Ssaidi@eecs.umich.edu    DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
1204435Ssaidi@eecs.umich.edu                pkt->getSrc(), pkt->getDest(), pkt->getAddr());
1214435Ssaidi@eecs.umich.edu
1224435Ssaidi@eecs.umich.edu    DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
1234435Ssaidi@eecs.umich.edu                    sendQueue.size(), queuedRequests, outstandingResponses);
1244435Ssaidi@eecs.umich.edu    DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n",
1254435Ssaidi@eecs.umich.edu                    otherPort->sendQueue.size(), otherPort->queuedRequests,
1263349Sbinkertn@umich.edu                    otherPort->outstandingResponses);
1273349Sbinkertn@umich.edu
1283918Ssaidi@eecs.umich.edu    if (pkt->isRequest() && otherPort->reqQueueFull() && pkt->result !=
1293349Sbinkertn@umich.edu            Packet::Nacked) {
1302384SN/A        DPRINTF(BusBridge, "Remote queue full, nacking\n");
1312384SN/A        nackRequest(pkt);
1322384SN/A        return true;
1332384SN/A    }
1342384SN/A
1352657Ssaidi@eecs.umich.edu    if (pkt->needsResponse() && pkt->result != Packet::Nacked)
1362384SN/A        if (respQueueFull()) {
1373090Sstever@eecs.umich.edu            DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
1384475Sstever@eecs.umich.edu            DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
1394475Sstever@eecs.umich.edu                    sendQueue.size(), queuedRequests, outstandingResponses);
1402384SN/A            nackRequest(pkt);
1414435Ssaidi@eecs.umich.edu            return true;
1424435Ssaidi@eecs.umich.edu        } else {
1434435Ssaidi@eecs.umich.edu            DPRINTF(BusBridge, "Request Needs response, reserving space\n");
1444435Ssaidi@eecs.umich.edu            ++outstandingResponses;
1454435Ssaidi@eecs.umich.edu        }
1462489SN/A
1472384SN/A    otherPort->queueForSendTiming(pkt);
1482901Ssaidi@eecs.umich.edu
1492565SN/A    return true;
1502641Sstever@eecs.umich.edu}
1515534Ssaidi@eecs.umich.edu
1522565SN/Avoid
1532565SN/ABridge::BridgePort::nackRequest(PacketPtr pkt)
1542384SN/A{
1554263Ssaidi@eecs.umich.edu    // Nack the packet
1562901Ssaidi@eecs.umich.edu    pkt->result = Packet::Nacked;
1572384SN/A    pkt->setDest(pkt->getSrc());
1582384SN/A
1592489SN/A    //put it on the list to send
1602489SN/A    Tick readyTime = curTick + nackDelay;
1612489SN/A    PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true);
1622489SN/A
1632489SN/A    // nothing on the list, add it and we're done
1642489SN/A    if (sendQueue.empty()) {
1652489SN/A        assert(!sendEvent.scheduled());
1662542SN/A        sendEvent.schedule(readyTime);
1672384SN/A        sendQueue.push_back(buf);
1682384SN/A        return;
1692384SN/A    }
1702489SN/A
1712489SN/A    assert(sendEvent.scheduled() || inRetry);
1721310SN/A
1732384SN/A    // does it go at the end?
1742901Ssaidi@eecs.umich.edu    if (readyTime >= sendQueue.back()->ready) {
1752901Ssaidi@eecs.umich.edu        sendQueue.push_back(buf);
1762489SN/A        return;
1772489SN/A    }
1782384SN/A
1792384SN/A    // ok, somewhere in the middle, fun
1802521SN/A    std::list<PacketBuffer*>::iterator i = sendQueue.begin();
1812384SN/A    std::list<PacketBuffer*>::iterator end = sendQueue.end();
1823090Sstever@eecs.umich.edu    std::list<PacketBuffer*>::iterator begin = sendQueue.begin();
1833090Sstever@eecs.umich.edu    bool done = false;
1842523SN/A
1852523SN/A    while (i != end && !done) {
1862523SN/A        if (readyTime < (*i)->ready) {
1873349Sbinkertn@umich.edu            if (i == begin)
1882384SN/A                sendEvent.reschedule(readyTime);
1892489SN/A            sendQueue.insert(i,buf);
1902523SN/A            done = true;
1912523SN/A        }
1922523SN/A        i++;
1932523SN/A    }
1943349Sbinkertn@umich.edu    assert(done);
195545SN/A}
196545SN/A
1974762Snate@binkert.org
1984762Snate@binkert.orgvoid
1994762Snate@binkert.orgBridge::BridgePort::queueForSendTiming(PacketPtr pkt)
2004762Snate@binkert.org{
2014762Snate@binkert.org    if (pkt->isResponse() || pkt->result == Packet::Nacked) {
2024762Snate@binkert.org        // This is a response for a request we forwarded earlier.  The
2032512SN/A        // corresponding PacketBuffer should be stored in the packet's
2044762Snate@binkert.org        // senderState field.
2054762Snate@binkert.org        PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
2062384SN/A        assert(buf != NULL);
2072541SN/A        // set up new packet dest & senderState based on values saved
2082541SN/A        // from original request
2092901Ssaidi@eecs.umich.edu        buf->fixResponse(pkt);
2102901Ssaidi@eecs.umich.edu
2112738Sstever@eecs.umich.edu        // Check if this packet was expecting a response and it's a nacked
2122384SN/A        // packet, in which case we will never being seeing it
2132521SN/A        if (buf->expectResponse && pkt->result == Packet::Nacked)
2142512SN/A            --outstandingResponses;
2152512SN/A
2162901Ssaidi@eecs.umich.edu        DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
2172384SN/A        delete buf;
2182521SN/A    }
2192384SN/A
2202384SN/A
2212489SN/A    if (pkt->isRequest() && pkt->result != Packet::Nacked) {
2222489SN/A        ++queuedRequests;
223545SN/A    }
224545SN/A
2252512SN/A
2262512SN/A
2272512SN/A    Tick readyTime = curTick + delay;
2282512SN/A    PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
2292512SN/A
2302512SN/A    // If we're about to put this packet at the head of the queue, we
2312512SN/A    // need to schedule an event to do the transmit.  Otherwise there
2322521SN/A    // should already be an event scheduled for sending the head
2332512SN/A    // packet.
2342512SN/A    if (sendQueue.empty()) {
2352512SN/A        sendEvent.schedule(readyTime);
2362512SN/A    }
2372512SN/A    sendQueue.push_back(buf);
2384762Snate@binkert.org}
2394762Snate@binkert.org
2404762Snate@binkert.orgvoid
2414762Snate@binkert.orgBridge::BridgePort::trySend()
2424762Snate@binkert.org{
2434762Snate@binkert.org    assert(!sendQueue.empty());
2444762Snate@binkert.org
2454762Snate@binkert.org    PacketBuffer *buf = sendQueue.front();
2462512SN/A
2472539SN/A    assert(buf->ready <= curTick);
2482982Sstever@eecs.umich.edu
2492539SN/A    PacketPtr pkt = buf->pkt;
2502542SN/A
2512539SN/A    pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
2522512SN/A
2532512SN/A    // Ugly! @todo When multilevel coherence works this will be removed
254545SN/A    if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
255545SN/A            pkt->result != Packet::Nacked) {
2564435Ssaidi@eecs.umich.edu        PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
2572384SN/A                            Packet::Broadcast);
2584435Ssaidi@eecs.umich.edu        funcPkt->dataStatic(pkt->getPtr<uint8_t>());
2594435Ssaidi@eecs.umich.edu        sendFunctional(funcPkt);
260545SN/A        pkt->cmd = MemCmd::WriteReq;
261545SN/A        delete funcPkt;
2624762Snate@binkert.org    }
2634762Snate@binkert.org
264545SN/A    DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
2652384SN/A            buf->origSrc, pkt->getDest(), pkt->getAddr());
2664762Snate@binkert.org
2674762Snate@binkert.org    bool wasReq = pkt->isRequest();
2684762Snate@binkert.org    bool wasNacked = pkt->result == Packet::Nacked;
2694762Snate@binkert.org
2704762Snate@binkert.org    if (sendTiming(pkt)) {
2714762Snate@binkert.org        // send successful
2725534Ssaidi@eecs.umich.edu        sendQueue.pop_front();
2734022Sstever@eecs.umich.edu        buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it
2745534Ssaidi@eecs.umich.edu
2754022Sstever@eecs.umich.edu        if (buf->expectResponse) {
2762565SN/A            // Must wait for response
2775534Ssaidi@eecs.umich.edu            DPRINTF(BusBridge, "  successful: awaiting response (%d)\n",
2784263Ssaidi@eecs.umich.edu                    outstandingResponses);
2795534Ssaidi@eecs.umich.edu        } else {
2804263Ssaidi@eecs.umich.edu            // no response expected... deallocate packet buffer now.
2812565SN/A            DPRINTF(BusBridge, "  successful: no response expected\n");
2822565SN/A            delete buf;
2832565SN/A        }
2842901Ssaidi@eecs.umich.edu
2852901Ssaidi@eecs.umich.edu        if (!wasNacked) {
2864263Ssaidi@eecs.umich.edu            if (wasReq)
2874263Ssaidi@eecs.umich.edu                --queuedRequests;
2882738Sstever@eecs.umich.edu            else
2892384SN/A                --outstandingResponses;
2902565SN/A        }
2912565SN/A
2922565SN/A        // If there are more packets to send, schedule event to try again.
2932901Ssaidi@eecs.umich.edu        if (!sendQueue.empty()) {
2942384SN/A            buf = sendQueue.front();
2952565SN/A            DPRINTF(BusBridge, "Scheduling next send\n");
2962565SN/A            sendEvent.schedule(std::max(buf->ready, curTick + 1));
2972565SN/A        }
2982901Ssaidi@eecs.umich.edu    } else {
2992384SN/A        DPRINTF(BusBridge, "  unsuccessful\n");
3002565SN/A        inRetry = true;
3012384SN/A    }
3022384SN/A    DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
3032489SN/A                    sendQueue.size(), queuedRequests, outstandingResponses);
3042489SN/A}
305545SN/A
306545SN/A
3072384SN/Avoid
3081310SN/ABridge::BridgePort::recvRetry()
309{
310    inRetry = false;
311    Tick nextReady = sendQueue.front()->ready;
312    if (nextReady <= curTick)
313        trySend();
314    else
315        sendEvent.schedule(nextReady);
316}
317
318/** Function called by the port when the bus is receiving a Atomic
319 * transaction.*/
320Tick
321Bridge::BridgePort::recvAtomic(PacketPtr pkt)
322{
323    // fix partial atomic writes... similar to the timing code that does the
324    // same... will be removed once our code gets this right
325    if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite) {
326
327        PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
328                         Packet::Broadcast);
329        funcPkt->dataStatic(pkt->getPtr<uint8_t>());
330        otherPort->sendFunctional(funcPkt);
331        delete funcPkt;
332        pkt->cmd = MemCmd::WriteReq;
333    }
334    return delay + otherPort->sendAtomic(pkt);
335}
336
337/** Function called by the port when the bus is receiving a Functional
338 * transaction.*/
339void
340Bridge::BridgePort::recvFunctional(PacketPtr pkt)
341{
342    std::list<PacketBuffer*>::iterator i;
343    bool pktContinue = true;
344
345    for (i = sendQueue.begin();  i != sendQueue.end(); ++i) {
346        if (pkt->intersect((*i)->pkt)) {
347            pktContinue &= fixPacket(pkt, (*i)->pkt);
348        }
349    }
350
351    if (pktContinue) {
352        otherPort->sendFunctional(pkt);
353    }
354}
355
356/** Function called by the port when the bus is receiving a status change.*/
357void
358Bridge::BridgePort::recvStatusChange(Port::Status status)
359{
360    otherPort->sendStatusChange(status);
361}
362
363void
364Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp,
365                                           bool &snoop)
366{
367    otherPort->getPeerAddressRanges(resp, snoop);
368}
369
370Bridge *
371BridgeParams::create()
372{
373    return new Bridge(this);
374}
375