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),
| 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)
| 50 outstandingResponses(0), queuedRequests(0), 51 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
| 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}
|
95 96/** Function called by the port when the bus is receiving a Timing 97 * transaction.*/ 98bool 99Bridge::BridgePort::recvTiming(PacketPtr pkt) 100{
| 103 104/** Function called by the port when the bus is receiving a Timing 105 * transaction.*/ 106bool 107Bridge::BridgePort::recvTiming(PacketPtr pkt) 108{
|
101 if (pkt->flags & SNOOP_COMMIT) { 102 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
| 109 if (!(pkt->flags & SNOOP_COMMIT)) 110 return true; 111 112 113 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
|
103 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 104
| 114 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 115
|
105 return otherPort->queueForSendTiming(pkt);
| 116 if (pkt->isRequest() && otherPort->queueFull()) { 117 DPRINTF(BusBridge, "Remote queue full, nacking\n"); 118 nackRequest(pkt); 119 return true;
|
106 }
| 120 }
|
107 else { 108 // Else it's just a snoop, properly return if we are blocking 109 return !queueFull();
| 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);
|
110 }
| 151 }
|
| 152 sendQueue.push_back(buf);
|
111} 112 113
| 153} 154 155
|
114bool
| 156void
|
115Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 116{
| 157Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 158{
|
117 if (queueFull()) { 118 DPRINTF(BusBridge, "Queue full, returning false\n"); 119 return false; 120 } 121 122 if (pkt->isResponse()) {
| 159 if (pkt->isResponse() || pkt->result == Packet::Nacked) {
|
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);
| 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
|
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 }
| 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 }
|
149
| 193 ++queuedRequests;
|
150 sendQueue.push_back(buf);
| 194 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 &&
| 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 &&
|
172 pkt->getOffset(pbs) && pkt->getSize() != pbs) {
| 214 pkt->result != Packet::Nacked && pkt->getOffset(pbs) && 215 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) {
| 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) {
|
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;
| 230 // Must wait for response
|
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
| 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
|
199 // If there are more packets to send, schedule event to try again. 200 if (!sendQueue.empty()) { 201 buf = sendQueue.front();
| 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");
|
202 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 203 } 204 // Let things start sending again
| 246 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 247 } 248 // Let things start sending again
|
205 if (was_full) {
| 249 if (was_full && !queueFull()) {
|
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 }
| 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);
|
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)
| 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
|
| |