bridge.cc revision 4450
14604Sgblack@eecs.umich.edu 24604Sgblack@eecs.umich.edu/* 34604Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 44604Sgblack@eecs.umich.edu * All rights reserved. 54604Sgblack@eecs.umich.edu * 64604Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 74604Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 84604Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 94604Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 104604Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 114604Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 124604Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 134604Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 144604Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 154604Sgblack@eecs.umich.edu * this software without specific prior written permission. 164604Sgblack@eecs.umich.edu * 174604Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 184604Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 194604Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 204604Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 214604Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 224604Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 234604Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 244604Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 254604Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 264604Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 274604Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 284604Sgblack@eecs.umich.edu * 294604Sgblack@eecs.umich.edu * Authors: Ali Saidi 304604Sgblack@eecs.umich.edu * Steve Reinhardt 314604Sgblack@eecs.umich.edu */ 324604Sgblack@eecs.umich.edu 334604Sgblack@eecs.umich.edu/** 344604Sgblack@eecs.umich.edu * @file 354604Sgblack@eecs.umich.edu * Definition of a simple bus bridge without buffering. 364604Sgblack@eecs.umich.edu */ 374604Sgblack@eecs.umich.edu 384604Sgblack@eecs.umich.edu#include <algorithm> 394604Sgblack@eecs.umich.edu 404604Sgblack@eecs.umich.edu#include "base/trace.hh" 414604Sgblack@eecs.umich.edu#include "mem/bridge.hh" 424604Sgblack@eecs.umich.edu#include "sim/builder.hh" 434604Sgblack@eecs.umich.edu 444604Sgblack@eecs.umich.eduBridge::BridgePort::BridgePort(const std::string &_name, 454604Sgblack@eecs.umich.edu Bridge *_bridge, BridgePort *_otherPort, 464604Sgblack@eecs.umich.edu int _delay, int _nack_delay, int _req_limit, 474604Sgblack@eecs.umich.edu int _resp_limit, bool fix_partial_write) 484604Sgblack@eecs.umich.edu : Port(_name), bridge(_bridge), otherPort(_otherPort), 494604Sgblack@eecs.umich.edu delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write), 504604Sgblack@eecs.umich.edu outstandingResponses(0), queuedRequests(0), inRetry(false), 514604Sgblack@eecs.umich.edu reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) 524604Sgblack@eecs.umich.edu{ 534604Sgblack@eecs.umich.edu} 544604Sgblack@eecs.umich.edu 554604Sgblack@eecs.umich.eduBridge::Bridge(Params *p) 564604Sgblack@eecs.umich.edu : MemObject(p->name), 574604Sgblack@eecs.umich.edu portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, 584604Sgblack@eecs.umich.edu p->req_size_a, p->resp_size_a, p->fix_partial_write_a), 594604Sgblack@eecs.umich.edu portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, 604604Sgblack@eecs.umich.edu p->req_size_b, p->resp_size_b, p->fix_partial_write_b), 614863Sgblack@eecs.umich.edu ackWrites(p->write_ack), _params(p) 624863Sgblack@eecs.umich.edu{ 634604Sgblack@eecs.umich.edu if (ackWrites) 644604Sgblack@eecs.umich.edu panic("No support for acknowledging writes\n"); 654604Sgblack@eecs.umich.edu} 664604Sgblack@eecs.umich.edu 674604Sgblack@eecs.umich.eduPort * 684604Sgblack@eecs.umich.eduBridge::getPort(const std::string &if_name, int idx) 694604Sgblack@eecs.umich.edu{ 704604Sgblack@eecs.umich.edu BridgePort *port; 714863Sgblack@eecs.umich.edu 724604Sgblack@eecs.umich.edu if (if_name == "side_a") 734604Sgblack@eecs.umich.edu port = &portA; 744604Sgblack@eecs.umich.edu else if (if_name == "side_b") 754604Sgblack@eecs.umich.edu port = &portB; 764604Sgblack@eecs.umich.edu else 774604Sgblack@eecs.umich.edu return NULL; 784604Sgblack@eecs.umich.edu 794604Sgblack@eecs.umich.edu if (port->getPeer() != NULL) 804604Sgblack@eecs.umich.edu panic("bridge side %s already connected to.", if_name); 814863Sgblack@eecs.umich.edu return port; 824604Sgblack@eecs.umich.edu} 834604Sgblack@eecs.umich.edu 844604Sgblack@eecs.umich.edu 854604Sgblack@eecs.umich.eduvoid 864604Sgblack@eecs.umich.eduBridge::init() 874604Sgblack@eecs.umich.edu{ 884604Sgblack@eecs.umich.edu // Make sure that both sides are connected to. 895966Sgblack@eecs.umich.edu if (portA.getPeer() == NULL || portB.getPeer() == NULL) 904604Sgblack@eecs.umich.edu fatal("Both ports of bus bridge are not connected to a bus.\n"); 914604Sgblack@eecs.umich.edu 924604Sgblack@eecs.umich.edu if (portA.peerBlockSize() != portB.peerBlockSize()) 934604Sgblack@eecs.umich.edu fatal("Busses don't have the same block size... Not supported.\n"); 94} 95 96bool 97Bridge::BridgePort::respQueueFull() 98{ 99 assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit); 100 return outstandingResponses >= respQueueLimit; 101} 102 103bool 104Bridge::BridgePort::reqQueueFull() 105{ 106 assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit); 107 return queuedRequests >= reqQueueLimit; 108} 109 110/** Function called by the port when the bus is receiving a Timing 111 * transaction.*/ 112bool 113Bridge::BridgePort::recvTiming(PacketPtr pkt) 114{ 115 if (!(pkt->flags & SNOOP_COMMIT)) 116 return true; 117 118 119 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 120 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 121 122 DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n", 123 sendQueue.size(), queuedRequests, outstandingResponses); 124 DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n", 125 otherPort->sendQueue.size(), otherPort->queuedRequests, 126 otherPort->outstandingResponses); 127 128 if (pkt->isRequest() && otherPort->reqQueueFull() && pkt->result != 129 Packet::Nacked) { 130 DPRINTF(BusBridge, "Remote queue full, nacking\n"); 131 nackRequest(pkt); 132 return true; 133 } 134 135 if (pkt->needsResponse() && pkt->result != Packet::Nacked) 136 if (respQueueFull()) { 137 DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 138 DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 139 sendQueue.size(), queuedRequests, outstandingResponses); 140 nackRequest(pkt); 141 return true; 142 } else { 143 DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 144 ++outstandingResponses; 145 } 146 147 otherPort->queueForSendTiming(pkt); 148 149 return true; 150} 151 152void 153Bridge::BridgePort::nackRequest(PacketPtr pkt) 154{ 155 // Nack the packet 156 pkt->result = Packet::Nacked; 157 pkt->setDest(pkt->getSrc()); 158 159 //put it on the list to send 160 Tick readyTime = curTick + nackDelay; 161 PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 162 163 // nothing on the list, add it and we're done 164 if (sendQueue.empty()) { 165 assert(!sendEvent.scheduled()); 166 sendEvent.schedule(readyTime); 167 sendQueue.push_back(buf); 168 return; 169 } 170 171 assert(sendEvent.scheduled() || inRetry); 172 173 // does it go at the end? 174 if (readyTime >= sendQueue.back()->ready) { 175 sendQueue.push_back(buf); 176 return; 177 } 178 179 // ok, somewhere in the middle, fun 180 std::list<PacketBuffer*>::iterator i = sendQueue.begin(); 181 std::list<PacketBuffer*>::iterator end = sendQueue.end(); 182 std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); 183 bool done = false; 184 185 while (i != end && !done) { 186 if (readyTime < (*i)->ready) { 187 if (i == begin) 188 sendEvent.reschedule(readyTime); 189 sendQueue.insert(i,buf); 190 done = true; 191 } 192 i++; 193 } 194 assert(done); 195} 196 197 198void 199Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 200{ 201 if (pkt->isResponse() || pkt->result == Packet::Nacked) { 202 // This is a response for a request we forwarded earlier. The 203 // corresponding PacketBuffer should be stored in the packet's 204 // senderState field. 205 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 206 assert(buf != NULL); 207 // set up new packet dest & senderState based on values saved 208 // from original request 209 buf->fixResponse(pkt); 210 211 // Check if this packet was expecting a response and it's a nacked 212 // packet, in which case we will never being seeing it 213 if (buf->expectResponse && pkt->result == Packet::Nacked) 214 --outstandingResponses; 215 216 217 DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", 218 pkt->senderState, buf); 219 DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); 220 delete buf; 221 } 222 223 224 if (pkt->isRequest() && pkt->result != Packet::Nacked) { 225 ++queuedRequests; 226 } 227 228 229 230 Tick readyTime = curTick + delay; 231 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 232 DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", 233 buf->origSenderState, buf); 234 235 // If we're about to put this packet at the head of the queue, we 236 // need to schedule an event to do the transmit. Otherwise there 237 // should already be an event scheduled for sending the head 238 // packet. 239 if (sendQueue.empty()) { 240 sendEvent.schedule(readyTime); 241 } 242 sendQueue.push_back(buf); 243} 244 245void 246Bridge::BridgePort::trySend() 247{ 248 assert(!sendQueue.empty()); 249 250 int pbs = peerBlockSize(); 251 252 PacketBuffer *buf = sendQueue.front(); 253 254 assert(buf->ready <= curTick); 255 256 PacketPtr pkt = buf->pkt; 257 258 pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set 259 260 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 261 pkt->result != Packet::Nacked && pkt->getOffset(pbs) && 262 pkt->getSize() != pbs) { 263 buf->partialWriteFix(this); 264 pkt = buf->pkt; 265 } 266 267 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 268 buf->origSrc, pkt->getDest(), pkt->getAddr()); 269 270 bool wasReq = pkt->isRequest(); 271 bool wasNacked = pkt->result == Packet::Nacked; 272 273 if (sendTiming(pkt)) { 274 // send successful 275 sendQueue.pop_front(); 276 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 277 278 if (buf->expectResponse) { 279 // Must wait for response 280 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 281 outstandingResponses); 282 } else { 283 // no response expected... deallocate packet buffer now. 284 DPRINTF(BusBridge, " successful: no response expected\n"); 285 delete buf; 286 } 287 288 if (!wasNacked) { 289 if (wasReq) 290 --queuedRequests; 291 else 292 --outstandingResponses; 293 } 294 295 // If there are more packets to send, schedule event to try again. 296 if (!sendQueue.empty()) { 297 buf = sendQueue.front(); 298 DPRINTF(BusBridge, "Scheduling next send\n"); 299 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 300 } 301 } else { 302 DPRINTF(BusBridge, " unsuccessful\n"); 303 buf->undoPartialWriteFix(); 304 inRetry = true; 305 } 306 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 307 sendQueue.size(), queuedRequests, outstandingResponses); 308} 309 310 311void 312Bridge::BridgePort::recvRetry() 313{ 314 inRetry = false; 315 Tick nextReady = sendQueue.front()->ready; 316 if (nextReady <= curTick) 317 trySend(); 318 else 319 sendEvent.schedule(nextReady); 320} 321 322/** Function called by the port when the bus is receiving a Atomic 323 * transaction.*/ 324Tick 325Bridge::BridgePort::recvAtomic(PacketPtr pkt) 326{ 327 int pbs = otherPort->peerBlockSize(); 328 Tick atomic_delay; 329 // fix partial atomic writes... similar to the timing code that does the 330 // same 331 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 332 pkt->getOffset(pbs) && pkt->getSize() != pbs) { 333 PacketDataPtr data; 334 data = new uint8_t[pbs]; 335 PacketPtr funcPkt = new Packet(pkt->req, MemCmd::ReadReq, 336 Packet::Broadcast, pbs); 337 338 funcPkt->dataStatic(data); 339 otherPort->sendFunctional(funcPkt); 340 assert(funcPkt->result == Packet::Success); 341 delete funcPkt; 342 memcpy(data + pkt->getOffset(pbs), pkt->getPtr<uint8_t>(), 343 pkt->getSize()); 344 PacketPtr newPkt = new Packet(pkt->req, MemCmd::WriteInvalidateReq, 345 Packet::Broadcast, pbs); 346 pkt->dataDynamicArray(data); 347 atomic_delay = otherPort->sendAtomic(newPkt); 348 delete newPkt; 349 } else { 350 atomic_delay = otherPort->sendAtomic(pkt); 351 } 352 return atomic_delay + delay; 353} 354 355/** Function called by the port when the bus is receiving a Functional 356 * transaction.*/ 357void 358Bridge::BridgePort::recvFunctional(PacketPtr pkt) 359{ 360 std::list<PacketBuffer*>::iterator i; 361 bool pktContinue = true; 362 363 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 364 if (pkt->intersect((*i)->pkt)) { 365 pktContinue &= fixPacket(pkt, (*i)->pkt); 366 } 367 } 368 369 if (pktContinue) { 370 otherPort->sendFunctional(pkt); 371 } 372} 373 374/** Function called by the port when the bus is receiving a status change.*/ 375void 376Bridge::BridgePort::recvStatusChange(Port::Status status) 377{ 378 otherPort->sendStatusChange(status); 379} 380 381void 382Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 383 AddrRangeList &snoop) 384{ 385 otherPort->getPeerAddressRanges(resp, snoop); 386} 387 388BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 389 390 Param<int> req_size_a; 391 Param<int> req_size_b; 392 Param<int> resp_size_a; 393 Param<int> resp_size_b; 394 Param<Tick> delay; 395 Param<Tick> nack_delay; 396 Param<bool> write_ack; 397 Param<bool> fix_partial_write_a; 398 Param<bool> fix_partial_write_b; 399 400END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 401 402BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 403 404 INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"), 405 INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"), 406 INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"), 407 INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"), 408 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 409 INIT_PARAM(nack_delay, "The minimum delay to nack a packet"), 410 INIT_PARAM(write_ack, "Acknowledge any writes that are received."), 411 INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), 412 INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") 413 414END_INIT_SIM_OBJECT_PARAMS(Bridge) 415 416CREATE_SIM_OBJECT(Bridge) 417{ 418 Bridge::Params *p = new Bridge::Params; 419 p->name = getInstanceName(); 420 p->req_size_a = req_size_a; 421 p->req_size_b = req_size_b; 422 p->resp_size_a = resp_size_a; 423 p->resp_size_b = resp_size_b; 424 p->delay = delay; 425 p->nack_delay = nack_delay; 426 p->write_ack = write_ack; 427 p->fix_partial_write_a = fix_partial_write_a; 428 p->fix_partial_write_b = fix_partial_write_b; 429 return new Bridge(p); 430} 431 432REGISTER_SIM_OBJECT("Bridge", Bridge) 433 434