bridge.cc revision 4432:5e55857abb01
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), queueLimit(_queueLimit), sendEvent(this) 51{ 52} 53 54Bridge::Bridge(const std::string &n, int qsa, int qsb, 55 Tick _delay, int write_ack, bool fix_partial_write_a, 56 bool fix_partial_write_b) 57 : MemObject(n), 58 portA(n + "-portA", this, &portB, _delay, qsa, fix_partial_write_a), 59 portB(n + "-portB", this, &portA, _delay, qsa, fix_partial_write_b), 60 ackWrites(write_ack) 61{ 62 if (ackWrites) 63 panic("No support for acknowledging writes\n"); 64} 65 66Port * 67Bridge::getPort(const std::string &if_name, int idx) 68{ 69 BridgePort *port; 70 71 if (if_name == "side_a") 72 port = &portA; 73 else if (if_name == "side_b") 74 port = &portB; 75 else 76 return NULL; 77 78 if (port->getPeer() != NULL) 79 panic("bridge side %s already connected to.", if_name); 80 return port; 81} 82 83 84void 85Bridge::init() 86{ 87 // Make sure that both sides are connected to. 88 if (portA.getPeer() == NULL || portB.getPeer() == NULL) 89 fatal("Both ports of bus bridge are not connected to a bus.\n"); 90 91 if (portA.peerBlockSize() != portB.peerBlockSize()) 92 fatal("Busses don't have the same block size... Not supported.\n"); 93} 94 95 96/** Function called by the port when the bus is receiving a Timing 97 * transaction.*/ 98bool 99Bridge::BridgePort::recvTiming(PacketPtr pkt) 100{ 101 if (pkt->flags & SNOOP_COMMIT) { 102 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 103 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 104 105 return otherPort->queueForSendTiming(pkt); 106 } 107 else { 108 // Else it's just a snoop, properly return if we are blocking 109 return !queueFull(); 110 } 111} 112 113 114bool 115Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 116{ 117 if (queueFull()) { 118 DPRINTF(BusBridge, "Queue full, returning false\n"); 119 return false; 120 } 121 122 if (pkt->isResponse()) { 123 // This is a response for a request we forwarded earlier. The 124 // corresponding PacketBuffer should be stored in the packet's 125 // senderState field. 126 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 127 assert(buf != NULL); 128 // set up new packet dest & senderState based on values saved 129 // from original request 130 buf->fixResponse(pkt); 131 DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", 132 pkt->senderState, buf); 133 DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); 134 delete buf; 135 } 136 137 Tick readyTime = curTick + delay; 138 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 139 DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", 140 buf->origSenderState, buf); 141 142 // If we're about to put this packet at the head of the queue, we 143 // need to schedule an event to do the transmit. Otherwise there 144 // should already be an event scheduled for sending the head 145 // packet. 146 if (sendQueue.empty()) { 147 sendEvent.schedule(readyTime); 148 } 149 150 sendQueue.push_back(buf); 151 152 return true; 153} 154 155void 156Bridge::BridgePort::trySend() 157{ 158 assert(!sendQueue.empty()); 159 160 bool was_full = queueFull(); 161 int pbs = peerBlockSize(); 162 163 PacketBuffer *buf = sendQueue.front(); 164 165 assert(buf->ready <= curTick); 166 167 PacketPtr pkt = buf->pkt; 168 169 pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set 170 171 if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && 172 pkt->getOffset(pbs) && pkt->getSize() != pbs) { 173 buf->partialWriteFix(this); 174 pkt = buf->pkt; 175 } 176 177 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 178 buf->origSrc, pkt->getDest(), pkt->getAddr()); 179 180 181 if (sendTiming(pkt)) { 182 // send successful 183 sendQueue.pop_front(); 184 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 185 186 if (buf->expectResponse) { 187 // Must wait for response. We just need to count outstanding 188 // responses (in case we want to cap them); PacketBuffer 189 // pointer will be recovered on response. 190 ++outstandingResponses; 191 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 192 outstandingResponses); 193 } else { 194 // no response expected... deallocate packet buffer now. 195 DPRINTF(BusBridge, " successful: no response expected\n"); 196 delete buf; 197 } 198 199 // If there are more packets to send, schedule event to try again. 200 if (!sendQueue.empty()) { 201 buf = sendQueue.front(); 202 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 203 } 204 // Let things start sending again 205 if (was_full) { 206 DPRINTF(BusBridge, "Queue was full, sending retry\n"); 207 otherPort->sendRetry(); 208 } 209 210 } else { 211 DPRINTF(BusBridge, " unsuccessful\n"); 212 buf->undoPartialWriteFix(); 213 } 214} 215 216 217void 218Bridge::BridgePort::recvRetry() 219{ 220 trySend(); 221} 222 223/** Function called by the port when the bus is receiving a Atomic 224 * transaction.*/ 225Tick 226Bridge::BridgePort::recvAtomic(PacketPtr pkt) 227{ 228 return otherPort->sendAtomic(pkt) + delay; 229} 230 231/** Function called by the port when the bus is receiving a Functional 232 * transaction.*/ 233void 234Bridge::BridgePort::recvFunctional(PacketPtr pkt) 235{ 236 std::list<PacketBuffer*>::iterator i; 237 bool pktContinue = true; 238 239 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 240 if (pkt->intersect((*i)->pkt)) { 241 pktContinue &= fixPacket(pkt, (*i)->pkt); 242 } 243 } 244 245 if (pktContinue) { 246 otherPort->sendFunctional(pkt); 247 } 248} 249 250/** Function called by the port when the bus is receiving a status change.*/ 251void 252Bridge::BridgePort::recvStatusChange(Port::Status status) 253{ 254 otherPort->sendStatusChange(status); 255} 256 257void 258Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 259 AddrRangeList &snoop) 260{ 261 otherPort->getPeerAddressRanges(resp, snoop); 262} 263 264BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 265 266 Param<int> queue_size_a; 267 Param<int> queue_size_b; 268 Param<Tick> delay; 269 Param<bool> write_ack; 270 Param<bool> fix_partial_write_a; 271 Param<bool> fix_partial_write_b; 272 273END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 274 275BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 276 277 INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), 278 INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), 279 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 280 INIT_PARAM(write_ack, "Acknowledge any writes that are received."), 281 INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), 282 INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") 283 284END_INIT_SIM_OBJECT_PARAMS(Bridge) 285 286CREATE_SIM_OBJECT(Bridge) 287{ 288 return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, 289 write_ack, fix_partial_write_a, fix_partial_write_b); 290} 291 292REGISTER_SIM_OBJECT("Bridge", Bridge) 293