bridge.cc revision 4433
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 _queueLimit, 47 bool fix_partial_write) 48 : Port(_name), bridge(_bridge), otherPort(_otherPort), 49 delay(_delay), fixPartialWrite(fix_partial_write), 50 outstandingResponses(0), queuedRequests(0), 51 queueLimit(_queueLimit), sendEvent(this) 52{ 53} 54 55Bridge::Bridge(const std::string &n, int qsa, int qsb, 56 Tick _delay, int write_ack, bool fix_partial_write_a, 57 bool fix_partial_write_b) 58 : MemObject(n), 59 portA(n + "-portA", this, &portB, _delay, qsa, fix_partial_write_a), 60 portB(n + "-portB", this, &portA, _delay, qsa, fix_partial_write_b), 61 ackWrites(write_ack) 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::queueFull() 98{ 99 // use >= here because sendQueue could get larger because of 100 // nacks getting inserted 101 return queuedRequests + outstandingResponses >= queueLimit; 102} 103 104/** Function called by the port when the bus is receiving a Timing 105 * transaction.*/ 106bool 107Bridge::BridgePort::recvTiming(PacketPtr pkt) 108{ 109 if (!(pkt->flags & SNOOP_COMMIT)) 110 return true; 111 112 113 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 114 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 115 116 if (pkt->isRequest() && otherPort->queueFull()) { 117 DPRINTF(BusBridge, "Remote queue full, nacking\n"); 118 nackRequest(pkt); 119 return true; 120 } 121 122 if (pkt->needsResponse() && pkt->result != Packet::Nacked) 123 if (queueFull()) { 124 DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 125 DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 126 sendQueue.size(), queuedRequests, outstandingResponses); 127 nackRequest(pkt); 128 return true; 129 } else { 130 DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 131 ++outstandingResponses; 132 } 133 134 otherPort->queueForSendTiming(pkt); 135 136 return true; 137} 138 139void 140Bridge::BridgePort::nackRequest(PacketPtr pkt) 141{ 142 // Nack the packet 143 pkt->result = Packet::Nacked; 144 pkt->setDest(pkt->getSrc()); 145 146 //put it on the list to send 147 Tick readyTime = curTick + delay; 148 PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 149 if (sendQueue.empty()) { 150 sendEvent.schedule(readyTime); 151 } 152 sendQueue.push_back(buf); 153} 154 155 156void 157Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 158{ 159 if (pkt->isResponse() || pkt->result == Packet::Nacked) { 160 // This is a response for a request we forwarded earlier. The 161 // corresponding PacketBuffer should be stored in the packet's 162 // senderState field. 163 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 164 assert(buf != NULL); 165 // set up new packet dest & senderState based on values saved 166 // from original request 167 buf->fixResponse(pkt); 168 169 // Check if this packet was expecting a response (this is either it or 170 // its a nacked packet and we won't be seeing that response) 171 if (buf->expectResponse) 172 --outstandingResponses; 173 174 175 DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", 176 pkt->senderState, buf); 177 DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); 178 delete buf; 179 } 180 181 Tick readyTime = curTick + delay; 182 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 183 DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", 184 buf->origSenderState, buf); 185 186 // If we're about to put this packet at the head of the queue, we 187 // need to schedule an event to do the transmit. Otherwise there 188 // should already be an event scheduled for sending the head 189 // packet. 190 if (sendQueue.empty()) { 191 sendEvent.schedule(readyTime); 192 } 193 ++queuedRequests; 194 sendQueue.push_back(buf); 195} 196 197void 198Bridge::BridgePort::trySend() 199{ 200 assert(!sendQueue.empty()); 201 202 bool was_full = queueFull(); 203 int pbs = peerBlockSize(); 204 205 PacketBuffer *buf = sendQueue.front(); 206 207 assert(buf->ready <= curTick); 208 209 PacketPtr pkt = buf->pkt; 210 211 pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set 212 213 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 214 pkt->result != Packet::Nacked && pkt->getOffset(pbs) && 215 pkt->getSize() != pbs) { 216 buf->partialWriteFix(this); 217 pkt = buf->pkt; 218 } 219 220 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 221 buf->origSrc, pkt->getDest(), pkt->getAddr()); 222 223 224 if (sendTiming(pkt)) { 225 // send successful 226 sendQueue.pop_front(); 227 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 228 229 if (buf->expectResponse) { 230 // Must wait for response 231 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 232 outstandingResponses); 233 } else { 234 // no response expected... deallocate packet buffer now. 235 DPRINTF(BusBridge, " successful: no response expected\n"); 236 delete buf; 237 } 238 239 if (!buf->nacked) 240 --queuedRequests; 241 242 // If there are more packets to send, schedule event to try again. 243 if (!sendQueue.empty()) { 244 buf = sendQueue.front(); 245 DPRINTF(BusBridge, "Scheduling next send\n"); 246 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 247 } 248 // Let things start sending again 249 if (was_full && !queueFull()) { 250 DPRINTF(BusBridge, "Queue was full, sending retry\n"); 251 otherPort->sendRetry(); 252 } 253 254 } else { 255 DPRINTF(BusBridge, " unsuccessful\n"); 256 buf->undoPartialWriteFix(); 257 } 258 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 259 sendQueue.size(), queuedRequests, outstandingResponses); 260} 261 262 263void 264Bridge::BridgePort::recvRetry() 265{ 266 trySend(); 267} 268 269/** Function called by the port when the bus is receiving a Atomic 270 * transaction.*/ 271Tick 272Bridge::BridgePort::recvAtomic(PacketPtr pkt) 273{ 274 return otherPort->sendAtomic(pkt) + delay; 275} 276 277/** Function called by the port when the bus is receiving a Functional 278 * transaction.*/ 279void 280Bridge::BridgePort::recvFunctional(PacketPtr pkt) 281{ 282 std::list<PacketBuffer*>::iterator i; 283 bool pktContinue = true; 284 285 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 286 if (pkt->intersect((*i)->pkt)) { 287 pktContinue &= fixPacket(pkt, (*i)->pkt); 288 } 289 } 290 291 if (pktContinue) { 292 otherPort->sendFunctional(pkt); 293 } 294} 295 296/** Function called by the port when the bus is receiving a status change.*/ 297void 298Bridge::BridgePort::recvStatusChange(Port::Status status) 299{ 300 otherPort->sendStatusChange(status); 301} 302 303void 304Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 305 AddrRangeList &snoop) 306{ 307 otherPort->getPeerAddressRanges(resp, snoop); 308} 309 310BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 311 312 Param<int> queue_size_a; 313 Param<int> queue_size_b; 314 Param<Tick> delay; 315 Param<bool> write_ack; 316 Param<bool> fix_partial_write_a; 317 Param<bool> fix_partial_write_b; 318 319END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 320 321BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 322 323 INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), 324 INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), 325 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 326 INIT_PARAM(write_ack, "Acknowledge any writes that are received."), 327 INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), 328 INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") 329 330END_INIT_SIM_OBJECT_PARAMS(Bridge) 331 332CREATE_SIM_OBJECT(Bridge) 333{ 334 return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, 335 write_ack, fix_partial_write_a, fix_partial_write_b); 336} 337 338REGISTER_SIM_OBJECT("Bridge", Bridge) 339 340