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 --- 33 unchanged lines hidden (view full) --- 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), --- 28 unchanged lines hidden (view full) --- 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} --- 63 unchanged lines hidden (view full) --- 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 |