bridge.cc revision 4435
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 "sim/builder.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 if (pkt->isRequest() && otherPort->reqQueueFull()) { 12312855Sgabeblack@google.com DPRINTF(BusBridge, "Remote queue full, nacking\n"); 12412855Sgabeblack@google.com nackRequest(pkt); 12512855Sgabeblack@google.com return true; 12612855Sgabeblack@google.com } 12712855Sgabeblack@google.com 12812855Sgabeblack@google.com if (pkt->needsResponse() && pkt->result != Packet::Nacked) 12912855Sgabeblack@google.com if (respQueueFull()) { 13012855Sgabeblack@google.com DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 13112855Sgabeblack@google.com DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 13212855Sgabeblack@google.com sendQueue.size(), queuedRequests, outstandingResponses); 13312855Sgabeblack@google.com nackRequest(pkt); 13412855Sgabeblack@google.com return true; 13512855Sgabeblack@google.com } else { 13612855Sgabeblack@google.com DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 13712855Sgabeblack@google.com ++outstandingResponses; 13812855Sgabeblack@google.com } 13912855Sgabeblack@google.com 14012855Sgabeblack@google.com otherPort->queueForSendTiming(pkt); 14112855Sgabeblack@google.com 14212855Sgabeblack@google.com return true; 14312855Sgabeblack@google.com} 14412855Sgabeblack@google.com 14512855Sgabeblack@google.comvoid 14612855Sgabeblack@google.comBridge::BridgePort::nackRequest(PacketPtr pkt) 14712855Sgabeblack@google.com{ 14812855Sgabeblack@google.com // Nack the packet 14912855Sgabeblack@google.com pkt->result = Packet::Nacked; 15012855Sgabeblack@google.com pkt->setDest(pkt->getSrc()); 15112855Sgabeblack@google.com 15212855Sgabeblack@google.com //put it on the list to send 15312855Sgabeblack@google.com Tick readyTime = curTick + nackDelay; 15412855Sgabeblack@google.com PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 15512855Sgabeblack@google.com 15612855Sgabeblack@google.com // nothing on the list, add it and we're done 15712855Sgabeblack@google.com if (sendQueue.empty()) { 15812855Sgabeblack@google.com assert(!sendEvent.scheduled()); 15912855Sgabeblack@google.com sendEvent.schedule(readyTime); 16012855Sgabeblack@google.com sendQueue.push_back(buf); 16112855Sgabeblack@google.com return; 16212855Sgabeblack@google.com } 16312855Sgabeblack@google.com 16412855Sgabeblack@google.com assert(sendEvent.scheduled() || inRetry); 165 166 // does it go at the end? 167 if (readyTime >= sendQueue.back()->ready) { 168 sendQueue.push_back(buf); 169 return; 170 } 171 172 // ok, somewhere in the middle, fun 173 std::list<PacketBuffer*>::iterator i = sendQueue.begin(); 174 std::list<PacketBuffer*>::iterator end = sendQueue.end(); 175 std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); 176 bool done = false; 177 178 while (i != end && !done) { 179 if (readyTime < (*i)->ready) { 180 if (i == begin) 181 sendEvent.reschedule(readyTime); 182 sendQueue.insert(i,buf); 183 done = true; 184 } 185 i++; 186 } 187 assert(done); 188} 189 190 191void 192Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 193{ 194 if (pkt->isResponse() || pkt->result == Packet::Nacked) { 195 // This is a response for a request we forwarded earlier. The 196 // corresponding PacketBuffer should be stored in the packet's 197 // senderState field. 198 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 199 assert(buf != NULL); 200 // set up new packet dest & senderState based on values saved 201 // from original request 202 buf->fixResponse(pkt); 203 204 // Check if this packet was expecting a response (this is either it or 205 // its a nacked packet and we won't be seeing that response) 206 if (buf->expectResponse) 207 --outstandingResponses; 208 209 210 DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", 211 pkt->senderState, buf); 212 DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); 213 delete buf; 214 } 215 216 Tick readyTime = curTick + delay; 217 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 218 DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", 219 buf->origSenderState, buf); 220 221 // If we're about to put this packet at the head of the queue, we 222 // need to schedule an event to do the transmit. Otherwise there 223 // should already be an event scheduled for sending the head 224 // packet. 225 if (sendQueue.empty()) { 226 sendEvent.schedule(readyTime); 227 } 228 ++queuedRequests; 229 sendQueue.push_back(buf); 230} 231 232void 233Bridge::BridgePort::trySend() 234{ 235 assert(!sendQueue.empty()); 236 237 int pbs = peerBlockSize(); 238 239 PacketBuffer *buf = sendQueue.front(); 240 241 assert(buf->ready <= curTick); 242 243 PacketPtr pkt = buf->pkt; 244 245 pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set 246 247 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 248 pkt->result != Packet::Nacked && pkt->getOffset(pbs) && 249 pkt->getSize() != pbs) { 250 buf->partialWriteFix(this); 251 pkt = buf->pkt; 252 } 253 254 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 255 buf->origSrc, pkt->getDest(), pkt->getAddr()); 256 257 258 if (sendTiming(pkt)) { 259 // send successful 260 sendQueue.pop_front(); 261 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 262 263 if (buf->expectResponse) { 264 // Must wait for response 265 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 266 outstandingResponses); 267 } else { 268 // no response expected... deallocate packet buffer now. 269 DPRINTF(BusBridge, " successful: no response expected\n"); 270 delete buf; 271 } 272 273 if (!buf->nacked) 274 --queuedRequests; 275 276 // If there are more packets to send, schedule event to try again. 277 if (!sendQueue.empty()) { 278 buf = sendQueue.front(); 279 DPRINTF(BusBridge, "Scheduling next send\n"); 280 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 281 } 282 } else { 283 DPRINTF(BusBridge, " unsuccessful\n"); 284 buf->undoPartialWriteFix(); 285 inRetry = true; 286 } 287 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 288 sendQueue.size(), queuedRequests, outstandingResponses); 289} 290 291 292void 293Bridge::BridgePort::recvRetry() 294{ 295 inRetry = false; 296 Tick nextReady = sendQueue.front()->ready; 297 if (nextReady <= curTick) 298 trySend(); 299 else 300 sendEvent.schedule(nextReady); 301} 302 303/** Function called by the port when the bus is receiving a Atomic 304 * transaction.*/ 305Tick 306Bridge::BridgePort::recvAtomic(PacketPtr pkt) 307{ 308 return otherPort->sendAtomic(pkt) + delay; 309} 310 311/** Function called by the port when the bus is receiving a Functional 312 * transaction.*/ 313void 314Bridge::BridgePort::recvFunctional(PacketPtr pkt) 315{ 316 std::list<PacketBuffer*>::iterator i; 317 bool pktContinue = true; 318 319 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 320 if (pkt->intersect((*i)->pkt)) { 321 pktContinue &= fixPacket(pkt, (*i)->pkt); 322 } 323 } 324 325 if (pktContinue) { 326 otherPort->sendFunctional(pkt); 327 } 328} 329 330/** Function called by the port when the bus is receiving a status change.*/ 331void 332Bridge::BridgePort::recvStatusChange(Port::Status status) 333{ 334 otherPort->sendStatusChange(status); 335} 336 337void 338Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 339 AddrRangeList &snoop) 340{ 341 otherPort->getPeerAddressRanges(resp, snoop); 342} 343 344BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 345 346 Param<int> req_size_a; 347 Param<int> req_size_b; 348 Param<int> resp_size_a; 349 Param<int> resp_size_b; 350 Param<Tick> delay; 351 Param<Tick> nack_delay; 352 Param<bool> write_ack; 353 Param<bool> fix_partial_write_a; 354 Param<bool> fix_partial_write_b; 355 356END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 357 358BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 359 360 INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"), 361 INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"), 362 INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"), 363 INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"), 364 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 365 INIT_PARAM(nack_delay, "The minimum delay to nack a packet"), 366 INIT_PARAM(write_ack, "Acknowledge any writes that are received."), 367 INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), 368 INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") 369 370END_INIT_SIM_OBJECT_PARAMS(Bridge) 371 372CREATE_SIM_OBJECT(Bridge) 373{ 374 Bridge::Params *p = new Bridge::Params; 375 p->name = getInstanceName(); 376 p->req_size_a = req_size_a; 377 p->req_size_b = req_size_b; 378 p->resp_size_a = resp_size_a; 379 p->resp_size_b = resp_size_b; 380 p->delay = delay; 381 p->nack_delay = nack_delay; 382 p->write_ack = write_ack; 383 p->fix_partial_write_a = fix_partial_write_a; 384 p->fix_partial_write_b = fix_partial_write_b; 385 return new Bridge(p); 386} 387 388REGISTER_SIM_OBJECT("Bridge", Bridge) 389 390