bridge.cc revision 4762
112855Sgabeblack@google.com 212855Sgabeblack@google.com/* 312855Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan 412855Sgabeblack@google.com * All rights reserved. 512855Sgabeblack@google.com * 612855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 712855Sgabeblack@google.com * modification, are permitted provided that the following conditions are 812855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 912855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 1012855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1112855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1212855Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1312855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1412855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1512855Sgabeblack@google.com * this software without specific prior written permission. 1612855Sgabeblack@google.com * 1712855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1812855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1912855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2012855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2112855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2212855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2312855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2412855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2512855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2612855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2712855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2812855Sgabeblack@google.com * 2912855Sgabeblack@google.com * Authors: Ali Saidi 3012855Sgabeblack@google.com * Steve Reinhardt 3112855Sgabeblack@google.com */ 3212855Sgabeblack@google.com 3312855Sgabeblack@google.com/** 3412855Sgabeblack@google.com * @file 3512855Sgabeblack@google.com * Definition of a simple bus bridge without buffering. 3612855Sgabeblack@google.com */ 3712855Sgabeblack@google.com 3812855Sgabeblack@google.com#include <algorithm> 3912855Sgabeblack@google.com 4012855Sgabeblack@google.com#include "base/trace.hh" 4112855Sgabeblack@google.com#include "mem/bridge.hh" 4212855Sgabeblack@google.com#include "params/Bridge.hh" 4312855Sgabeblack@google.com 4412855Sgabeblack@google.comBridge::BridgePort::BridgePort(const std::string &_name, 4512855Sgabeblack@google.com Bridge *_bridge, BridgePort *_otherPort, 4612855Sgabeblack@google.com int _delay, int _nack_delay, int _req_limit, 4712855Sgabeblack@google.com int _resp_limit, bool fix_partial_write) 4812855Sgabeblack@google.com : Port(_name), bridge(_bridge), otherPort(_otherPort), 4912855Sgabeblack@google.com delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write), 5012855Sgabeblack@google.com outstandingResponses(0), queuedRequests(0), inRetry(false), 5112855Sgabeblack@google.com reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) 5212855Sgabeblack@google.com{ 5312855Sgabeblack@google.com} 5412855Sgabeblack@google.com 5512855Sgabeblack@google.comBridge::Bridge(Params *p) 5612855Sgabeblack@google.com : MemObject(p->name), 5712855Sgabeblack@google.com portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, 5812855Sgabeblack@google.com p->req_size_a, p->resp_size_a, p->fix_partial_write_a), 5912855Sgabeblack@google.com portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, 6012855Sgabeblack@google.com p->req_size_b, p->resp_size_b, p->fix_partial_write_b), 6112855Sgabeblack@google.com ackWrites(p->write_ack), _params(p) 6212855Sgabeblack@google.com{ 6312855Sgabeblack@google.com if (ackWrites) 6412855Sgabeblack@google.com panic("No support for acknowledging writes\n"); 6512855Sgabeblack@google.com} 6612855Sgabeblack@google.com 6712855Sgabeblack@google.comPort * 6812855Sgabeblack@google.comBridge::getPort(const std::string &if_name, int idx) 6912855Sgabeblack@google.com{ 7012855Sgabeblack@google.com BridgePort *port; 7112855Sgabeblack@google.com 7212855Sgabeblack@google.com if (if_name == "side_a") 7312855Sgabeblack@google.com port = &portA; 7412855Sgabeblack@google.com else if (if_name == "side_b") 7512855Sgabeblack@google.com port = &portB; 7612855Sgabeblack@google.com else 7712855Sgabeblack@google.com return NULL; 7812855Sgabeblack@google.com 7912855Sgabeblack@google.com if (port->getPeer() != NULL) 8012855Sgabeblack@google.com panic("bridge side %s already connected to.", if_name); 8112855Sgabeblack@google.com return port; 8212855Sgabeblack@google.com} 8312855Sgabeblack@google.com 8412855Sgabeblack@google.com 8512855Sgabeblack@google.comvoid 8612855Sgabeblack@google.comBridge::init() 8712855Sgabeblack@google.com{ 8812855Sgabeblack@google.com // Make sure that both sides are connected to. 8912855Sgabeblack@google.com if (portA.getPeer() == NULL || portB.getPeer() == NULL) 9012855Sgabeblack@google.com fatal("Both ports of bus bridge are not connected to a bus.\n"); 9112855Sgabeblack@google.com 9212855Sgabeblack@google.com if (portA.peerBlockSize() != portB.peerBlockSize()) 9312855Sgabeblack@google.com fatal("Busses don't have the same block size... Not supported.\n"); 9412855Sgabeblack@google.com} 9512855Sgabeblack@google.com 9612855Sgabeblack@google.combool 9712855Sgabeblack@google.comBridge::BridgePort::respQueueFull() 9812855Sgabeblack@google.com{ 9912855Sgabeblack@google.com assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit); 10012855Sgabeblack@google.com return outstandingResponses >= respQueueLimit; 10112855Sgabeblack@google.com} 10212855Sgabeblack@google.com 10312855Sgabeblack@google.combool 10412855Sgabeblack@google.comBridge::BridgePort::reqQueueFull() 10512855Sgabeblack@google.com{ 10612855Sgabeblack@google.com assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit); 10712855Sgabeblack@google.com return queuedRequests >= reqQueueLimit; 10812855Sgabeblack@google.com} 10912855Sgabeblack@google.com 11012855Sgabeblack@google.com/** Function called by the port when the bus is receiving a Timing 11112855Sgabeblack@google.com * transaction.*/ 11212855Sgabeblack@google.combool 11312855Sgabeblack@google.comBridge::BridgePort::recvTiming(PacketPtr pkt) 11412855Sgabeblack@google.com{ 11512855Sgabeblack@google.com if (!(pkt->flags & SNOOP_COMMIT)) 11612855Sgabeblack@google.com return true; 11712855Sgabeblack@google.com 11812855Sgabeblack@google.com 11912855Sgabeblack@google.com DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 12012855Sgabeblack@google.com pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 12112855Sgabeblack@google.com 12212855Sgabeblack@google.com DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n", 12312855Sgabeblack@google.com sendQueue.size(), queuedRequests, outstandingResponses); 12412855Sgabeblack@google.com DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n", 12512855Sgabeblack@google.com otherPort->sendQueue.size(), otherPort->queuedRequests, 12612855Sgabeblack@google.com otherPort->outstandingResponses); 12712855Sgabeblack@google.com 12812855Sgabeblack@google.com if (pkt->isRequest() && otherPort->reqQueueFull() && pkt->result != 12912855Sgabeblack@google.com Packet::Nacked) { 13012855Sgabeblack@google.com DPRINTF(BusBridge, "Remote queue full, nacking\n"); 13112855Sgabeblack@google.com nackRequest(pkt); 13212855Sgabeblack@google.com return true; 13312855Sgabeblack@google.com } 13412855Sgabeblack@google.com 13512855Sgabeblack@google.com if (pkt->needsResponse() && pkt->result != Packet::Nacked) 13612855Sgabeblack@google.com if (respQueueFull()) { 13712855Sgabeblack@google.com DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 13812855Sgabeblack@google.com DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 13912855Sgabeblack@google.com sendQueue.size(), queuedRequests, outstandingResponses); 14012855Sgabeblack@google.com nackRequest(pkt); 14112855Sgabeblack@google.com return true; 14212855Sgabeblack@google.com } else { 14312855Sgabeblack@google.com DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 14412855Sgabeblack@google.com ++outstandingResponses; 14512855Sgabeblack@google.com } 14612855Sgabeblack@google.com 14712855Sgabeblack@google.com otherPort->queueForSendTiming(pkt); 14812855Sgabeblack@google.com 14912855Sgabeblack@google.com return true; 15012855Sgabeblack@google.com} 15112855Sgabeblack@google.com 15212855Sgabeblack@google.comvoid 15312855Sgabeblack@google.comBridge::BridgePort::nackRequest(PacketPtr pkt) 15412855Sgabeblack@google.com{ 15512855Sgabeblack@google.com // Nack the packet 15612855Sgabeblack@google.com pkt->result = Packet::Nacked; 15712855Sgabeblack@google.com pkt->setDest(pkt->getSrc()); 15812855Sgabeblack@google.com 15912855Sgabeblack@google.com //put it on the list to send 16012855Sgabeblack@google.com Tick readyTime = curTick + nackDelay; 16112855Sgabeblack@google.com PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 16212855Sgabeblack@google.com 16312855Sgabeblack@google.com // nothing on the list, add it and we're done 16412855Sgabeblack@google.com if (sendQueue.empty()) { 16512855Sgabeblack@google.com assert(!sendEvent.scheduled()); 16612855Sgabeblack@google.com sendEvent.schedule(readyTime); 16712855Sgabeblack@google.com sendQueue.push_back(buf); 16812855Sgabeblack@google.com return; 16912855Sgabeblack@google.com } 17012855Sgabeblack@google.com 17112855Sgabeblack@google.com assert(sendEvent.scheduled() || inRetry); 17212855Sgabeblack@google.com 17312855Sgabeblack@google.com // does it go at the end? 17412855Sgabeblack@google.com if (readyTime >= sendQueue.back()->ready) { 17512855Sgabeblack@google.com sendQueue.push_back(buf); 17612855Sgabeblack@google.com return; 17712855Sgabeblack@google.com } 17812855Sgabeblack@google.com 17912855Sgabeblack@google.com // ok, somewhere in the middle, fun 18012855Sgabeblack@google.com std::list<PacketBuffer*>::iterator i = sendQueue.begin(); 18112855Sgabeblack@google.com std::list<PacketBuffer*>::iterator end = sendQueue.end(); 18212855Sgabeblack@google.com std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); 18312855Sgabeblack@google.com bool done = false; 18412855Sgabeblack@google.com 18512855Sgabeblack@google.com while (i != end && !done) { 18612855Sgabeblack@google.com if (readyTime < (*i)->ready) { 18712855Sgabeblack@google.com if (i == begin) 18812855Sgabeblack@google.com sendEvent.reschedule(readyTime); 18912855Sgabeblack@google.com sendQueue.insert(i,buf); 19012855Sgabeblack@google.com done = true; 19112855Sgabeblack@google.com } 19212855Sgabeblack@google.com i++; 19312855Sgabeblack@google.com } 19412855Sgabeblack@google.com assert(done); 19512855Sgabeblack@google.com} 19612855Sgabeblack@google.com 19712855Sgabeblack@google.com 19812855Sgabeblack@google.comvoid 19912855Sgabeblack@google.comBridge::BridgePort::queueForSendTiming(PacketPtr pkt) 20012855Sgabeblack@google.com{ 20112855Sgabeblack@google.com if (pkt->isResponse() || pkt->result == Packet::Nacked) { 20212855Sgabeblack@google.com // This is a response for a request we forwarded earlier. The 20312855Sgabeblack@google.com // corresponding PacketBuffer should be stored in the packet's 20412855Sgabeblack@google.com // senderState field. 20512855Sgabeblack@google.com PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 20612855Sgabeblack@google.com assert(buf != NULL); 20712855Sgabeblack@google.com // set up new packet dest & senderState based on values saved 20812855Sgabeblack@google.com // from original request 20912855Sgabeblack@google.com buf->fixResponse(pkt); 21012855Sgabeblack@google.com 21112855Sgabeblack@google.com // Check if this packet was expecting a response and it's a nacked 21212855Sgabeblack@google.com // packet, in which case we will never being seeing it 21312855Sgabeblack@google.com if (buf->expectResponse && pkt->result == Packet::Nacked) 21412855Sgabeblack@google.com --outstandingResponses; 21512855Sgabeblack@google.com 21612855Sgabeblack@google.com DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest()); 21712855Sgabeblack@google.com delete buf; 21812855Sgabeblack@google.com } 21912855Sgabeblack@google.com 22012855Sgabeblack@google.com 22112855Sgabeblack@google.com if (pkt->isRequest() && pkt->result != Packet::Nacked) { 22212855Sgabeblack@google.com ++queuedRequests; 22312855Sgabeblack@google.com } 22412855Sgabeblack@google.com 22512855Sgabeblack@google.com 22612855Sgabeblack@google.com 22712855Sgabeblack@google.com Tick readyTime = curTick + delay; 22812855Sgabeblack@google.com PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 22912855Sgabeblack@google.com 23012855Sgabeblack@google.com // If we're about to put this packet at the head of the queue, we 23112855Sgabeblack@google.com // need to schedule an event to do the transmit. Otherwise there 23212855Sgabeblack@google.com // should already be an event scheduled for sending the head 23312855Sgabeblack@google.com // packet. 23412855Sgabeblack@google.com if (sendQueue.empty()) { 23512855Sgabeblack@google.com sendEvent.schedule(readyTime); 23612855Sgabeblack@google.com } 23712855Sgabeblack@google.com sendQueue.push_back(buf); 23812855Sgabeblack@google.com} 23912855Sgabeblack@google.com 24012855Sgabeblack@google.comvoid 24112855Sgabeblack@google.comBridge::BridgePort::trySend() 24212855Sgabeblack@google.com{ 24312855Sgabeblack@google.com assert(!sendQueue.empty()); 24412855Sgabeblack@google.com 24512855Sgabeblack@google.com PacketBuffer *buf = sendQueue.front(); 24612855Sgabeblack@google.com 24712855Sgabeblack@google.com assert(buf->ready <= curTick); 24812855Sgabeblack@google.com 24912855Sgabeblack@google.com PacketPtr pkt = buf->pkt; 25012855Sgabeblack@google.com 25112855Sgabeblack@google.com pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set 25212855Sgabeblack@google.com 25312855Sgabeblack@google.com // Ugly! @todo When multilevel coherence works this will be removed 25412855Sgabeblack@google.com if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 25512855Sgabeblack@google.com pkt->result != Packet::Nacked) { 25612855Sgabeblack@google.com PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq, 25712855Sgabeblack@google.com Packet::Broadcast); 25812855Sgabeblack@google.com funcPkt->dataStatic(pkt->getPtr<uint8_t>()); 25912855Sgabeblack@google.com sendFunctional(funcPkt); 26012855Sgabeblack@google.com pkt->cmd = MemCmd::WriteReq; 26112855Sgabeblack@google.com delete funcPkt; 26212855Sgabeblack@google.com } 26312855Sgabeblack@google.com 26412855Sgabeblack@google.com DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 26512855Sgabeblack@google.com buf->origSrc, pkt->getDest(), pkt->getAddr()); 26612855Sgabeblack@google.com 26712855Sgabeblack@google.com bool wasReq = pkt->isRequest(); 26812855Sgabeblack@google.com bool wasNacked = pkt->result == Packet::Nacked; 26912855Sgabeblack@google.com 27012855Sgabeblack@google.com if (sendTiming(pkt)) { 27112855Sgabeblack@google.com // send successful 27212855Sgabeblack@google.com sendQueue.pop_front(); 273 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 274 275 if (buf->expectResponse) { 276 // Must wait for response 277 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 278 outstandingResponses); 279 } else { 280 // no response expected... deallocate packet buffer now. 281 DPRINTF(BusBridge, " successful: no response expected\n"); 282 delete buf; 283 } 284 285 if (!wasNacked) { 286 if (wasReq) 287 --queuedRequests; 288 else 289 --outstandingResponses; 290 } 291 292 // If there are more packets to send, schedule event to try again. 293 if (!sendQueue.empty()) { 294 buf = sendQueue.front(); 295 DPRINTF(BusBridge, "Scheduling next send\n"); 296 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 297 } 298 } else { 299 DPRINTF(BusBridge, " unsuccessful\n"); 300 inRetry = true; 301 } 302 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 303 sendQueue.size(), queuedRequests, outstandingResponses); 304} 305 306 307void 308Bridge::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