1 2/* 3 * Copyright (c) 2006 The Regents of The University of Michigan 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Authors: Ali Saidi 30 * Steve Reinhardt 31 */ 32 33/** 34 * @file 35 * Definition of a simple bus bridge without buffering. 36 */ 37 38#include <algorithm> 39 40#include "base/trace.hh" 41#include "mem/bridge.hh" 42#include "sim/builder.hh" 43 44Bridge::BridgePort::BridgePort(const std::string &_name, 45 Bridge *_bridge, BridgePort *_otherPort, 46 int _delay, int _nack_delay, int _req_limit, 47 int _resp_limit, bool fix_partial_write) 48 : Port(_name), bridge(_bridge), otherPort(_otherPort), 49 delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write), 50 outstandingResponses(0), queuedRequests(0), inRetry(false), 51 reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) 52{ 53} 54 55Bridge::Bridge(Params *p) 56 : MemObject(p->name), 57 portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, 58 p->req_size_a, p->resp_size_a, p->fix_partial_write_a), 59 portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, 60 p->req_size_b, p->resp_size_b, p->fix_partial_write_b), 61 ackWrites(p->write_ack), _params(p) 62{ 63 if (ackWrites) 64 panic("No support for acknowledging writes\n"); 65} 66 67Port * 68Bridge::getPort(const std::string &if_name, int idx) 69{ 70 BridgePort *port; 71 72 if (if_name == "side_a") 73 port = &portA; 74 else if (if_name == "side_b") 75 port = &portB; 76 else 77 return NULL; 78 79 if (port->getPeer() != NULL) 80 panic("bridge side %s already connected to.", if_name); 81 return port; 82} 83 84 85void 86Bridge::init() 87{ 88 // Make sure that both sides are connected to. 89 if (portA.getPeer() == NULL || portB.getPeer() == NULL) 90 fatal("Both ports of bus bridge are not connected to a bus.\n"); 91 92 if (portA.peerBlockSize() != portB.peerBlockSize()) 93 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
|
115 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 116 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 117 118 DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n", 119 sendQueue.size(), queuedRequests, outstandingResponses); 120 DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n", 121 otherPort->sendQueue.size(), otherPort->queuedRequests, 122 otherPort->outstandingResponses); 123 124 if (pkt->isRequest() && otherPort->reqQueueFull() && pkt->result != 125 Packet::Nacked) { 126 DPRINTF(BusBridge, "Remote queue full, nacking\n"); 127 nackRequest(pkt); 128 return true; 129 } 130 131 if (pkt->needsResponse() && pkt->result != Packet::Nacked) 132 if (respQueueFull()) { 133 DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 134 DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 135 sendQueue.size(), queuedRequests, outstandingResponses); 136 nackRequest(pkt); 137 return true; 138 } else { 139 DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 140 ++outstandingResponses; 141 } 142 143 otherPort->queueForSendTiming(pkt); 144 145 return true; 146} 147 148void 149Bridge::BridgePort::nackRequest(PacketPtr pkt) 150{ 151 // Nack the packet 152 pkt->result = Packet::Nacked; 153 pkt->setDest(pkt->getSrc()); 154 155 //put it on the list to send 156 Tick readyTime = curTick + nackDelay; 157 PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 158 159 // nothing on the list, add it and we're done 160 if (sendQueue.empty()) { 161 assert(!sendEvent.scheduled()); 162 sendEvent.schedule(readyTime); 163 sendQueue.push_back(buf); 164 return; 165 } 166 167 assert(sendEvent.scheduled() || inRetry); 168 169 // does it go at the end? 170 if (readyTime >= sendQueue.back()->ready) { 171 sendQueue.push_back(buf); 172 return; 173 } 174 175 // ok, somewhere in the middle, fun 176 std::list<PacketBuffer*>::iterator i = sendQueue.begin(); 177 std::list<PacketBuffer*>::iterator end = sendQueue.end(); 178 std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); 179 bool done = false; 180 181 while (i != end && !done) { 182 if (readyTime < (*i)->ready) { 183 if (i == begin) 184 sendEvent.reschedule(readyTime); 185 sendQueue.insert(i,buf); 186 done = true; 187 } 188 i++; 189 } 190 assert(done); 191} 192 193 194void 195Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 196{ 197 if (pkt->isResponse() || pkt->result == Packet::Nacked) { 198 // This is a response for a request we forwarded earlier. The 199 // corresponding PacketBuffer should be stored in the packet's 200 // senderState field. 201 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 202 assert(buf != NULL); 203 // set up new packet dest & senderState based on values saved 204 // from original request 205 buf->fixResponse(pkt); 206 207 // Check if this packet was expecting a response and it's a nacked 208 // packet, in which case we will never being seeing it 209 if (buf->expectResponse && pkt->result == Packet::Nacked) 210 --outstandingResponses; 211 212 213 DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", 214 pkt->senderState, buf); 215 DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); 216 delete buf; 217 } 218 219 220 if (pkt->isRequest() && pkt->result != Packet::Nacked) { 221 ++queuedRequests; 222 } 223 224 225 226 Tick readyTime = curTick + delay; 227 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 228 DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", 229 buf->origSenderState, buf); 230 231 // If we're about to put this packet at the head of the queue, we 232 // need to schedule an event to do the transmit. Otherwise there 233 // should already be an event scheduled for sending the head 234 // packet. 235 if (sendQueue.empty()) { 236 sendEvent.schedule(readyTime); 237 } 238 sendQueue.push_back(buf); 239} 240 241void 242Bridge::BridgePort::trySend() 243{ 244 assert(!sendQueue.empty()); 245
|
246 int pbs = peerBlockSize(); 247 |
248 PacketBuffer *buf = sendQueue.front(); 249 250 assert(buf->ready <= curTick); 251 252 PacketPtr pkt = buf->pkt; 253
|
256 pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
257
258 // Ugly! @todo When multilevel coherence works this will be removed
|
254 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
|
260 pkt->result != Packet::Nacked) {
261 PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
262 Packet::Broadcast);
263 funcPkt->dataStatic(pkt->getPtr<uint8_t>());
264 sendFunctional(funcPkt);
265 pkt->cmd = MemCmd::WriteReq;
266 delete funcPkt;
|
255 pkt->result != Packet::Nacked && pkt->getOffset(pbs) && 256 pkt->getSize() != pbs) { 257 buf->partialWriteFix(this); 258 pkt = buf->pkt; |
259 } 260 261 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 262 buf->origSrc, pkt->getDest(), pkt->getAddr()); 263 264 bool wasReq = pkt->isRequest(); 265 bool wasNacked = pkt->result == Packet::Nacked; 266 267 if (sendTiming(pkt)) { 268 // send successful 269 sendQueue.pop_front(); 270 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 271 272 if (buf->expectResponse) { 273 // Must wait for response 274 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 275 outstandingResponses); 276 } else { 277 // no response expected... deallocate packet buffer now. 278 DPRINTF(BusBridge, " successful: no response expected\n"); 279 delete buf; 280 } 281 282 if (!wasNacked) { 283 if (wasReq) 284 --queuedRequests; 285 else 286 --outstandingResponses; 287 } 288 289 // If there are more packets to send, schedule event to try again. 290 if (!sendQueue.empty()) { 291 buf = sendQueue.front(); 292 DPRINTF(BusBridge, "Scheduling next send\n"); 293 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 294 } 295 } else { 296 DPRINTF(BusBridge, " unsuccessful\n");
|
297 buf->undoPartialWriteFix(); |
298 inRetry = true; 299 } 300 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 301 sendQueue.size(), queuedRequests, outstandingResponses); 302} 303 304 305void 306Bridge::BridgePort::recvRetry() 307{ 308 inRetry = false; 309 Tick nextReady = sendQueue.front()->ready; 310 if (nextReady <= curTick) 311 trySend(); 312 else 313 sendEvent.schedule(nextReady); 314} 315 316/** Function called by the port when the bus is receiving a Atomic 317 * transaction.*/ 318Tick 319Bridge::BridgePort::recvAtomic(PacketPtr pkt) 320{
|
321 int pbs = otherPort->peerBlockSize(); 322 Tick atomic_delay; |
323 // fix partial atomic writes... similar to the timing code that does the
|
329 // same... will be removed once our code gets this right
330 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite) {
|
324 // same 325 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 326 pkt->getOffset(pbs) && pkt->getSize() != pbs) { 327 PacketDataPtr data; 328 data = new uint8_t[pbs]; 329 PacketPtr funcPkt = new Packet(pkt->req, MemCmd::ReadReq, 330 Packet::Broadcast, pbs); |
331
|
332 PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
333 Packet::Broadcast);
334 funcPkt->dataStatic(pkt->getPtr<uint8_t>());
|
332 funcPkt->dataStatic(data); |
333 otherPort->sendFunctional(funcPkt);
|
334 assert(funcPkt->result == Packet::Success); |
335 delete funcPkt;
|
337 pkt->cmd = MemCmd::WriteReq;
|
336 memcpy(data + pkt->getOffset(pbs), pkt->getPtr<uint8_t>(), 337 pkt->getSize()); 338 PacketPtr newPkt = new Packet(pkt->req, MemCmd::WriteInvalidateReq, 339 Packet::Broadcast, pbs); 340 pkt->dataDynamicArray(data); 341 atomic_delay = otherPort->sendAtomic(newPkt); 342 delete newPkt; 343 } else { 344 atomic_delay = otherPort->sendAtomic(pkt); |
345 }
|
339 return delay + otherPort->sendAtomic(pkt);
|
346 return atomic_delay + delay; |
347} 348 349/** Function called by the port when the bus is receiving a Functional 350 * transaction.*/ 351void 352Bridge::BridgePort::recvFunctional(PacketPtr pkt) 353{ 354 std::list<PacketBuffer*>::iterator i; 355 bool pktContinue = true; 356 357 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 358 if (pkt->intersect((*i)->pkt)) { 359 pktContinue &= fixPacket(pkt, (*i)->pkt); 360 } 361 } 362 363 if (pktContinue) { 364 otherPort->sendFunctional(pkt); 365 } 366} 367 368/** Function called by the port when the bus is receiving a status change.*/ 369void 370Bridge::BridgePort::recvStatusChange(Port::Status status) 371{ 372 otherPort->sendStatusChange(status); 373} 374 375void 376Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 377 AddrRangeList &snoop) 378{ 379 otherPort->getPeerAddressRanges(resp, snoop); 380} 381 382BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 383 384 Param<int> req_size_a; 385 Param<int> req_size_b; 386 Param<int> resp_size_a; 387 Param<int> resp_size_b; 388 Param<Tick> delay; 389 Param<Tick> nack_delay; 390 Param<bool> write_ack; 391 Param<bool> fix_partial_write_a; 392 Param<bool> fix_partial_write_b; 393 394END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 395 396BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 397 398 INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"), 399 INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"), 400 INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"), 401 INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"), 402 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 403 INIT_PARAM(nack_delay, "The minimum delay to nack a packet"), 404 INIT_PARAM(write_ack, "Acknowledge any writes that are received."), 405 INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), 406 INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") 407 408END_INIT_SIM_OBJECT_PARAMS(Bridge) 409 410CREATE_SIM_OBJECT(Bridge) 411{ 412 Bridge::Params *p = new Bridge::Params; 413 p->name = getInstanceName(); 414 p->req_size_a = req_size_a; 415 p->req_size_b = req_size_b; 416 p->resp_size_a = resp_size_a; 417 p->resp_size_b = resp_size_b; 418 p->delay = delay; 419 p->nack_delay = nack_delay; 420 p->write_ack = write_ack; 421 p->fix_partial_write_a = fix_partial_write_a; 422 p->fix_partial_write_b = fix_partial_write_b; 423 return new Bridge(p); 424} 425 426REGISTER_SIM_OBJECT("Bridge", Bridge) 427
|
421
|
|