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