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 30/** 31 * @file Definition of a simple bus bridge without buffering. 32 */ 33
| 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 30/** 31 * @file Definition of a simple bus bridge without buffering. 32 */ 33
|
| 34#include <algorithm>
|
34 35#include "base/trace.hh" 36#include "mem/bridge.hh" 37#include "sim/builder.hh" 38
| 35 36#include "base/trace.hh" 37#include "mem/bridge.hh" 38#include "sim/builder.hh" 39
|
| 40Bridge::BridgePort::BridgePort(const std::string &_name, 41 Bridge *_bridge, BridgePort *_otherPort, 42 int _delay, int _queueLimit) 43 : Port(_name), bridge(_bridge), otherPort(_otherPort), 44 delay(_delay), outstandingResponses(0), 45 queueLimit(_queueLimit), sendEvent(this) 46{ 47} 48 49Bridge::Bridge(const std::string &n, int qsa, int qsb, 50 Tick _delay, int write_ack) 51 : MemObject(n), 52 portA(n + "-portA", this, &portB, _delay, qsa), 53 portB(n + "-portB", this, &portA, _delay, qsa), 54 ackWrites(write_ack) 55{ 56} 57 58Port * 59Bridge::getPort(const std::string &if_name) 60{ 61 BridgePort *port; 62 63 if (if_name == "side_a") 64 port = &portA; 65 else if (if_name == "side_b") 66 port = &portB; 67 else 68 return NULL; 69 70 if (port->getPeer() != NULL) 71 panic("bridge side %s already connected to.", if_name); 72 return port; 73} 74 75
|
39void 40Bridge::init() 41{ 42 // Make sure that both sides are connected to.
| 76void 77Bridge::init() 78{ 79 // Make sure that both sides are connected to.
|
43 if (sideA == NULL || sideB == NULL)
| 80 if (portA.getPeer() == NULL || portB.getPeer() == NULL)
|
44 panic("Both ports of bus bridge are not connected to a bus.\n"); 45} 46 47
| 81 panic("Both ports of bus bridge are not connected to a bus.\n"); 82} 83 84
|
48/** Function called by the port when the bus is recieving a Timing
| 85/** Function called by the port when the bus is receiving a Timing
|
49 * transaction.*/ 50bool
| 86 * transaction.*/ 87bool
|
51Bridge::recvTiming(Packet *pkt, Side id)
| 88Bridge::BridgePort::recvTiming(Packet *pkt)
|
52{
| 89{
|
53 if (blockedA && id == SideA) 54 return false; 55 if (blockedB && id == SideB) 56 return false;
| 90 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 91 pkt->getSrc(), pkt->getDest(), pkt->getAddr());
|
57
| 92
|
58 if (delay) { 59 if (!sendEvent.scheduled()) 60 sendEvent.schedule(curTick + delay); 61 if (id == SideA) { 62 inboundA.push_back(std::make_pair<Packet*, Tick>(pkt, curTick)); 63 blockCheck(SideA); 64 } else { 65 inboundB.push_back(std::make_pair<Packet*, Tick>(pkt, curTick)); 66 blockCheck(SideB); 67 } 68 } else { 69 if (id == SideB) { 70 sideA->sendPkt(pkt); 71 blockCheck(SideB); 72 } else { 73 sideB->sendPkt(pkt); 74 blockCheck(SideA); 75 }
| 93 if (pkt->isResponse()) { 94 // This is a response for a request we forwarded earlier. The 95 // corresponding PacketBuffer should be stored in the packet's 96 // senderState field. 97 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 98 assert(buf != NULL); 99 // set up new packet dest & senderState based on values saved 100 // from original request 101 buf->fixResponse(pkt); 102 DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); 103 delete buf;
|
76 }
| 104 }
|
77 return true;
| |
78
| 105
|
| 106 return otherPort->queueForSendTiming(pkt);
|
79} 80
| 107} 108
|
81void 82Bridge::blockCheck(Side id) 83{ 84 /* Check that we still have buffer space available. */ 85 if (id == SideB) { 86 if (sideA->numQueued() + inboundB.size() >= queueSizeA && !blockedB) { 87 sideB->sendStatusChange(Port::Blocked); 88 blockedB = true; 89 } else if (sideA->numQueued() + inboundB.size() < queueSizeA && blockedB) { 90 sideB->sendStatusChange(Port::Unblocked); 91 blockedB = false; 92 } 93 } else { 94 if (sideB->numQueued() + inboundA.size() >= queueSizeB && !blockedA) { 95 sideA->sendStatusChange(Port::Blocked); 96 blockedA = true; 97 } else if (sideB->numQueued() + inboundA.size() < queueSizeB && blockedA) { 98 sideA->sendStatusChange(Port::Unblocked); 99 blockedA = false; 100 } 101 } 102}
| |
103
| 109
|
104void Bridge::timerEvent()
| 110bool 111Bridge::BridgePort::queueForSendTiming(Packet *pkt)
|
105{
| 112{
|
106 Tick t = 0;
| 113 if (queueFull()) 114 return false;
|
107
| 115
|
108 assert(inboundA.size() || inboundB.size()); 109 if (inboundA.size()) { 110 while (inboundA.front().second <= curTick + delay){ 111 sideB->sendPkt(inboundA.front()); 112 inboundA.pop_front(); 113 } 114 if (inboundA.size()) 115 t = inboundA.front().second + delay;
| 116 Tick readyTime = curTick + delay; 117 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 118 119 // If we're about to put this packet at the head of the queue, we 120 // need to schedule an event to do the transmit. Otherwise there 121 // should already be an event scheduled for sending the head 122 // packet. 123 if (sendQueue.empty()) { 124 sendEvent.schedule(readyTime);
|
116 }
| 125 }
|
117 if (inboundB.size()) { 118 while (inboundB.front().second <= curTick + delay){ 119 sideB->sendPkt(inboundA.front()); 120 inboundB.pop_front(); 121 } 122 if (inboundB.size()) 123 if (t == 0) 124 t = inboundB.front().second + delay; 125 else 126 t = std::min(t,inboundB.front().second + delay); 127 } else { 128 panic("timerEvent() called but nothing to do?"); 129 }
| |
130
| 126
|
131 if (t != 0) 132 sendEvent.schedule(t);
| 127 sendQueue.push_back(buf); 128 129 // Did we just become blocked? If yes, let other side know. 130 if (queueFull()) 131 otherPort->sendStatusChange(Port::Blocked); 132 133 return true;
|
133} 134 135 136void
| 134} 135 136 137void
|
137Bridge::BridgePort::sendPkt(Packet *pkt)
| 138Bridge::BridgePort::finishSend(PacketBuffer *buf)
|
138{
| 139{
|
139 if (!sendTiming(pkt)) 140 outbound.push_back(std::make_pair<Packet*,Tick>(pkt, curTick));
| 140 if (buf->expectResponse) { 141 // Must wait for response. We just need to count outstanding 142 // responses (in case we want to cap them); PacketBuffer 143 // pointer will be recovered on response. 144 ++outstandingResponses; 145 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 146 outstandingResponses); 147 } else { 148 // no response expected... deallocate packet buffer now. 149 DPRINTF(BusBridge, " successful: no response expected\n"); 150 delete buf; 151 } 152 153 // If there are more packets to send, schedule event to try again. 154 if (!sendQueue.empty()) { 155 buf = sendQueue.front(); 156 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 157 }
|
141} 142
| 158} 159
|
| 160
|
143void
| 161void
|
144Bridge::BridgePort::sendPkt(std::pair<Packet*, Tick> p)
| 162Bridge::BridgePort::trySend()
|
145{
| 163{
|
146 if (!sendTiming(p.first)) 147 outbound.push_back(p);
| 164 assert(!sendQueue.empty()); 165 166 PacketBuffer *buf = sendQueue.front(); 167 168 assert(buf->ready <= curTick); 169 170 Packet *pkt = buf->pkt; 171 172 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 173 buf->origSrc, pkt->getDest(), pkt->getAddr()); 174 175 if (sendTiming(pkt)) { 176 // send successful 177 sendQueue.pop_front(); 178 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 179 finishSend(buf); 180 } else { 181 DPRINTF(BusBridge, " unsuccessful\n"); 182 }
|
148} 149 150 151Packet * 152Bridge::BridgePort::recvRetry() 153{
| 183} 184 185 186Packet * 187Bridge::BridgePort::recvRetry() 188{
|
154 Packet *pkt; 155 assert(outbound.size() > 0); 156 assert(outbound.front().second >= curTick + bridge->delay); 157 pkt = outbound.front().first; 158 outbound.pop_front(); 159 bridge->blockCheck(side);
| 189 PacketBuffer *buf = sendQueue.front(); 190 Packet *pkt = buf->pkt; 191 finishSend(buf);
|
160 return pkt; 161} 162
| 192 return pkt; 193} 194
|
163/** Function called by the port when the bus is recieving a Atomic
| 195/** Function called by the port when the bus is receiving a Atomic
|
164 * transaction.*/ 165Tick
| 196 * transaction.*/ 197Tick
|
166Bridge::recvAtomic(Packet *pkt, Side id)
| 198Bridge::BridgePort::recvAtomic(Packet *pkt)
|
167{
| 199{
|
168 pkt->time += delay; 169 170 if (id == SideA) 171 return sideB->sendAtomic(pkt); 172 else 173 return sideA->sendAtomic(pkt);
| 200 return otherPort->sendAtomic(pkt) + delay;
|
174} 175
| 201} 202
|
176/** Function called by the port when the bus is recieving a Functional
| 203/** Function called by the port when the bus is receiving a Functional
|
177 * transaction.*/ 178void
| 204 * transaction.*/ 205void
|
179Bridge::recvFunctional(Packet *pkt, Side id)
| 206Bridge::BridgePort::recvFunctional(Packet *pkt)
|
180{
| 207{
|
181 pkt->time += delay; 182 std::list<std::pair<Packet*, Tick> >::iterator i;
| 208 std::list<PacketBuffer*>::iterator i;
|
183 bool pktContinue = true; 184
| 209 bool pktContinue = true; 210
|
185 for(i = inboundA.begin(); i != inboundA.end(); ++i) { 186 if (pkt->intersect(i->first)) { 187 pktContinue &= fixPacket(pkt, i->first);
| 211 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 212 if (pkt->intersect((*i)->pkt)) { 213 pktContinue &= fixPacket(pkt, (*i)->pkt);
|
188 } 189 } 190
| 214 } 215 } 216
|
191 for(i = inboundB.begin(); i != inboundB.end(); ++i) { 192 if (pkt->intersect(i->first)) { 193 pktContinue &= fixPacket(pkt, i->first); 194 } 195 } 196 197 for(i = sideA->outbound.begin(); i != sideA->outbound.end(); ++i) { 198 if (pkt->intersect(i->first)) { 199 pktContinue &= fixPacket(pkt, i->first); 200 } 201 } 202 203 for(i = sideB->outbound.begin(); i != sideB->outbound.end(); ++i) { 204 if (pkt->intersect(i->first)) { 205 pktContinue &= fixPacket(pkt, i->first); 206 } 207 } 208
| |
209 if (pktContinue) {
| 217 if (pktContinue) {
|
210 if (id == SideA) 211 sideB->sendFunctional(pkt); 212 else 213 sideA->sendFunctional(pkt);
| 218 otherPort->sendFunctional(pkt);
|
214 } 215} 216
| 219 } 220} 221
|
217/** Function called by the port when the bus is recieving a status change.*/
| 222/** Function called by the port when the bus is receiving a status change.*/
|
218void
| 223void
|
219Bridge::recvStatusChange(Port::Status status, Side id)
| 224Bridge::BridgePort::recvStatusChange(Port::Status status)
|
220{ 221 if (status == Port::Blocked || status == Port::Unblocked)
| 225{ 226 if (status == Port::Blocked || status == Port::Unblocked)
|
222 return ;
| 227 return;
|
223
| 228
|
224 if (id == SideA) 225 sideB->sendStatusChange(status); 226 else 227 sideA->sendStatusChange(status);
| 229 otherPort->sendStatusChange(status);
|
228} 229 230void
| 230} 231 232void
|
231Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id)
| 233Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 234 AddrRangeList &snoop)
|
232{
| 235{
|
233 if (id == SideA) 234 sideB->getPeerAddressRanges(resp, snoop); 235 else 236 sideA->getPeerAddressRanges(resp, snoop);
| 236 otherPort->getPeerAddressRanges(resp, snoop);
|
237} 238 239BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 240 241 Param<int> queue_size_a; 242 Param<int> queue_size_b; 243 Param<Tick> delay; 244 Param<bool> write_ack; 245 246END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 247 248BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 249 250 INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), 251 INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), 252 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 253 INIT_PARAM(write_ack, "Acknowledge any writes that are received.") 254 255END_INIT_SIM_OBJECT_PARAMS(Bridge) 256 257CREATE_SIM_OBJECT(Bridge) 258{ 259 return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, 260 write_ack); 261} 262 263REGISTER_SIM_OBJECT("Bridge", Bridge)
| 237} 238 239BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) 240 241 Param<int> queue_size_a; 242 Param<int> queue_size_b; 243 Param<Tick> delay; 244 Param<bool> write_ack; 245 246END_DECLARE_SIM_OBJECT_PARAMS(Bridge) 247 248BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) 249 250 INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), 251 INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), 252 INIT_PARAM(delay, "The miminum delay to cross this bridge"), 253 INIT_PARAM(write_ack, "Acknowledge any writes that are received.") 254 255END_INIT_SIM_OBJECT_PARAMS(Bridge) 256 257CREATE_SIM_OBJECT(Bridge) 258{ 259 return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, 260 write_ack); 261} 262 263REGISTER_SIM_OBJECT("Bridge", Bridge)
|